alias_db.c revision 179480
117683Spst/*-
239291Sfenner * Copyright (c) 2001 Charles Mott <cm@linktel.net>
317683Spst * All rights reserved.
417683Spst *
517683Spst * Redistribution and use in source and binary forms, with or without
617683Spst * modification, are permitted provided that the following conditions
717683Spst * are met:
817683Spst * 1. Redistributions of source code must retain the above copyright
917683Spst *    notice, this list of conditions and the following disclaimer.
1017683Spst * 2. Redistributions in binary form must reproduce the above copyright
1117683Spst *    notice, this list of conditions and the following disclaimer in the
1217683Spst *    documentation and/or other materials provided with the distribution.
1317683Spst *
1417683Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1517683Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1617683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1717683Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1817683Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1917683Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20162020Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21162020Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2217683Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2317683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24127664Sbms * SUCH DAMAGE.
25162012Ssam */
2617683Spst
2717683Spst#include <sys/cdefs.h>
2875107Sfenner__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_db.c 179480 2008-06-01 18:34:58Z mav $");
2975107Sfenner
3075107Sfenner/*
3175107Sfenner    Alias_db.c encapsulates all data structures used for storing
3217683Spst    packet aliasing data.  Other parts of the aliasing software
3317683Spst    access data through functions provided in this file.
3417683Spst
3517683Spst    Data storage is based on the notion of a "link", which is
3617683Spst    established for ICMP echo/reply packets, UDP datagrams and
3717683Spst    TCP stream connections.  A link stores the original source
38127664Sbms    and destination addresses.  For UDP and TCP, it also stores
3917683Spst    source and destination port numbers, as well as an alias
4017683Spst    port number.  Links are also used to store information about
41127664Sbms    fragments.
4298530Sfenner
43127664Sbms    There is a facility for sweeping through and deleting old
4498530Sfenner    links as new packets are sent through.  A simple timeout is
45127664Sbms    used for ICMP and UDP links.  TCP links are left alone unless
46127664Sbms    there is an incomplete connection, in which case the link
4798530Sfenner    can be deleted after a certain amount of time.
48127664Sbms
49127664Sbms
50127664Sbms    Initial version: August, 1996  (cjm)
51127664Sbms
52127664Sbms    Version 1.4: September 16, 1996 (cjm)
53127664Sbms	Facility for handling incoming links added.
54127664Sbms
55127664Sbms    Version 1.6: September 18, 1996 (cjm)
56127664Sbms	ICMP data handling simplified.
57127664Sbms
58127664Sbms    Version 1.7: January 9, 1997 (cjm)
59127664Sbms	Fragment handling simplified.
60127664Sbms	Saves pointers for unresolved fragments.
6198530Sfenner	Permits links for unspecified remote ports
62127664Sbms	  or unspecified remote addresses.
63127664Sbms	Fixed bug which did not properly zero port
64147894Ssam	  table entries after a link was deleted.
65127664Sbms	Cleaned up some obsolete comments.
6617683Spst
67127664Sbms    Version 1.8: January 14, 1997 (cjm)
68127664Sbms	Fixed data type error in StartPoint().
69127664Sbms	(This error did not exist prior to v1.7
70127664Sbms	and was discovered and fixed by Ari Suutari)
71127664Sbms
72127664Sbms    Version 1.9: February 1, 1997
73127664Sbms	Optionally, connections initiated from packet aliasing host
74127664Sbms	machine will will not have their port number aliased unless it
75127664Sbms	conflicts with an aliasing port already being used. (cjm)
76127664Sbms
77127664Sbms	All options earlier being #ifdef'ed are now available through
78127664Sbms	a new interface, SetPacketAliasMode().  This allows run time
79127664Sbms	control (which is now available in PPP+pktAlias through the
80127664Sbms	'alias' keyword). (ee)
81127664Sbms
82127664Sbms	Added ability to create an alias port without
83127664Sbms	either destination address or port specified.
84127664Sbms	port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
85127664Sbms
86127664Sbms	Removed K&R style function headers
87127664Sbms	and general cleanup. (ee)
88127664Sbms
8917683Spst	Added packetAliasMode to replace compiler #defines's (ee)
9017683Spst
9117683Spst	Allocates sockets for partially specified
9217683Spst	ports if ALIAS_USE_SOCKETS defined. (cjm)
9317683Spst
9417683Spst    Version 2.0: March, 1997
9517683Spst	SetAliasAddress() will now clean up alias links
9617683Spst	if the aliasing address is changed. (cjm)
9717683Spst
9817683Spst	PacketAliasPermanentLink() function added to support permanent
99127664Sbms	links.  (J. Fortes suggested the need for this.)
100127664Sbms	Examples:
101127664Sbms
102127664Sbms	(192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
10317683Spst
10417683Spst	(192.168.0.2, port 21)  <-> alias port 3604, known dest addr
10517683Spst						     unknown dest port
10617683Spst
107127664Sbms	These permanent links allow for incoming connections to
10856889Sfenner	machines on the local network.  They can be given with a
109127664Sbms	user-chosen amount of specificity, with increasing specificity
110162012Ssam	meaning more security. (cjm)
111127664Sbms
112127664Sbms	Quite a bit of rework to the basic engine.  The portTable[]
113127664Sbms	array, which kept track of which ports were in use was replaced
114127664Sbms	by a table/linked list structure. (cjm)
11517683Spst
11617683Spst	SetExpire() function added. (cjm)
11717683Spst
11898530Sfenner	DeleteLink() no longer frees memory association with a pointer
11998530Sfenner	to a fragment (this bug was first recognized by E. Eklund in
12098530Sfenner	v1.9).
12198530Sfenner
12298530Sfenner    Version 2.1: May, 1997 (cjm)
12398530Sfenner	Packet aliasing engine reworked so that it can handle
12498530Sfenner	multiple external addresses rather than just a single
12598530Sfenner	host address.
12698530Sfenner
12798530Sfenner	PacketAliasRedirectPort() and PacketAliasRedirectAddr()
12898530Sfenner	added to the API.  The first function is a more generalized
12998530Sfenner	version of PacketAliasPermanentLink().  The second function
13098530Sfenner	implements static network address translation.
13117683Spst
13275107Sfenner    Version 3.2: July, 2000 (salander and satoh)
13375107Sfenner	Added FindNewPortGroup to get contiguous range of port values.
13417683Spst
13517683Spst	Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
13617683Spst	link but not actually add one.
13717683Spst
13817683Spst	Added FindRtspOut, which is closely derived from FindUdpTcpOut,
13917683Spst	except that the alias port (from FindNewPortGroup) is provided
14017683Spst	as input.
14117683Spst
142127664Sbms    See HISTORY file for additional revisions.
143127664Sbms*/
14417683Spst
14517683Spst#ifdef _KERNEL
14617683Spst#include <machine/stdarg.h>
14717683Spst#include <sys/param.h>
148146768Ssam#include <sys/kernel.h>
149127664Sbms#include <sys/module.h>
150146768Ssam#include <sys/syslog.h>
151146768Ssam#else
152146768Ssam#include <stdarg.h>
15317683Spst#include <stdlib.h>
154127664Sbms#include <stdio.h>
15517683Spst#include <sys/errno.h>
156127664Sbms#include <sys/time.h>
157127664Sbms#include <unistd.h>
158127664Sbms#endif
159127664Sbms
160127664Sbms#include <sys/socket.h>
161127664Sbms#include <netinet/tcp.h>
162127664Sbms
163127664Sbms#ifdef _KERNEL
164127664Sbms#include <netinet/libalias/alias.h>
165127664Sbms#include <netinet/libalias/alias_local.h>
166127664Sbms#include <netinet/libalias/alias_mod.h>
167127664Sbms#include <net/if.h>
16817683Spst#else
16917683Spst#include "alias.h"
17017683Spst#include "alias_local.h"
17117683Spst#include "alias_mod.h"
17217683Spst#endif
17317683Spst
17417683Spststatic		LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
17517683Spst
17617683Spst
17717683Spst/*
178127664Sbms   Constants (note: constants are also defined
179127664Sbms	      near relevant functions or structs)
180127664Sbms*/
181127664Sbms
182127664Sbms/* Parameters used for cleanup of expired links */
183127664Sbms/* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
184127664Sbms#define ALIAS_CLEANUP_INTERVAL_SECS  64
185127664Sbms#define ALIAS_CLEANUP_MAX_SPOKES     (LINK_TABLE_OUT_SIZE/5)
186127664Sbms
187127664Sbms/* Timeouts (in seconds) for different link types */
188127664Sbms#define ICMP_EXPIRE_TIME             60
189127664Sbms#define UDP_EXPIRE_TIME              60
190127664Sbms#define PROTO_EXPIRE_TIME            60
191127664Sbms#define FRAGMENT_ID_EXPIRE_TIME      10
192127664Sbms#define FRAGMENT_PTR_EXPIRE_TIME     30
193127664Sbms
194127664Sbms/* TCP link expire time for different cases */
195127664Sbms/* When the link has been used and closed - minimal grace time to
196127664Sbms   allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
197127664Sbms#ifndef TCP_EXPIRE_DEAD
198127664Sbms#define TCP_EXPIRE_DEAD           10
199127664Sbms#endif
200127664Sbms
201127664Sbms/* When the link has been used and closed on one side - the other side
202127664Sbms   is allowed to still send data */
203127664Sbms#ifndef TCP_EXPIRE_SINGLEDEAD
20417683Spst#define TCP_EXPIRE_SINGLEDEAD     90
20517683Spst#endif
20617683Spst
20717683Spst/* When the link isn't yet up */
20817683Spst#ifndef TCP_EXPIRE_INITIAL
20917683Spst#define TCP_EXPIRE_INITIAL       300
21017683Spst#endif
21117683Spst
21217683Spst/* When the link is up */
21317683Spst#ifndef TCP_EXPIRE_CONNECTED
21417683Spst#define TCP_EXPIRE_CONNECTED   86400
21517683Spst#endif
21617683Spst
21717683Spst
21817683Spst/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
21917683Spst   These constants can be anything except zero, which indicates an
22017683Spst   unknown port number. */
22175107Sfenner
22275107Sfenner#define NO_DEST_PORT     1
22317683Spst#define NO_SRC_PORT      1
22417683Spst
22517683Spst
22617683Spst
22717683Spst/* Data Structures
22817683Spst
22917683Spst    The fundamental data structure used in this program is
23017683Spst    "struct alias_link".  Whenever a TCP connection is made,
23117683Spst    a UDP datagram is sent out, or an ICMP echo request is made,
23217683Spst    a link record is made (if it has not already been created).
23317683Spst    The link record is identified by the source address/port
234146768Ssam    and the destination address/port. In the case of an ICMP
235146768Ssam    echo request, the source port is treated as being equivalent
236146768Ssam    with the 16-bit ID number of the ICMP packet.
23717683Spst
23817683Spst    The link record also can store some auxiliary data.  For
239127664Sbms    TCP connections that have had sequence and acknowledgment
240127664Sbms    modifications, data space is available to track these changes.
241127664Sbms    A state field is used to keep track in changes to the TCP
242127664Sbms    connection state.  ID numbers of fragments can also be
243127664Sbms    stored in the auxiliary space.  Pointers to unresolved
244127664Sbms    fragments can also be stored.
245127664Sbms
246127664Sbms    The link records support two independent chainings.  Lookup
247127664Sbms    tables for input and out tables hold the initial pointers
248127664Sbms    the link chains.  On input, the lookup table indexes on alias
249127664Sbms    port and link type.  On output, the lookup table indexes on
250127664Sbms    source address, destination address, source port, destination
251127664Sbms    port and link type.
252127664Sbms*/
253127664Sbms
254127664Sbmsstruct ack_data_record {	/* used to save changes to ACK/sequence
255127664Sbms				 * numbers */
256127664Sbms	u_long		ack_old;
257127664Sbms	u_long		ack_new;
258127664Sbms	int		delta;
259127664Sbms	int		active;
26017683Spst};
26117683Spst
262146768Ssamstruct tcp_state {		/* Information about TCP connection        */
26317683Spst	int		in;	/* State for outside -> inside             */
264127664Sbms	int		out;	/* State for inside  -> outside            */
265127664Sbms	int		index;	/* Index to ACK data array                 */
266146768Ssam	int		ack_modified;	/* Indicates whether ACK and
267146768Ssam					 * sequence numbers */
268146768Ssam	/* been modified                           */
269146768Ssam};
270146768Ssam
271146768Ssam#define N_LINK_TCP_DATA   3	/* Number of distinct ACK number changes
272146768Ssam				 * saved for a modified TCP stream */
273146768Ssamstruct tcp_dat {
27417683Spst	struct tcp_state state;
275127664Sbms	struct ack_data_record ack[N_LINK_TCP_DATA];
276146768Ssam	int		fwhole;	/* Which firewall record is used for this
277146768Ssam				 * hole? */
278146768Ssam};
279146768Ssam
28098530Sfennerstruct server {			/* LSNAT server pool (circular list) */
281127664Sbms	struct in_addr	addr;
282127664Sbms	u_short		port;
283127664Sbms	struct server  *next;
284127664Sbms};
285146768Ssam
286146768Ssamstruct alias_link {		/* Main data structure */
287146768Ssam	struct libalias *la;
28898530Sfenner	struct in_addr	src_addr;	/* Address and port information        */
289146768Ssam	struct in_addr	dst_addr;
290146768Ssam	struct in_addr	alias_addr;
291146768Ssam	struct in_addr	proxy_addr;
292146768Ssam	u_short		src_port;
293146768Ssam	u_short		dst_port;
294146768Ssam	u_short		alias_port;
295146768Ssam	u_short		proxy_port;
296146768Ssam	struct server  *server;
297146768Ssam
298146768Ssam	int		link_type;	/* Type of link: TCP, UDP, ICMP,
299146768Ssam					 * proto, frag */
300146768Ssam
301146768Ssam/* values for link_type */
302146768Ssam#define LINK_ICMP                     IPPROTO_ICMP
303146768Ssam#define LINK_UDP                      IPPROTO_UDP
304127664Sbms#define LINK_TCP                      IPPROTO_TCP
305127664Sbms#define LINK_FRAGMENT_ID              (IPPROTO_MAX + 1)
306127664Sbms#define LINK_FRAGMENT_PTR             (IPPROTO_MAX + 2)
307127664Sbms#define LINK_ADDR                     (IPPROTO_MAX + 3)
308127664Sbms#define LINK_PPTP                     (IPPROTO_MAX + 4)
309127664Sbms
310127664Sbms	int		flags;	/* indicates special characteristics   */
311127664Sbms	int		pflags;	/* protocol-specific flags */
312127664Sbms
313127664Sbms/* flag bits */
314127664Sbms#define LINK_UNKNOWN_DEST_PORT     0x01
31517683Spst#define LINK_UNKNOWN_DEST_ADDR     0x02
31617683Spst#define LINK_PERMANENT             0x04
31717683Spst#define LINK_PARTIALLY_SPECIFIED   0x03	/* logical-or of first two bits */
31817683Spst#define LINK_UNFIREWALLED          0x08
31917683Spst
32017683Spst	int		timestamp;	/* Time link was last accessed         */
32117683Spst	int		expire_time;	/* Expire time for link                */
322146768Ssam#ifndef	NO_USE_SOCKETS
323146768Ssam	int		sockfd;	/* socket descriptor                   */
324146768Ssam#endif
325146768Ssam			LIST_ENTRY    (alias_link) list_out;	/* Linked list of
326146768Ssam								 * pointers for     */
327146768Ssam			LIST_ENTRY    (alias_link) list_in;	/* input and output
328146768Ssam								 * lookup tables  */
329146768Ssam
330146768Ssam	union {			/* Auxiliary data                      */
331146768Ssam		char           *frag_ptr;
332146768Ssam		struct in_addr	frag_addr;
333146768Ssam		struct tcp_dat *tcp;
334146768Ssam	}		data;
335146768Ssam};
336146768Ssam
337146768Ssam/* Clean up procedure. */
338146768Ssamstatic void finishoff(void);
339146768Ssam
340146768Ssam/* Kernel module definition. */
341146768Ssam#ifdef	_KERNEL
342146768SsamMALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
343146768Ssam
344146768SsamMODULE_VERSION(libalias, 1);
345146768Ssam
346146768Ssamstatic int
347146768Ssamalias_mod_handler(module_t mod, int type, void *data)
348146768Ssam{
349146768Ssam	int error;
350146768Ssam
351146768Ssam	switch (type) {
352146768Ssam	case MOD_LOAD:
353146768Ssam		error = 0;
354146768Ssam		handler_chain_init();
355146768Ssam		break;
356146768Ssam	case MOD_QUIESCE:
357146768Ssam	case MOD_UNLOAD:
358146768Ssam	        handler_chain_destroy();
359146768Ssam	        finishoff();
360146768Ssam		error = 0;
361146768Ssam		break;
362146768Ssam	default:
363146768Ssam		error = EINVAL;
364146768Ssam	}
365146768Ssam
366146768Ssam	return (error);
367146768Ssam}
368146768Ssam
369146768Ssamstatic moduledata_t alias_mod = {
370146768Ssam       "alias", alias_mod_handler, NULL
371127664Sbms};
372127664Sbms
373127664SbmsDECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
374127664Sbms#endif
375127664Sbms
376127664Sbms/* Internal utility routines (used only in alias_db.c)
377127664Sbms
378127664SbmsLookup table starting points:
379127664Sbms    StartPointIn()           -- link table initial search point for
380127664Sbms				incoming packets
381127664Sbms    StartPointOut()          -- link table initial search point for
382127664Sbms				outgoing packets
383127664Sbms
384127664SbmsMiscellaneous:
385127664Sbms    SeqDiff()                -- difference between two TCP sequences
386127664Sbms    ShowAliasStats()         -- send alias statistics to a monitor file
387127664Sbms*/
388127664Sbms
389127664Sbms
390127664Sbms/* Local prototypes */
391127664Sbmsstatic u_int	StartPointIn(struct in_addr, u_short, int);
392127664Sbms
393127664Sbmsstatic		u_int
394127664SbmsStartPointOut(struct in_addr, struct in_addr,
395127664Sbms    u_short, u_short, int);
396127664Sbms
397127664Sbmsstatic int	SeqDiff(u_long, u_long);
398127664Sbms
399127664Sbms#ifndef NO_FW_PUNCH
400127664Sbms/* Firewall control */
401127664Sbmsstatic void	InitPunchFW(struct libalias *);
402127664Sbmsstatic void	UninitPunchFW(struct libalias *);
403127664Sbmsstatic void	ClearFWHole(struct alias_link *);
404127664Sbms
405127664Sbms#endif
406127664Sbms
407127664Sbms/* Log file control */
408127664Sbmsstatic void	ShowAliasStats(struct libalias *);
409127664Sbmsstatic int	InitPacketAliasLog(struct libalias *);
410127664Sbmsstatic void	UninitPacketAliasLog(struct libalias *);
411127664Sbms
412127664Sbmsstatic		u_int
413127664SbmsStartPointIn(struct in_addr alias_addr,
414127664Sbms    u_short alias_port,
415127664Sbms    int link_type)
416127664Sbms{
417127664Sbms	u_int n;
418127664Sbms
419127664Sbms	n = alias_addr.s_addr;
420127664Sbms	if (link_type != LINK_PPTP)
421127664Sbms		n += alias_port;
422127664Sbms	n += link_type;
423127664Sbms	return (n % LINK_TABLE_IN_SIZE);
424127664Sbms}
425127664Sbms
426127664Sbms
427127664Sbmsstatic		u_int
428127664SbmsStartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
429127664Sbms    u_short src_port, u_short dst_port, int link_type)
430127664Sbms{
431127664Sbms	u_int n;
432127664Sbms
433127664Sbms	n = src_addr.s_addr;
434127664Sbms	n += dst_addr.s_addr;
435127664Sbms	if (link_type != LINK_PPTP) {
436127664Sbms		n += src_port;
437127664Sbms		n += dst_port;
438127664Sbms	}
439127664Sbms	n += link_type;
440127664Sbms
441127664Sbms	return (n % LINK_TABLE_OUT_SIZE);
442127664Sbms}
443127664Sbms
444127664Sbms
445127664Sbmsstatic int
446127664SbmsSeqDiff(u_long x, u_long y)
447127664Sbms{
448127664Sbms/* Return the difference between two TCP sequence numbers */
449127664Sbms
450127664Sbms/*
451127664Sbms    This function is encapsulated in case there are any unusual
452127664Sbms    arithmetic conditions that need to be considered.
453127664Sbms*/
454127664Sbms
455127664Sbms	return (ntohl(y) - ntohl(x));
456127664Sbms}
457127664Sbms
458127664Sbms#ifdef _KERNEL
459127664Sbms
460127664Sbmsstatic void
461127664SbmsAliasLog(char *str, const char *format, ...)
462127664Sbms{
463127664Sbms	va_list ap;
464127664Sbms
465127664Sbms	va_start(ap, format);
466127664Sbms	vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
467127664Sbms	va_end(ap);
468127664Sbms}
469127664Sbms#else
470127664Sbmsstatic void
471127664SbmsAliasLog(FILE *stream, const char *format, ...)
472127664Sbms{
473127664Sbms	va_list ap;
474127664Sbms
475127664Sbms	va_start(ap, format);
476127664Sbms	vfprintf(stream, format, ap);
477127664Sbms	va_end(ap);
478127664Sbms	fflush(stream);
479127664Sbms}
480127664Sbms#endif
481127664Sbms
482127664Sbmsstatic void
483127664SbmsShowAliasStats(struct libalias *la)
484127664Sbms{
485127664Sbms
486127664Sbms	LIBALIAS_LOCK_ASSERT(la);
487127664Sbms/* Used for debugging */
488127664Sbms	if (la->logDesc) {
489127664Sbms		int tot  = la->icmpLinkCount + la->udpLinkCount +
490127664Sbms			la->tcpLinkCount + la->pptpLinkCount +
491127664Sbms			la->protoLinkCount + la->fragmentIdLinkCount +
492127664Sbms			la->fragmentPtrLinkCount;
493127664Sbms
494127664Sbms		AliasLog(la->logDesc,
495127664Sbms			 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
496127664Sbms			 la->icmpLinkCount,
497127664Sbms			 la->udpLinkCount,
498127664Sbms			 la->tcpLinkCount,
499127664Sbms			 la->pptpLinkCount,
500127664Sbms			 la->protoLinkCount,
501127664Sbms			 la->fragmentIdLinkCount,
502127664Sbms			 la->fragmentPtrLinkCount, tot);
503127664Sbms#ifndef _KERNEL
504127664Sbms		AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
505127664Sbms#endif
506127664Sbms	}
507127664Sbms}
508127664Sbms
509127664Sbms/* Internal routines for finding, deleting and adding links
510127664Sbms
511127664SbmsPort Allocation:
512127664Sbms    GetNewPort()             -- find and reserve new alias port number
513127664Sbms    GetSocket()              -- try to allocate a socket for a given port
514127664Sbms
515127664SbmsLink creation and deletion:
516127664Sbms    CleanupAliasData()      - remove all link chains from lookup table
517127664Sbms    IncrementalCleanup()    - look for stale links in a single chain
518127664Sbms    DeleteLink()            - remove link
519127664Sbms    AddLink()               - add link
520127664Sbms    ReLink()                - change link
521127664Sbms
522127664SbmsLink search:
523127664Sbms    FindLinkOut()           - find link for outgoing packets
52417683Spst    FindLinkIn()            - find link for incoming packets
52517683Spst
52617683SpstPort search:
52717683Spst    FindNewPortGroup()      - find an available group of ports
52817683Spst*/
52975107Sfenner
53017683Spst/* Local prototypes */
531127664Sbmsstatic int	GetNewPort(struct libalias *, struct alias_link *, int);
53217683Spst#ifndef	NO_USE_SOCKETS
533127664Sbmsstatic u_short	GetSocket(struct libalias *, u_short, int *, int);
534127664Sbms#endif
535127664Sbmsstatic void	CleanupAliasData(struct libalias *);
536127664Sbms
537127664Sbmsstatic void	IncrementalCleanup(struct libalias *);
538127664Sbms
539127664Sbmsstatic void	DeleteLink(struct alias_link *);
540127664Sbms
541127664Sbmsstatic struct alias_link *
54217683SpstAddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
54317683Spst    u_short, u_short, int, int);
54417683Spst
54575107Sfennerstatic struct alias_link *
546146768SsamReLink(struct alias_link *,
547146768Ssam    struct in_addr, struct in_addr, struct in_addr,
548146768Ssam    u_short, u_short, int, int);
549146768Ssam
550146768Ssamstatic struct alias_link *
551146768Ssam		FindLinkOut   (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
552146768Ssam
553146768Ssamstatic struct alias_link *
554146768Ssam		FindLinkIn    (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
555146768Ssam
556146768Ssam
557146768Ssam#define ALIAS_PORT_BASE            0x08000
558146768Ssam#define ALIAS_PORT_MASK            0x07fff
559146768Ssam#define ALIAS_PORT_MASK_EVEN       0x07ffe
560146768Ssam#define GET_NEW_PORT_MAX_ATTEMPTS       20
561146768Ssam
562146768Ssam#define GET_ALIAS_PORT                  -1
56317683Spst#define GET_ALIAS_ID        GET_ALIAS_PORT
56417683Spst
56517683Spst#define FIND_EVEN_ALIAS_BASE             1
56617683Spst
56717683Spst/* GetNewPort() allocates port numbers.  Note that if a port number
56817683Spst   is already in use, that does not mean that it cannot be used by
56975107Sfenner   another link concurrently.  This is because GetNewPort() looks for
57075107Sfenner   unused triplets: (dest addr, dest port, alias port). */
57117683Spst
57217683Spststatic int
57317683SpstGetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
57417683Spst{
575127664Sbms	int i;
576146768Ssam	int max_trials;
577146768Ssam	u_short port_sys;
578127664Sbms	u_short port_net;
579146768Ssam
580146768Ssam	LIBALIAS_LOCK_ASSERT(la);
581146768Ssam/*
582146768Ssam   Description of alias_port_param for GetNewPort().  When
58317683Spst   this parameter is zero or positive, it precisely specifies
584127664Sbms   the port number.  GetNewPort() will return this number
585127664Sbms   without check that it is in use.
58617683Spst
58717683Spst   When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
58817683Spst   selected port number.
58917683Spst*/
590127664Sbms
591109839Sfenner	if (alias_port_param == GET_ALIAS_PORT) {
592127664Sbms		/*
593146768Ssam		 * The aliasing port is automatically selected by one of
594146768Ssam		 * two methods below:
595146768Ssam		 */
59617683Spst		max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
59717683Spst
598146768Ssam		if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
599146768Ssam			/*
600127664Sbms			 * When the PKT_ALIAS_SAME_PORTS option is chosen,
60117683Spst			 * the first try will be the actual source port. If
602127664Sbms			 * this is already in use, the remainder of the
603127664Sbms			 * trials will be random.
604127664Sbms			 */
605127664Sbms			port_net = lnk->src_port;
606127664Sbms			port_sys = ntohs(port_net);
607109839Sfenner		} else {
608127664Sbms			/* First trial and all subsequent are random. */
609127664Sbms			port_sys = random() & ALIAS_PORT_MASK;
610127664Sbms			port_sys += ALIAS_PORT_BASE;
611127664Sbms			port_net = htons(port_sys);
61217683Spst		}
61317683Spst	} else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
61475107Sfenner		lnk->alias_port = (u_short) alias_port_param;
61575107Sfenner		return (0);
61617683Spst	} else {
61717683Spst#ifdef LIBALIAS_DEBUG
61875107Sfenner		fprintf(stderr, "PacketAlias/GetNewPort(): ");
61917683Spst		fprintf(stderr, "input parameter error\n");
62017683Spst#endif
62117683Spst		return (-1);
62217683Spst	}
62317683Spst
62417683Spst
62517683Spst/* Port number search */
62617683Spst	for (i = 0; i < max_trials; i++) {
62775107Sfenner		int go_ahead;
62875107Sfenner		struct alias_link *search_result;
62917683Spst
63017683Spst		search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
63117683Spst		    lnk->dst_port, port_net,
63217683Spst		    lnk->link_type, 0);
63375107Sfenner
63475107Sfenner		if (search_result == NULL)
63517683Spst			go_ahead = 1;
63617683Spst		else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
63775107Sfenner		    && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
63875107Sfenner			go_ahead = 1;
63975107Sfenner		else
64075107Sfenner			go_ahead = 0;
641127664Sbms
642127664Sbms		if (go_ahead) {
64375107Sfenner#ifndef	NO_USE_SOCKETS
64475107Sfenner			if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
64575107Sfenner			    && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
64639291Sfenner			    && ((lnk->link_type == LINK_TCP) ||
647127664Sbms			    (lnk->link_type == LINK_UDP))) {
648127664Sbms				if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
649127664Sbms					lnk->alias_port = port_net;
65075107Sfenner					return (0);
65175107Sfenner				}
65275107Sfenner			} else {
65375107Sfenner#endif
65475107Sfenner				lnk->alias_port = port_net;
65575107Sfenner				return (0);
65639291Sfenner#ifndef	NO_USE_SOCKETS
65775107Sfenner			}
65875107Sfenner#endif
65975107Sfenner		}
66075107Sfenner		port_sys = random() & ALIAS_PORT_MASK;
66175107Sfenner		port_sys += ALIAS_PORT_BASE;
66275107Sfenner		port_net = htons(port_sys);
66375107Sfenner	}
66475107Sfenner
66575107Sfenner#ifdef LIBALIAS_DEBUG
66675107Sfenner	fprintf(stderr, "PacketAlias/GetnewPort(): ");
66775107Sfenner	fprintf(stderr, "could not find free port\n");
66875107Sfenner#endif
66975107Sfenner
67075107Sfenner	return (-1);
67117683Spst}
67217683Spst
67375107Sfenner#ifndef	NO_USE_SOCKETS
67417683Spststatic		u_short
67517683SpstGetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
67675107Sfenner{
67775107Sfenner	int err;
67817683Spst	int sock;
67917683Spst	struct sockaddr_in sock_addr;
68098530Sfenner
68198530Sfenner	LIBALIAS_LOCK_ASSERT(la);
68298530Sfenner	if (link_type == LINK_TCP)
68398530Sfenner		sock = socket(AF_INET, SOCK_STREAM, 0);
68456889Sfenner	else if (link_type == LINK_UDP)
68598530Sfenner		sock = socket(AF_INET, SOCK_DGRAM, 0);
68698530Sfenner	else {
68798530Sfenner#ifdef LIBALIAS_DEBUG
68898530Sfenner		fprintf(stderr, "PacketAlias/GetSocket(): ");
68998530Sfenner		fprintf(stderr, "incorrect link type\n");
69098530Sfenner#endif
69198530Sfenner		return (0);
69298530Sfenner	}
69398530Sfenner
69498530Sfenner	if (sock < 0) {
69598530Sfenner#ifdef LIBALIAS_DEBUG
69698530Sfenner		fprintf(stderr, "PacketAlias/GetSocket(): ");
69798530Sfenner		fprintf(stderr, "socket() error %d\n", *sockfd);
69898530Sfenner#endif
699127664Sbms		return (0);
700127664Sbms	}
701127664Sbms	sock_addr.sin_family = AF_INET;
702127664Sbms	sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
70398530Sfenner	sock_addr.sin_port = port_net;
70475107Sfenner
70598530Sfenner	err = bind(sock,
70675107Sfenner	    (struct sockaddr *)&sock_addr,
707127664Sbms	    sizeof(sock_addr));
70898530Sfenner	if (err == 0) {
70998530Sfenner		la->sockCount++;
71056889Sfenner		*sockfd = sock;
71156889Sfenner		return (1);
71239291Sfenner	} else {
71339291Sfenner		close(sock);
71439291Sfenner		return (0);
71539291Sfenner	}
71639291Sfenner}
71739291Sfenner#endif
71839291Sfenner
71939291Sfenner/* FindNewPortGroup() returns a base port number for an available
72039291Sfenner   range of contiguous port numbers. Note that if a port number
72139291Sfenner   is already in use, that does not mean that it cannot be used by
72239291Sfenner   another link concurrently.  This is because FindNewPortGroup()
72356889Sfenner   looks for unused triplets: (dest addr, dest port, alias port). */
72456889Sfenner
725127664Sbmsint
72656889SfennerFindNewPortGroup(struct libalias *la,
72756889Sfenner    struct in_addr dst_addr,
72856889Sfenner    struct in_addr alias_addr,
72956889Sfenner    u_short src_port,
73056889Sfenner    u_short dst_port,
73139291Sfenner    u_short port_count,
73239291Sfenner    u_char proto,
733146768Ssam    u_char align)
734146768Ssam{
735147894Ssam	int i, j;
736146768Ssam	int max_trials;
737146768Ssam	u_short port_sys;
738146768Ssam	int link_type;
73917683Spst
74017683Spst	LIBALIAS_LOCK_ASSERT(la);
741127664Sbms	/*
742109839Sfenner	 * Get link_type from protocol
743127664Sbms	 */
744127664Sbms
745127664Sbms	switch (proto) {
746109839Sfenner	case IPPROTO_UDP:
747127664Sbms		link_type = LINK_UDP;
748146768Ssam		break;
749146768Ssam	case IPPROTO_TCP:
750146768Ssam		link_type = LINK_TCP;
751162020Ssam		break;
752109839Sfenner	default:
753109839Sfenner		return (0);
754109839Sfenner		break;
755109839Sfenner	}
756109839Sfenner
757109839Sfenner	/*
758127664Sbms	 * The aliasing port is automatically selected by one of two
759109839Sfenner	 * methods below:
760109839Sfenner	 */
761146768Ssam	max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
762109839Sfenner
763109839Sfenner	if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
764109839Sfenner		/*
765146768Ssam		 * When the ALIAS_SAME_PORTS option is chosen, the first
766146768Ssam		 * try will be the actual source port. If this is already
767146768Ssam		 * in use, the remainder of the trials will be random.
768146768Ssam		 */
769146768Ssam		port_sys = ntohs(src_port);
770146768Ssam
771146768Ssam	} else {
772146768Ssam
773146768Ssam		/* First trial and all subsequent are random. */
774146768Ssam		if (align == FIND_EVEN_ALIAS_BASE)
775146768Ssam			port_sys = random() & ALIAS_PORT_MASK_EVEN;
776146768Ssam		else
777146768Ssam			port_sys = random() & ALIAS_PORT_MASK;
778146768Ssam
779146768Ssam		port_sys += ALIAS_PORT_BASE;
780146768Ssam	}
781146768Ssam
782146768Ssam/* Port number search */
783146768Ssam	for (i = 0; i < max_trials; i++) {
784146768Ssam
785146768Ssam		struct alias_link *search_result;
786146768Ssam
787146768Ssam		for (j = 0; j < port_count; j++)
788146768Ssam			if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
789146768Ssam			    dst_port, htons(port_sys + j),
790146768Ssam			    link_type, 0)))
791146768Ssam				break;
792146768Ssam
793146768Ssam		/* Found a good range, return base */
794146768Ssam		if (j == port_count)
795146768Ssam			return (htons(port_sys));
796146768Ssam
797146768Ssam		/* Find a new base to try */
798146768Ssam		if (align == FIND_EVEN_ALIAS_BASE)
799109839Sfenner			port_sys = random() & ALIAS_PORT_MASK_EVEN;
800109839Sfenner		else
801127664Sbms			port_sys = random() & ALIAS_PORT_MASK;
802127664Sbms
803127664Sbms		port_sys += ALIAS_PORT_BASE;
804127664Sbms	}
805127664Sbms
806127664Sbms#ifdef LIBALIAS_DEBUG
807109839Sfenner	fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
808127664Sbms	fprintf(stderr, "could not find free port(s)\n");
809109839Sfenner#endif
810146768Ssam
811146768Ssam	return (0);
812146768Ssam}
813146768Ssam
814146768Ssamstatic void
815146768SsamCleanupAliasData(struct libalias *la)
816146768Ssam{
817146768Ssam	struct alias_link *lnk;
818146768Ssam	int i;
819146768Ssam
820146768Ssam	LIBALIAS_LOCK_ASSERT(la);
821146768Ssam	for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
822146768Ssam		while ((lnk = LIST_FIRST(&la->linkTableOut[i])) != NULL)
823146768Ssam			DeleteLink(lnk);
824146768Ssam	}
825146768Ssam
826146768Ssam	la->cleanupIndex = 0;
827146768Ssam}
828146768Ssam
829146768Ssam
830146768Ssamstatic void
831146768SsamIncrementalCleanup(struct libalias *la)
832146768Ssam{
833146768Ssam	struct alias_link *lnk, *lnk_tmp;
834146768Ssam
835146768Ssam	LIBALIAS_LOCK_ASSERT(la);
836146768Ssam	LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
837146768Ssam	    list_out, lnk_tmp) {
838146768Ssam		if (la->timeStamp - lnk->timestamp > lnk->expire_time)
839146768Ssam			DeleteLink(lnk);
840146768Ssam	}
841146768Ssam
842146768Ssam	if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
843146768Ssam		la->cleanupIndex = 0;
844146768Ssam}
845146768Ssam
84617683Spststatic void
84717683SpstDeleteLink(struct alias_link *lnk)
848127664Sbms{
849127664Sbms	struct libalias *la = lnk->la;
850127664Sbms
851127664Sbms	LIBALIAS_LOCK_ASSERT(la);
852127664Sbms/* Don't do anything if the link is marked permanent */
85317683Spst	if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
85417683Spst		return;
85517683Spst
85617683Spst#ifndef NO_FW_PUNCH
85775107Sfenner/* Delete associated firewall hole, if any */
85875107Sfenner	ClearFWHole(lnk);
85917683Spst#endif
86017683Spst
86117683Spst/* Free memory allocated for LSNAT server pool */
86275107Sfenner	if (lnk->server != NULL) {
86375107Sfenner		struct server *head, *curr, *next;
86475107Sfenner
86575107Sfenner		head = curr = lnk->server;
86675107Sfenner		do {
86775107Sfenner			next = curr->next;
86875107Sfenner			free(curr);
86975107Sfenner		} while ((curr = next) != head);
87075107Sfenner	}
87175107Sfenner/* Adjust output table pointers */
87275107Sfenner	LIST_REMOVE(lnk, list_out);
87375107Sfenner
87475107Sfenner/* Adjust input table pointers */
87575107Sfenner	LIST_REMOVE(lnk, list_in);
87675107Sfenner#ifndef	NO_USE_SOCKETS
87775107Sfenner/* Close socket, if one has been allocated */
87875107Sfenner	if (lnk->sockfd != -1) {
87975107Sfenner		la->sockCount--;
88075107Sfenner		close(lnk->sockfd);
88175107Sfenner	}
88275107Sfenner#endif
88375107Sfenner/* Link-type dependent cleanup */
88475107Sfenner	switch (lnk->link_type) {
88575107Sfenner	case LINK_ICMP:
88675107Sfenner		la->icmpLinkCount--;
88775107Sfenner		break;
88875107Sfenner	case LINK_UDP:
88975107Sfenner		la->udpLinkCount--;
89075107Sfenner		break;
89175107Sfenner	case LINK_TCP:
89275107Sfenner		la->tcpLinkCount--;
89375107Sfenner		free(lnk->data.tcp);
89475107Sfenner		break;
89575107Sfenner	case LINK_PPTP:
89675107Sfenner		la->pptpLinkCount--;
89775107Sfenner		break;
89875107Sfenner	case LINK_FRAGMENT_ID:
89975107Sfenner		la->fragmentIdLinkCount--;
90075107Sfenner		break;
90175107Sfenner	case LINK_FRAGMENT_PTR:
90275107Sfenner		la->fragmentPtrLinkCount--;
90375107Sfenner		if (lnk->data.frag_ptr != NULL)
90475107Sfenner			free(lnk->data.frag_ptr);
90575107Sfenner		break;
90675107Sfenner	case LINK_ADDR:
90775107Sfenner		break;
90875107Sfenner	default:
90975107Sfenner		la->protoLinkCount--;
91075107Sfenner		break;
91175107Sfenner	}
91275107Sfenner
91375107Sfenner/* Free memory */
91475107Sfenner	free(lnk);
91575107Sfenner
91675107Sfenner/* Write statistics, if logging enabled */
91775107Sfenner	if (la->packetAliasMode & PKT_ALIAS_LOG) {
91875107Sfenner		ShowAliasStats(la);
91975107Sfenner	}
92098530Sfenner}
92117683Spst
92298530Sfenner
92398530Sfennerstatic struct alias_link *
92498530SfennerAddLink(struct libalias *la, struct in_addr src_addr,
92598530Sfenner    struct in_addr dst_addr,
92698530Sfenner    struct in_addr alias_addr,
92717683Spst    u_short src_port,
92817683Spst    u_short dst_port,
92975107Sfenner    int alias_port_param,	/* if less than zero, alias   */
93075107Sfenner    int link_type)
93117683Spst{				/* port will be automatically *//* chosen.
93217683Spst				 * If greater than    */
93317683Spst	u_int start_point;	/* zero, equal to alias port  */
93417683Spst	struct alias_link *lnk;
93517683Spst
93675107Sfenner	LIBALIAS_LOCK_ASSERT(la);
93775107Sfenner	lnk = malloc(sizeof(struct alias_link));
93817683Spst	if (lnk != NULL) {
93917683Spst		/* Basic initialization */
940127664Sbms		lnk->la = la;
941127664Sbms		lnk->src_addr = src_addr;
942127664Sbms		lnk->dst_addr = dst_addr;
943127664Sbms		lnk->alias_addr = alias_addr;
944127664Sbms		lnk->proxy_addr.s_addr = INADDR_ANY;
94517683Spst		lnk->src_port = src_port;
946127664Sbms		lnk->dst_port = dst_port;
947146768Ssam		lnk->proxy_port = 0;
948146768Ssam		lnk->server = NULL;
949146768Ssam		lnk->link_type = link_type;
950146768Ssam#ifndef	NO_USE_SOCKETS
951146768Ssam		lnk->sockfd = -1;
952146768Ssam#endif
953146768Ssam		lnk->flags = 0;
954146768Ssam		lnk->pflags = 0;
955146768Ssam		lnk->timestamp = la->timeStamp;
956146768Ssam
957146768Ssam		/* Expiration time */
958146768Ssam		switch (link_type) {
959146768Ssam		case LINK_ICMP:
960146768Ssam			lnk->expire_time = ICMP_EXPIRE_TIME;
961146768Ssam			break;
962146768Ssam		case LINK_UDP:
963146768Ssam			lnk->expire_time = UDP_EXPIRE_TIME;
964146768Ssam			break;
965146768Ssam		case LINK_TCP:
966146768Ssam			lnk->expire_time = TCP_EXPIRE_INITIAL;
967146768Ssam			break;
968146768Ssam		case LINK_PPTP:
969127664Sbms			lnk->flags |= LINK_PERMANENT;	/* no timeout. */
970127664Sbms			break;
971127664Sbms		case LINK_FRAGMENT_ID:
972127664Sbms			lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
973127664Sbms			break;
974127664Sbms		case LINK_FRAGMENT_PTR:
975127664Sbms			lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
976127664Sbms			break;
977127664Sbms		case LINK_ADDR:
978127664Sbms			break;
979127664Sbms		default:
980127664Sbms			lnk->expire_time = PROTO_EXPIRE_TIME;
981127664Sbms			break;
982127664Sbms		}
983127664Sbms
984127664Sbms		/* Determine alias flags */
985127664Sbms		if (dst_addr.s_addr == INADDR_ANY)
986127664Sbms			lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
987127664Sbms		if (dst_port == 0)
988127664Sbms			lnk->flags |= LINK_UNKNOWN_DEST_PORT;
989127664Sbms
990127664Sbms		/* Determine alias port */
991127664Sbms		if (GetNewPort(la, lnk, alias_port_param) != 0) {
992127664Sbms			free(lnk);
993127664Sbms			return (NULL);
994127664Sbms		}
995127664Sbms		/* Link-type dependent initialization */
996127664Sbms		switch (link_type) {
997127664Sbms			struct tcp_dat *aux_tcp;
998127664Sbms
999127664Sbms		case LINK_ICMP:
1000127664Sbms			la->icmpLinkCount++;
1001127664Sbms			break;
1002127664Sbms		case LINK_UDP:
1003127664Sbms			la->udpLinkCount++;
1004147894Ssam			break;
1005127664Sbms		case LINK_TCP:
1006127664Sbms			aux_tcp = malloc(sizeof(struct tcp_dat));
1007127664Sbms			if (aux_tcp != NULL) {
1008127664Sbms				int i;
1009147894Ssam
1010147894Ssam				la->tcpLinkCount++;
1011147894Ssam				aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1012147894Ssam				aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1013147894Ssam				aux_tcp->state.index = 0;
1014127664Sbms				aux_tcp->state.ack_modified = 0;
1015127664Sbms				for (i = 0; i < N_LINK_TCP_DATA; i++)
1016127664Sbms					aux_tcp->ack[i].active = 0;
1017146768Ssam				aux_tcp->fwhole = -1;
1018127664Sbms				lnk->data.tcp = aux_tcp;
1019147894Ssam			} else {
1020127664Sbms#ifdef LIBALIAS_DEBUG
1021127664Sbms				fprintf(stderr, "PacketAlias/AddLink: ");
1022127664Sbms				fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1023127664Sbms#endif
1024146768Ssam				free(lnk);
1025127664Sbms				return (NULL);
102617683Spst			}
102717683Spst			break;
102817683Spst		case LINK_PPTP:
1029146768Ssam			la->pptpLinkCount++;
1030146768Ssam			break;
103117683Spst		case LINK_FRAGMENT_ID:
103217683Spst			la->fragmentIdLinkCount++;
103317683Spst			break;
103417683Spst		case LINK_FRAGMENT_PTR:
103517683Spst			la->fragmentPtrLinkCount++;
1036127664Sbms			break;
103717683Spst		case LINK_ADDR:
1038127664Sbms			break;
1039127664Sbms		default:
1040127664Sbms			la->protoLinkCount++;
1041127664Sbms			break;
1042127664Sbms		}
1043127664Sbms
1044127664Sbms		/* Set up pointers for output lookup table */
1045127664Sbms		start_point = StartPointOut(src_addr, dst_addr,
1046127664Sbms		    src_port, dst_port, link_type);
1047127664Sbms		LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1048127664Sbms
104956889Sfenner		/* Set up pointers for input lookup table */
105056889Sfenner		start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
105156889Sfenner		LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
105256889Sfenner	} else {
105356889Sfenner#ifdef LIBALIAS_DEBUG
105475107Sfenner		fprintf(stderr, "PacketAlias/AddLink(): ");
1055127664Sbms		fprintf(stderr, "malloc() call failed.\n");
1056127664Sbms#endif
1057127664Sbms	}
105875107Sfenner	if (la->packetAliasMode & PKT_ALIAS_LOG) {
105975107Sfenner		ShowAliasStats(la);
1060127664Sbms	}
1061127664Sbms	return (lnk);
1062127664Sbms}
1063127664Sbms
1064127664Sbmsstatic struct alias_link *
1065127664SbmsReLink(struct alias_link *old_lnk,
1066127664Sbms    struct in_addr src_addr,
1067127664Sbms    struct in_addr dst_addr,
1068127664Sbms    struct in_addr alias_addr,
1069127664Sbms    u_short src_port,
1070127664Sbms    u_short dst_port,
1071127664Sbms    int alias_port_param,	/* if less than zero, alias   */
1072127664Sbms    int link_type)
107375107Sfenner{				/* port will be automatically *//* chosen.
107475107Sfenner				 * If greater than    */
107517683Spst	struct alias_link *new_lnk;	/* zero, equal to alias port  */
107617683Spst	struct libalias *la = old_lnk->la;
1077127664Sbms
1078146768Ssam	LIBALIAS_LOCK_ASSERT(la);
1079146768Ssam	new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1080146768Ssam	    src_port, dst_port, alias_port_param,
1081146768Ssam	    link_type);
1082146768Ssam#ifndef NO_FW_PUNCH
1083146768Ssam	if (new_lnk != NULL &&
1084146768Ssam	    old_lnk->link_type == LINK_TCP &&
1085146768Ssam	    old_lnk->data.tcp->fwhole > 0) {
108617683Spst		PunchFWHole(new_lnk);
108717683Spst	}
1088109839Sfenner#endif
1089147894Ssam	DeleteLink(old_lnk);
1090147894Ssam	return (new_lnk);
1091147894Ssam}
1092147894Ssam
1093127664Sbmsstatic struct alias_link *
1094162012Ssam_FindLinkOut(struct libalias *la, struct in_addr src_addr,
1095147894Ssam    struct in_addr dst_addr,
1096147894Ssam    u_short src_port,
1097147894Ssam    u_short dst_port,
1098147894Ssam    int link_type,
1099147894Ssam    int replace_partial_links)
1100147894Ssam{
1101162012Ssam	u_int i;
1102147894Ssam	struct alias_link *lnk;
1103162012Ssam
1104147894Ssam	LIBALIAS_LOCK_ASSERT(la);
1105162012Ssam	i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1106147894Ssam	LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1107147894Ssam		if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1108147894Ssam		    lnk->src_addr.s_addr == src_addr.s_addr &&
1109162012Ssam		    lnk->src_port == src_port &&
1110147894Ssam		    lnk->dst_port == dst_port &&
1111147894Ssam		    lnk->link_type == link_type &&
1112147894Ssam		    lnk->server == NULL) {
1113162012Ssam			lnk->timestamp = la->timeStamp;
1114147894Ssam			break;
1115147894Ssam		}
1116147894Ssam	}
1117147894Ssam
1118147894Ssam/* Search for partially specified links. */
1119147894Ssam	if (lnk == NULL && replace_partial_links) {
1120147894Ssam		if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1121147894Ssam			lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1122147894Ssam			    link_type, 0);
1123147894Ssam			if (lnk == NULL)
1124147894Ssam				lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1125147894Ssam				    dst_port, link_type, 0);
1126127664Sbms		}
1127109839Sfenner		if (lnk == NULL &&
1128127664Sbms		    (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1129109839Sfenner			lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1130109839Sfenner			    link_type, 0);
1131109839Sfenner		}
1132127664Sbms		if (lnk != NULL) {
1133109839Sfenner			lnk = ReLink(lnk,
1134127664Sbms			    src_addr, dst_addr, lnk->alias_addr,
1135127664Sbms			    src_port, dst_port, lnk->alias_port,
1136109839Sfenner			    link_type);
1137		}
1138	}
1139	return (lnk);
1140}
1141
1142static struct alias_link *
1143FindLinkOut(struct libalias *la, struct in_addr src_addr,
1144    struct in_addr dst_addr,
1145    u_short src_port,
1146    u_short dst_port,
1147    int link_type,
1148    int replace_partial_links)
1149{
1150	struct alias_link *lnk;
1151
1152	LIBALIAS_LOCK_ASSERT(la);
1153	lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1154	    link_type, replace_partial_links);
1155
1156	if (lnk == NULL) {
1157		/*
1158		 * The following allows permanent links to be specified as
1159		 * using the default source address (i.e. device interface
1160		 * address) without knowing in advance what that address
1161		 * is.
1162		 */
1163		if (la->aliasAddress.s_addr != INADDR_ANY &&
1164		    src_addr.s_addr == la->aliasAddress.s_addr) {
1165			lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1166			    link_type, replace_partial_links);
1167		}
1168	}
1169	return (lnk);
1170}
1171
1172
1173static struct alias_link *
1174_FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1175    struct in_addr alias_addr,
1176    u_short dst_port,
1177    u_short alias_port,
1178    int link_type,
1179    int replace_partial_links)
1180{
1181	int flags_in;
1182	u_int start_point;
1183	struct alias_link *lnk;
1184	struct alias_link *lnk_fully_specified;
1185	struct alias_link *lnk_unknown_all;
1186	struct alias_link *lnk_unknown_dst_addr;
1187	struct alias_link *lnk_unknown_dst_port;
1188
1189	LIBALIAS_LOCK_ASSERT(la);
1190/* Initialize pointers */
1191	lnk_fully_specified = NULL;
1192	lnk_unknown_all = NULL;
1193	lnk_unknown_dst_addr = NULL;
1194	lnk_unknown_dst_port = NULL;
1195
1196/* If either the dest addr or port is unknown, the search
1197   loop will have to know about this. */
1198
1199	flags_in = 0;
1200	if (dst_addr.s_addr == INADDR_ANY)
1201		flags_in |= LINK_UNKNOWN_DEST_ADDR;
1202	if (dst_port == 0)
1203		flags_in |= LINK_UNKNOWN_DEST_PORT;
1204
1205/* Search loop */
1206	start_point = StartPointIn(alias_addr, alias_port, link_type);
1207	LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1208		int flags;
1209
1210		flags = flags_in | lnk->flags;
1211		if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1212			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1213			    && lnk->alias_port == alias_port
1214			    && lnk->dst_addr.s_addr == dst_addr.s_addr
1215			    && lnk->dst_port == dst_port
1216			    && lnk->link_type == link_type) {
1217				lnk_fully_specified = lnk;
1218				break;
1219			}
1220		} else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1221		    && (flags & LINK_UNKNOWN_DEST_PORT)) {
1222			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1223			    && lnk->alias_port == alias_port
1224			    && lnk->link_type == link_type) {
1225				if (lnk_unknown_all == NULL)
1226					lnk_unknown_all = lnk;
1227			}
1228		} else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1229			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1230			    && lnk->alias_port == alias_port
1231			    && lnk->link_type == link_type
1232			    && lnk->dst_port == dst_port) {
1233				if (lnk_unknown_dst_addr == NULL)
1234					lnk_unknown_dst_addr = lnk;
1235			}
1236		} else if (flags & LINK_UNKNOWN_DEST_PORT) {
1237			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1238			    && lnk->alias_port == alias_port
1239			    && lnk->link_type == link_type
1240			    && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1241				if (lnk_unknown_dst_port == NULL)
1242					lnk_unknown_dst_port = lnk;
1243			}
1244		}
1245	}
1246
1247
1248
1249	if (lnk_fully_specified != NULL) {
1250		lnk_fully_specified->timestamp = la->timeStamp;
1251		lnk = lnk_fully_specified;
1252	} else if (lnk_unknown_dst_port != NULL)
1253		lnk = lnk_unknown_dst_port;
1254	else if (lnk_unknown_dst_addr != NULL)
1255		lnk = lnk_unknown_dst_addr;
1256	else if (lnk_unknown_all != NULL)
1257		lnk = lnk_unknown_all;
1258	else
1259		return (NULL);
1260
1261	if (replace_partial_links &&
1262	    (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1263		struct in_addr src_addr;
1264		u_short src_port;
1265
1266		if (lnk->server != NULL) {	/* LSNAT link */
1267			src_addr = lnk->server->addr;
1268			src_port = lnk->server->port;
1269			lnk->server = lnk->server->next;
1270		} else {
1271			src_addr = lnk->src_addr;
1272			src_port = lnk->src_port;
1273		}
1274
1275		lnk = ReLink(lnk,
1276		    src_addr, dst_addr, alias_addr,
1277		    src_port, dst_port, alias_port,
1278		    link_type);
1279	}
1280	return (lnk);
1281}
1282
1283static struct alias_link *
1284FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1285    struct in_addr alias_addr,
1286    u_short dst_port,
1287    u_short alias_port,
1288    int link_type,
1289    int replace_partial_links)
1290{
1291	struct alias_link *lnk;
1292
1293	LIBALIAS_LOCK_ASSERT(la);
1294	lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1295	    link_type, replace_partial_links);
1296
1297	if (lnk == NULL) {
1298		/*
1299		 * The following allows permanent links to be specified as
1300		 * using the default aliasing address (i.e. device
1301		 * interface address) without knowing in advance what that
1302		 * address is.
1303		 */
1304		if (la->aliasAddress.s_addr != INADDR_ANY &&
1305		    alias_addr.s_addr == la->aliasAddress.s_addr) {
1306			lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1307			    link_type, replace_partial_links);
1308		}
1309	}
1310	return (lnk);
1311}
1312
1313
1314
1315
1316/* External routines for finding/adding links
1317
1318-- "external" means outside alias_db.c, but within alias*.c --
1319
1320    FindIcmpIn(), FindIcmpOut()
1321    FindFragmentIn1(), FindFragmentIn2()
1322    AddFragmentPtrLink(), FindFragmentPtr()
1323    FindProtoIn(), FindProtoOut()
1324    FindUdpTcpIn(), FindUdpTcpOut()
1325    AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1326    FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1327    FindOriginalAddress(), FindAliasAddress()
1328
1329(prototypes in alias_local.h)
1330*/
1331
1332
1333struct alias_link *
1334FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1335    struct in_addr alias_addr,
1336    u_short id_alias,
1337    int create)
1338{
1339	struct alias_link *lnk;
1340
1341	LIBALIAS_LOCK_ASSERT(la);
1342	lnk = FindLinkIn(la, dst_addr, alias_addr,
1343	    NO_DEST_PORT, id_alias,
1344	    LINK_ICMP, 0);
1345	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1346		struct in_addr target_addr;
1347
1348		target_addr = FindOriginalAddress(la, alias_addr);
1349		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1350		    id_alias, NO_DEST_PORT, id_alias,
1351		    LINK_ICMP);
1352	}
1353	return (lnk);
1354}
1355
1356
1357struct alias_link *
1358FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1359    struct in_addr dst_addr,
1360    u_short id,
1361    int create)
1362{
1363	struct alias_link *lnk;
1364
1365	LIBALIAS_LOCK_ASSERT(la);
1366	lnk = FindLinkOut(la, src_addr, dst_addr,
1367	    id, NO_DEST_PORT,
1368	    LINK_ICMP, 0);
1369	if (lnk == NULL && create) {
1370		struct in_addr alias_addr;
1371
1372		alias_addr = FindAliasAddress(la, src_addr);
1373		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1374		    id, NO_DEST_PORT, GET_ALIAS_ID,
1375		    LINK_ICMP);
1376	}
1377	return (lnk);
1378}
1379
1380
1381struct alias_link *
1382FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1383    struct in_addr alias_addr,
1384    u_short ip_id)
1385{
1386	struct alias_link *lnk;
1387
1388	LIBALIAS_LOCK_ASSERT(la);
1389	lnk = FindLinkIn(la, dst_addr, alias_addr,
1390	    NO_DEST_PORT, ip_id,
1391	    LINK_FRAGMENT_ID, 0);
1392
1393	if (lnk == NULL) {
1394		lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1395		    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1396		    LINK_FRAGMENT_ID);
1397	}
1398	return (lnk);
1399}
1400
1401
1402struct alias_link *
1403FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,	/* Doesn't add a link if
1404								 * one */
1405    struct in_addr alias_addr,	/* is not found.           */
1406    u_short ip_id)
1407{
1408
1409	LIBALIAS_LOCK_ASSERT(la);
1410	return FindLinkIn(la, dst_addr, alias_addr,
1411	    NO_DEST_PORT, ip_id,
1412	    LINK_FRAGMENT_ID, 0);
1413}
1414
1415
1416struct alias_link *
1417AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1418    u_short ip_id)
1419{
1420
1421	LIBALIAS_LOCK_ASSERT(la);
1422	return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1423	    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1424	    LINK_FRAGMENT_PTR);
1425}
1426
1427
1428struct alias_link *
1429FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1430    u_short ip_id)
1431{
1432
1433	LIBALIAS_LOCK_ASSERT(la);
1434	return FindLinkIn(la, dst_addr, la->nullAddress,
1435	    NO_DEST_PORT, ip_id,
1436	    LINK_FRAGMENT_PTR, 0);
1437}
1438
1439
1440struct alias_link *
1441FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1442    struct in_addr alias_addr,
1443    u_char proto)
1444{
1445	struct alias_link *lnk;
1446
1447	LIBALIAS_LOCK_ASSERT(la);
1448	lnk = FindLinkIn(la, dst_addr, alias_addr,
1449	    NO_DEST_PORT, 0,
1450	    proto, 1);
1451
1452	if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1453		struct in_addr target_addr;
1454
1455		target_addr = FindOriginalAddress(la, alias_addr);
1456		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1457		    NO_SRC_PORT, NO_DEST_PORT, 0,
1458		    proto);
1459	}
1460	return (lnk);
1461}
1462
1463
1464struct alias_link *
1465FindProtoOut(struct libalias *la, struct in_addr src_addr,
1466    struct in_addr dst_addr,
1467    u_char proto)
1468{
1469	struct alias_link *lnk;
1470
1471	LIBALIAS_LOCK_ASSERT(la);
1472	lnk = FindLinkOut(la, src_addr, dst_addr,
1473	    NO_SRC_PORT, NO_DEST_PORT,
1474	    proto, 1);
1475
1476	if (lnk == NULL) {
1477		struct in_addr alias_addr;
1478
1479		alias_addr = FindAliasAddress(la, src_addr);
1480		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1481		    NO_SRC_PORT, NO_DEST_PORT, 0,
1482		    proto);
1483	}
1484	return (lnk);
1485}
1486
1487
1488struct alias_link *
1489FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1490    struct in_addr alias_addr,
1491    u_short dst_port,
1492    u_short alias_port,
1493    u_char proto,
1494    int create)
1495{
1496	int link_type;
1497	struct alias_link *lnk;
1498
1499	LIBALIAS_LOCK_ASSERT(la);
1500	switch (proto) {
1501	case IPPROTO_UDP:
1502		link_type = LINK_UDP;
1503		break;
1504	case IPPROTO_TCP:
1505		link_type = LINK_TCP;
1506		break;
1507	default:
1508		return (NULL);
1509		break;
1510	}
1511
1512	lnk = FindLinkIn(la, dst_addr, alias_addr,
1513	    dst_port, alias_port,
1514	    link_type, create);
1515
1516	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1517		struct in_addr target_addr;
1518
1519		target_addr = FindOriginalAddress(la, alias_addr);
1520		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1521		    alias_port, dst_port, alias_port,
1522		    link_type);
1523	}
1524	return (lnk);
1525}
1526
1527
1528struct alias_link *
1529FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1530    struct in_addr dst_addr,
1531    u_short src_port,
1532    u_short dst_port,
1533    u_char proto,
1534    int create)
1535{
1536	int link_type;
1537	struct alias_link *lnk;
1538
1539	LIBALIAS_LOCK_ASSERT(la);
1540	switch (proto) {
1541	case IPPROTO_UDP:
1542		link_type = LINK_UDP;
1543		break;
1544	case IPPROTO_TCP:
1545		link_type = LINK_TCP;
1546		break;
1547	default:
1548		return (NULL);
1549		break;
1550	}
1551
1552	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1553
1554	if (lnk == NULL && create) {
1555		struct in_addr alias_addr;
1556
1557		alias_addr = FindAliasAddress(la, src_addr);
1558		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1559		    src_port, dst_port, GET_ALIAS_PORT,
1560		    link_type);
1561	}
1562	return (lnk);
1563}
1564
1565
1566struct alias_link *
1567AddPptp(struct libalias *la, struct in_addr src_addr,
1568    struct in_addr dst_addr,
1569    struct in_addr alias_addr,
1570    u_int16_t src_call_id)
1571{
1572	struct alias_link *lnk;
1573
1574	LIBALIAS_LOCK_ASSERT(la);
1575	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1576	    src_call_id, 0, GET_ALIAS_PORT,
1577	    LINK_PPTP);
1578
1579	return (lnk);
1580}
1581
1582
1583struct alias_link *
1584FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1585    struct in_addr dst_addr,
1586    u_int16_t src_call_id)
1587{
1588	u_int i;
1589	struct alias_link *lnk;
1590
1591	LIBALIAS_LOCK_ASSERT(la);
1592	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1593	LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1594	    if (lnk->link_type == LINK_PPTP &&
1595	    lnk->src_addr.s_addr == src_addr.s_addr &&
1596	    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1597	    lnk->src_port == src_call_id)
1598		break;
1599
1600	return (lnk);
1601}
1602
1603
1604struct alias_link *
1605FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1606    struct in_addr dst_addr,
1607    u_int16_t dst_call_id)
1608{
1609	u_int i;
1610	struct alias_link *lnk;
1611
1612	LIBALIAS_LOCK_ASSERT(la);
1613	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1614	LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1615	    if (lnk->link_type == LINK_PPTP &&
1616	    lnk->src_addr.s_addr == src_addr.s_addr &&
1617	    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1618	    lnk->dst_port == dst_call_id)
1619		break;
1620
1621	return (lnk);
1622}
1623
1624
1625struct alias_link *
1626FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1627    struct in_addr alias_addr,
1628    u_int16_t dst_call_id)
1629{
1630	u_int i;
1631	struct alias_link *lnk;
1632
1633	LIBALIAS_LOCK_ASSERT(la);
1634	i = StartPointIn(alias_addr, 0, LINK_PPTP);
1635	LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1636	    if (lnk->link_type == LINK_PPTP &&
1637	    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1638	    lnk->alias_addr.s_addr == alias_addr.s_addr &&
1639	    lnk->dst_port == dst_call_id)
1640		break;
1641
1642	return (lnk);
1643}
1644
1645
1646struct alias_link *
1647FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1648    struct in_addr alias_addr,
1649    u_int16_t alias_call_id)
1650{
1651	struct alias_link *lnk;
1652
1653	LIBALIAS_LOCK_ASSERT(la);
1654	lnk = FindLinkIn(la, dst_addr, alias_addr,
1655	    0 /* any */ , alias_call_id,
1656	    LINK_PPTP, 0);
1657
1658
1659	return (lnk);
1660}
1661
1662
1663struct alias_link *
1664FindRtspOut(struct libalias *la, struct in_addr src_addr,
1665    struct in_addr dst_addr,
1666    u_short src_port,
1667    u_short alias_port,
1668    u_char proto)
1669{
1670	int link_type;
1671	struct alias_link *lnk;
1672
1673	LIBALIAS_LOCK_ASSERT(la);
1674	switch (proto) {
1675	case IPPROTO_UDP:
1676		link_type = LINK_UDP;
1677		break;
1678	case IPPROTO_TCP:
1679		link_type = LINK_TCP;
1680		break;
1681	default:
1682		return (NULL);
1683		break;
1684	}
1685
1686	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1687
1688	if (lnk == NULL) {
1689		struct in_addr alias_addr;
1690
1691		alias_addr = FindAliasAddress(la, src_addr);
1692		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1693		    src_port, 0, alias_port,
1694		    link_type);
1695	}
1696	return (lnk);
1697}
1698
1699
1700struct in_addr
1701FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1702{
1703	struct alias_link *lnk;
1704
1705	LIBALIAS_LOCK_ASSERT(la);
1706	lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1707	    0, 0, LINK_ADDR, 0);
1708	if (lnk == NULL) {
1709		la->newDefaultLink = 1;
1710		if (la->targetAddress.s_addr == INADDR_ANY)
1711			return (alias_addr);
1712		else if (la->targetAddress.s_addr == INADDR_NONE)
1713			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1714			    la->aliasAddress : alias_addr;
1715		else
1716			return (la->targetAddress);
1717	} else {
1718		if (lnk->server != NULL) {	/* LSNAT link */
1719			struct in_addr src_addr;
1720
1721			src_addr = lnk->server->addr;
1722			lnk->server = lnk->server->next;
1723			return (src_addr);
1724		} else if (lnk->src_addr.s_addr == INADDR_ANY)
1725			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1726			    la->aliasAddress : alias_addr;
1727		else
1728			return (lnk->src_addr);
1729	}
1730}
1731
1732
1733struct in_addr
1734FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1735{
1736	struct alias_link *lnk;
1737
1738	LIBALIAS_LOCK_ASSERT(la);
1739	lnk = FindLinkOut(la, original_addr, la->nullAddress,
1740	    0, 0, LINK_ADDR, 0);
1741	if (lnk == NULL) {
1742		return (la->aliasAddress.s_addr != INADDR_ANY) ?
1743		    la->aliasAddress : original_addr;
1744	} else {
1745		if (lnk->alias_addr.s_addr == INADDR_ANY)
1746			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1747			    la->aliasAddress : original_addr;
1748		else
1749			return (lnk->alias_addr);
1750	}
1751}
1752
1753
1754/* External routines for getting or changing link data
1755   (external to alias_db.c, but internal to alias*.c)
1756
1757    SetFragmentData(), GetFragmentData()
1758    SetFragmentPtr(), GetFragmentPtr()
1759    SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1760    GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1761    GetOriginalPort(), GetAliasPort()
1762    SetAckModified(), GetAckModified()
1763    GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1764    SetProtocolFlags(), GetProtocolFlags()
1765    SetDestCallId()
1766*/
1767
1768
1769void
1770SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1771{
1772	lnk->data.frag_addr = src_addr;
1773}
1774
1775
1776void
1777GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1778{
1779	*src_addr = lnk->data.frag_addr;
1780}
1781
1782
1783void
1784SetFragmentPtr(struct alias_link *lnk, char *fptr)
1785{
1786	lnk->data.frag_ptr = fptr;
1787}
1788
1789
1790void
1791GetFragmentPtr(struct alias_link *lnk, char **fptr)
1792{
1793	*fptr = lnk->data.frag_ptr;
1794}
1795
1796
1797void
1798SetStateIn(struct alias_link *lnk, int state)
1799{
1800	/* TCP input state */
1801	switch (state) {
1802		case ALIAS_TCP_STATE_DISCONNECTED:
1803		if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1804			lnk->expire_time = TCP_EXPIRE_DEAD;
1805		else
1806			lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1807		break;
1808	case ALIAS_TCP_STATE_CONNECTED:
1809		if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1810			lnk->expire_time = TCP_EXPIRE_CONNECTED;
1811		break;
1812	default:
1813#ifdef	_KERNEL
1814		panic("libalias:SetStateIn() unknown state");
1815#else
1816		abort();
1817#endif
1818	}
1819	lnk->data.tcp->state.in = state;
1820}
1821
1822
1823void
1824SetStateOut(struct alias_link *lnk, int state)
1825{
1826	/* TCP output state */
1827	switch (state) {
1828		case ALIAS_TCP_STATE_DISCONNECTED:
1829		if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1830			lnk->expire_time = TCP_EXPIRE_DEAD;
1831		else
1832			lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1833		break;
1834	case ALIAS_TCP_STATE_CONNECTED:
1835		if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1836			lnk->expire_time = TCP_EXPIRE_CONNECTED;
1837		break;
1838	default:
1839#ifdef	_KERNEL
1840		panic("libalias:SetStateOut() unknown state");
1841#else
1842		abort();
1843#endif
1844	}
1845	lnk->data.tcp->state.out = state;
1846}
1847
1848
1849int
1850GetStateIn(struct alias_link *lnk)
1851{
1852	/* TCP input state */
1853	return (lnk->data.tcp->state.in);
1854}
1855
1856
1857int
1858GetStateOut(struct alias_link *lnk)
1859{
1860	/* TCP output state */
1861	return (lnk->data.tcp->state.out);
1862}
1863
1864
1865struct in_addr
1866GetOriginalAddress(struct alias_link *lnk)
1867{
1868	if (lnk->src_addr.s_addr == INADDR_ANY)
1869		return (lnk->la->aliasAddress);
1870	else
1871		return (lnk->src_addr);
1872}
1873
1874
1875struct in_addr
1876GetDestAddress(struct alias_link *lnk)
1877{
1878	return (lnk->dst_addr);
1879}
1880
1881
1882struct in_addr
1883GetAliasAddress(struct alias_link *lnk)
1884{
1885	if (lnk->alias_addr.s_addr == INADDR_ANY)
1886		return (lnk->la->aliasAddress);
1887	else
1888		return (lnk->alias_addr);
1889}
1890
1891
1892struct in_addr
1893GetDefaultAliasAddress(struct libalias *la)
1894{
1895
1896	LIBALIAS_LOCK_ASSERT(la);
1897	return (la->aliasAddress);
1898}
1899
1900
1901void
1902SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1903{
1904
1905	LIBALIAS_LOCK_ASSERT(la);
1906	la->aliasAddress = alias_addr;
1907}
1908
1909
1910u_short
1911GetOriginalPort(struct alias_link *lnk)
1912{
1913	return (lnk->src_port);
1914}
1915
1916
1917u_short
1918GetAliasPort(struct alias_link *lnk)
1919{
1920	return (lnk->alias_port);
1921}
1922
1923#ifndef NO_FW_PUNCH
1924static		u_short
1925GetDestPort(struct alias_link *lnk)
1926{
1927	return (lnk->dst_port);
1928}
1929
1930#endif
1931
1932void
1933SetAckModified(struct alias_link *lnk)
1934{
1935/* Indicate that ACK numbers have been modified in a TCP connection */
1936	lnk->data.tcp->state.ack_modified = 1;
1937}
1938
1939
1940struct in_addr
1941GetProxyAddress(struct alias_link *lnk)
1942{
1943	return (lnk->proxy_addr);
1944}
1945
1946
1947void
1948SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1949{
1950	lnk->proxy_addr = addr;
1951}
1952
1953
1954u_short
1955GetProxyPort(struct alias_link *lnk)
1956{
1957	return (lnk->proxy_port);
1958}
1959
1960
1961void
1962SetProxyPort(struct alias_link *lnk, u_short port)
1963{
1964	lnk->proxy_port = port;
1965}
1966
1967
1968int
1969GetAckModified(struct alias_link *lnk)
1970{
1971/* See if ACK numbers have been modified */
1972	return (lnk->data.tcp->state.ack_modified);
1973}
1974
1975// XXX ip free
1976int
1977GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1978{
1979/*
1980Find out how much the ACK number has been altered for an incoming
1981TCP packet.  To do this, a circular list of ACK numbers where the TCP
1982packet size was altered is searched.
1983*/
1984
1985	int i;
1986	int delta, ack_diff_min;
1987
1988	delta = 0;
1989	ack_diff_min = -1;
1990	for (i = 0; i < N_LINK_TCP_DATA; i++) {
1991		struct ack_data_record x;
1992
1993		x = lnk->data.tcp->ack[i];
1994		if (x.active == 1) {
1995			int ack_diff;
1996
1997			ack_diff = SeqDiff(x.ack_new, ack);
1998			if (ack_diff >= 0) {
1999				if (ack_diff_min >= 0) {
2000					if (ack_diff < ack_diff_min) {
2001						delta = x.delta;
2002						ack_diff_min = ack_diff;
2003					}
2004				} else {
2005					delta = x.delta;
2006					ack_diff_min = ack_diff;
2007				}
2008			}
2009		}
2010	}
2011	return (delta);
2012}
2013
2014// XXX ip free
2015int
2016GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
2017{
2018/*
2019Find out how much the sequence number has been altered for an outgoing
2020TCP packet.  To do this, a circular list of ACK numbers where the TCP
2021packet size was altered is searched.
2022*/
2023
2024	int i;
2025	int delta, seq_diff_min;
2026
2027	delta = 0;
2028	seq_diff_min = -1;
2029	for (i = 0; i < N_LINK_TCP_DATA; i++) {
2030		struct ack_data_record x;
2031
2032		x = lnk->data.tcp->ack[i];
2033		if (x.active == 1) {
2034			int seq_diff;
2035
2036			seq_diff = SeqDiff(x.ack_old, seq);
2037			if (seq_diff >= 0) {
2038				if (seq_diff_min >= 0) {
2039					if (seq_diff < seq_diff_min) {
2040						delta = x.delta;
2041						seq_diff_min = seq_diff;
2042					}
2043				} else {
2044					delta = x.delta;
2045					seq_diff_min = seq_diff;
2046				}
2047			}
2048		}
2049	}
2050	return (delta);
2051}
2052
2053// XXX ip free
2054void
2055AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
2056    u_long th_seq, u_int th_off)
2057{
2058/*
2059When a TCP packet has been altered in length, save this
2060information in a circular list.  If enough packets have
2061been altered, then this list will begin to overwrite itself.
2062*/
2063
2064	struct ack_data_record x;
2065	int hlen, tlen, dlen;
2066	int i;
2067
2068	hlen = (ip_hl + th_off) << 2;
2069	tlen = ntohs(ip_len);
2070	dlen = tlen - hlen;
2071
2072	x.ack_old = htonl(ntohl(th_seq) + dlen);
2073	x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
2074	x.delta = delta;
2075	x.active = 1;
2076
2077	i = lnk->data.tcp->state.index;
2078	lnk->data.tcp->ack[i] = x;
2079
2080	i++;
2081	if (i == N_LINK_TCP_DATA)
2082		lnk->data.tcp->state.index = 0;
2083	else
2084		lnk->data.tcp->state.index = i;
2085}
2086
2087void
2088SetExpire(struct alias_link *lnk, int expire)
2089{
2090	if (expire == 0) {
2091		lnk->flags &= ~LINK_PERMANENT;
2092		DeleteLink(lnk);
2093	} else if (expire == -1) {
2094		lnk->flags |= LINK_PERMANENT;
2095	} else if (expire > 0) {
2096		lnk->expire_time = expire;
2097	} else {
2098#ifdef LIBALIAS_DEBUG
2099		fprintf(stderr, "PacketAlias/SetExpire(): ");
2100		fprintf(stderr, "error in expire parameter\n");
2101#endif
2102	}
2103}
2104
2105void
2106ClearCheckNewLink(struct libalias *la)
2107{
2108
2109	LIBALIAS_LOCK_ASSERT(la);
2110	la->newDefaultLink = 0;
2111}
2112
2113void
2114SetProtocolFlags(struct alias_link *lnk, int pflags)
2115{
2116
2117	lnk->pflags = pflags;;
2118}
2119
2120int
2121GetProtocolFlags(struct alias_link *lnk)
2122{
2123
2124	return (lnk->pflags);
2125}
2126
2127void
2128SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2129{
2130	struct libalias *la = lnk->la;
2131
2132	LIBALIAS_LOCK_ASSERT(la);
2133	la->deleteAllLinks = 1;
2134	ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2135	    lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2136	la->deleteAllLinks = 0;
2137}
2138
2139
2140/* Miscellaneous Functions
2141
2142    HouseKeeping()
2143    InitPacketAliasLog()
2144    UninitPacketAliasLog()
2145*/
2146
2147/*
2148    Whenever an outgoing or incoming packet is handled, HouseKeeping()
2149    is called to find and remove timed-out aliasing links.  Logic exists
2150    to sweep through the entire table and linked list structure
2151    every 60 seconds.
2152
2153    (prototype in alias_local.h)
2154*/
2155
2156void
2157HouseKeeping(struct libalias *la)
2158{
2159	int i, n;
2160#ifndef	_KERNEL
2161	struct timeval tv;
2162	struct timezone tz;
2163#endif
2164
2165	LIBALIAS_LOCK_ASSERT(la);
2166	/*
2167	 * Save system time (seconds) in global variable timeStamp for use
2168	 * by other functions. This is done so as not to unnecessarily
2169	 * waste timeline by making system calls.
2170	 */
2171#ifdef	_KERNEL
2172	la->timeStamp = time_uptime;
2173#else
2174	gettimeofday(&tv, &tz);
2175	la->timeStamp = tv.tv_sec;
2176#endif
2177
2178	/* Compute number of spokes (output table link chains) to cover */
2179	n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2180	n /= ALIAS_CLEANUP_INTERVAL_SECS;
2181
2182	/* Handle different cases */
2183	if (n > 0) {
2184		if (n > ALIAS_CLEANUP_MAX_SPOKES)
2185			n = ALIAS_CLEANUP_MAX_SPOKES;
2186		la->lastCleanupTime = la->timeStamp;
2187		for (i = 0; i < n; i++)
2188			IncrementalCleanup(la);
2189	} else if (n < 0) {
2190#ifdef LIBALIAS_DEBUG
2191		fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2192		fprintf(stderr, "something unexpected in time values\n");
2193#endif
2194		la->lastCleanupTime = la->timeStamp;
2195	}
2196}
2197
2198/* Init the log file and enable logging */
2199static int
2200InitPacketAliasLog(struct libalias *la)
2201{
2202
2203	LIBALIAS_LOCK_ASSERT(la);
2204	if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2205#ifdef _KERNEL
2206		if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2207			;
2208#else
2209		if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2210			fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2211#endif
2212		else
2213			return (ENOMEM); /* log initialization failed */
2214		la->packetAliasMode |= PKT_ALIAS_LOG;
2215	}
2216
2217	return (1);
2218}
2219
2220/* Close the log-file and disable logging. */
2221static void
2222UninitPacketAliasLog(struct libalias *la)
2223{
2224
2225	LIBALIAS_LOCK_ASSERT(la);
2226	if (la->logDesc) {
2227#ifdef _KERNEL
2228		free(la->logDesc);
2229#else
2230		fclose(la->logDesc);
2231#endif
2232		la->logDesc = NULL;
2233	}
2234	la->packetAliasMode &= ~PKT_ALIAS_LOG;
2235}
2236
2237/* Outside world interfaces
2238
2239-- "outside world" means other than alias*.c routines --
2240
2241    PacketAliasRedirectPort()
2242    PacketAliasAddServer()
2243    PacketAliasRedirectProto()
2244    PacketAliasRedirectAddr()
2245    PacketAliasRedirectDynamic()
2246    PacketAliasRedirectDelete()
2247    PacketAliasSetAddress()
2248    PacketAliasInit()
2249    PacketAliasUninit()
2250    PacketAliasSetMode()
2251
2252(prototypes in alias.h)
2253*/
2254
2255/* Redirection from a specific public addr:port to a
2256   private addr:port */
2257struct alias_link *
2258LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2259    struct in_addr dst_addr, u_short dst_port,
2260    struct in_addr alias_addr, u_short alias_port,
2261    u_char proto)
2262{
2263	int link_type;
2264	struct alias_link *lnk;
2265
2266	LIBALIAS_LOCK(la);
2267	switch (proto) {
2268	case IPPROTO_UDP:
2269		link_type = LINK_UDP;
2270		break;
2271	case IPPROTO_TCP:
2272		link_type = LINK_TCP;
2273		break;
2274	default:
2275#ifdef LIBALIAS_DEBUG
2276		fprintf(stderr, "PacketAliasRedirectPort(): ");
2277		fprintf(stderr, "only TCP and UDP protocols allowed\n");
2278#endif
2279		lnk = NULL;
2280		goto getout;
2281	}
2282
2283	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2284	    src_port, dst_port, alias_port,
2285	    link_type);
2286
2287	if (lnk != NULL) {
2288		lnk->flags |= LINK_PERMANENT;
2289	}
2290#ifdef LIBALIAS_DEBUG
2291	else {
2292		fprintf(stderr, "PacketAliasRedirectPort(): "
2293		    "call to AddLink() failed\n");
2294	}
2295#endif
2296
2297getout:
2298	LIBALIAS_UNLOCK(la);
2299	return (lnk);
2300}
2301
2302/* Add server to the pool of servers */
2303int
2304LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2305{
2306	struct server *server;
2307	int res;
2308
2309	LIBALIAS_LOCK(la);
2310	(void)la;
2311
2312	server = malloc(sizeof(struct server));
2313
2314	if (server != NULL) {
2315		struct server *head;
2316
2317		server->addr = addr;
2318		server->port = port;
2319
2320		head = lnk->server;
2321		if (head == NULL)
2322			server->next = server;
2323		else {
2324			struct server *s;
2325
2326			for (s = head; s->next != head; s = s->next);
2327			s->next = server;
2328			server->next = head;
2329		}
2330		lnk->server = server;
2331		res = 0;
2332	} else
2333		res = -1;
2334
2335	LIBALIAS_UNLOCK(la);
2336	return (res);
2337}
2338
2339/* Redirect packets of a given IP protocol from a specific
2340   public address to a private address */
2341struct alias_link *
2342LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2343    struct in_addr dst_addr,
2344    struct in_addr alias_addr,
2345    u_char proto)
2346{
2347	struct alias_link *lnk;
2348
2349	LIBALIAS_LOCK(la);
2350	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2351	    NO_SRC_PORT, NO_DEST_PORT, 0,
2352	    proto);
2353
2354	if (lnk != NULL) {
2355		lnk->flags |= LINK_PERMANENT;
2356	}
2357#ifdef LIBALIAS_DEBUG
2358	else {
2359		fprintf(stderr, "PacketAliasRedirectProto(): "
2360		    "call to AddLink() failed\n");
2361	}
2362#endif
2363
2364	LIBALIAS_UNLOCK(la);
2365	return (lnk);
2366}
2367
2368/* Static address translation */
2369struct alias_link *
2370LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2371    struct in_addr alias_addr)
2372{
2373	struct alias_link *lnk;
2374
2375	LIBALIAS_LOCK(la);
2376	lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2377	    0, 0, 0,
2378	    LINK_ADDR);
2379
2380	if (lnk != NULL) {
2381		lnk->flags |= LINK_PERMANENT;
2382	}
2383#ifdef LIBALIAS_DEBUG
2384	else {
2385		fprintf(stderr, "PacketAliasRedirectAddr(): "
2386		    "call to AddLink() failed\n");
2387	}
2388#endif
2389
2390	LIBALIAS_UNLOCK(la);
2391	return (lnk);
2392}
2393
2394
2395/* Mark the aliasing link dynamic */
2396int
2397LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2398{
2399	int res;
2400
2401	LIBALIAS_LOCK(la);
2402	(void)la;
2403
2404	if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2405		res = -1;
2406	else {
2407		lnk->flags &= ~LINK_PERMANENT;
2408		res = 0;
2409	}
2410	LIBALIAS_UNLOCK(la);
2411	return (res);
2412}
2413
2414
2415void
2416LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2417{
2418/* This is a dangerous function to put in the API,
2419   because an invalid pointer can crash the program. */
2420
2421	LIBALIAS_LOCK(la);
2422	la->deleteAllLinks = 1;
2423	DeleteLink(lnk);
2424	la->deleteAllLinks = 0;
2425	LIBALIAS_UNLOCK(la);
2426}
2427
2428
2429void
2430LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2431{
2432
2433	LIBALIAS_LOCK(la);
2434	if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2435	    && la->aliasAddress.s_addr != addr.s_addr)
2436		CleanupAliasData(la);
2437
2438	la->aliasAddress = addr;
2439	LIBALIAS_UNLOCK(la);
2440}
2441
2442
2443void
2444LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2445{
2446
2447	LIBALIAS_LOCK(la);
2448	la->targetAddress = target_addr;
2449	LIBALIAS_UNLOCK(la);
2450}
2451
2452static void
2453finishoff(void)
2454{
2455
2456	while (!LIST_EMPTY(&instancehead))
2457		LibAliasUninit(LIST_FIRST(&instancehead));
2458}
2459
2460struct libalias *
2461LibAliasInit(struct libalias *la)
2462{
2463	int i;
2464#ifndef	_KERNEL
2465	struct timeval tv;
2466	struct timezone tz;
2467#endif
2468
2469	if (la == NULL) {
2470		la = calloc(sizeof *la, 1);
2471		if (la == NULL)
2472			return (la);
2473
2474#ifndef	_KERNEL		/* kernel cleans up on module unload */
2475		if (LIST_EMPTY(&instancehead))
2476			atexit(finishoff);
2477#endif
2478		LIST_INSERT_HEAD(&instancehead, la, instancelist);
2479
2480#ifdef	_KERNEL
2481		la->timeStamp = time_uptime;
2482		la->lastCleanupTime = time_uptime;
2483#else
2484		gettimeofday(&tv, &tz);
2485		la->timeStamp = tv.tv_sec;
2486		la->lastCleanupTime = tv.tv_sec;
2487#endif
2488
2489		for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2490			LIST_INIT(&la->linkTableOut[i]);
2491		for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2492			LIST_INIT(&la->linkTableIn[i]);
2493		LIBALIAS_LOCK_INIT(la);
2494		LIBALIAS_LOCK(la);
2495	} else {
2496		LIBALIAS_LOCK(la);
2497		la->deleteAllLinks = 1;
2498		CleanupAliasData(la);
2499		la->deleteAllLinks = 0;
2500	}
2501
2502	la->aliasAddress.s_addr = INADDR_ANY;
2503	la->targetAddress.s_addr = INADDR_ANY;
2504
2505	la->icmpLinkCount = 0;
2506	la->udpLinkCount = 0;
2507	la->tcpLinkCount = 0;
2508	la->pptpLinkCount = 0;
2509	la->protoLinkCount = 0;
2510	la->fragmentIdLinkCount = 0;
2511	la->fragmentPtrLinkCount = 0;
2512	la->sockCount = 0;
2513
2514	la->cleanupIndex = 0;
2515
2516	la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2517#ifndef	NO_USE_SOCKETS
2518	    | PKT_ALIAS_USE_SOCKETS
2519#endif
2520	    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2521#ifndef NO_FW_PUNCH
2522	la->fireWallFD = -1;
2523#endif
2524#ifndef _KERNEL
2525	LibAliasRefreshModules();
2526#endif
2527	LIBALIAS_UNLOCK(la);
2528	return (la);
2529}
2530
2531void
2532LibAliasUninit(struct libalias *la)
2533{
2534
2535	LIBALIAS_LOCK(la);
2536	la->deleteAllLinks = 1;
2537	CleanupAliasData(la);
2538	la->deleteAllLinks = 0;
2539	UninitPacketAliasLog(la);
2540#ifndef NO_FW_PUNCH
2541	UninitPunchFW(la);
2542#endif
2543	LIST_REMOVE(la, instancelist);
2544	LIBALIAS_UNLOCK(la);
2545	LIBALIAS_LOCK_DESTROY(la);
2546	free(la);
2547}
2548
2549/* Change mode for some operations */
2550unsigned int
2551LibAliasSetMode(
2552    struct libalias *la,
2553    unsigned int flags,		/* Which state to bring flags to */
2554    unsigned int mask		/* Mask of which flags to affect (use 0 to
2555				 * do a probe for flag values) */
2556)
2557{
2558	int res = -1;
2559
2560	LIBALIAS_LOCK(la);
2561/* Enable logging? */
2562	if (flags & mask & PKT_ALIAS_LOG) {
2563		/* Do the enable */
2564		if (InitPacketAliasLog(la) == ENOMEM)
2565			goto getout;
2566	} else
2567/* _Disable_ logging? */
2568	if (~flags & mask & PKT_ALIAS_LOG) {
2569		UninitPacketAliasLog(la);
2570	}
2571#ifndef NO_FW_PUNCH
2572/* Start punching holes in the firewall? */
2573	if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2574		InitPunchFW(la);
2575	} else
2576/* Stop punching holes in the firewall? */
2577	if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2578		UninitPunchFW(la);
2579	}
2580#endif
2581
2582/* Other flags can be set/cleared without special action */
2583	la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2584	res = la->packetAliasMode;
2585getout:
2586	LIBALIAS_UNLOCK(la);
2587	return (res);
2588}
2589
2590
2591int
2592LibAliasCheckNewLink(struct libalias *la)
2593{
2594	int res;
2595
2596	LIBALIAS_LOCK(la);
2597	res = la->newDefaultLink;
2598	LIBALIAS_UNLOCK(la);
2599	return (res);
2600}
2601
2602
2603#ifndef NO_FW_PUNCH
2604
2605/*****************
2606  Code to support firewall punching.  This shouldn't really be in this
2607  file, but making variables global is evil too.
2608  ****************/
2609
2610/* Firewall include files */
2611#include <net/if.h>
2612#include <netinet/ip_fw.h>
2613#include <string.h>
2614#include <err.h>
2615
2616/*
2617 * helper function, updates the pointer to cmd with the length
2618 * of the current command, and also cleans up the first word of
2619 * the new command in case it has been clobbered before.
2620 */
2621static ipfw_insn *
2622next_cmd(ipfw_insn * cmd)
2623{
2624	cmd += F_LEN(cmd);
2625	bzero(cmd, sizeof(*cmd));
2626	return (cmd);
2627}
2628
2629/*
2630 * A function to fill simple commands of size 1.
2631 * Existing flags are preserved.
2632 */
2633static ipfw_insn *
2634fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2635    int flags, u_int16_t arg)
2636{
2637	cmd->opcode = opcode;
2638	cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2639	cmd->arg1 = arg;
2640	return next_cmd(cmd);
2641}
2642
2643static ipfw_insn *
2644fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2645{
2646	ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2647
2648	cmd->addr.s_addr = addr;
2649	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2650}
2651
2652static ipfw_insn *
2653fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2654{
2655	ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2656
2657	cmd->ports[0] = cmd->ports[1] = port;
2658	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2659}
2660
2661static int
2662fill_rule(void *buf, int bufsize, int rulenum,
2663    enum ipfw_opcodes action, int proto,
2664    struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2665{
2666	struct ip_fw *rule = (struct ip_fw *)buf;
2667	ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2668
2669	bzero(buf, bufsize);
2670	rule->rulenum = rulenum;
2671
2672	cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2673	cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2674	cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2675	cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2676	cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2677
2678	rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2679	cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2680
2681	rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2682
2683	return ((char *)cmd - (char *)buf);
2684}
2685
2686static void	ClearAllFWHoles(struct libalias *la);
2687
2688
2689#define fw_setfield(la, field, num)                         \
2690do {                                                    \
2691    (field)[(num) - la->fireWallBaseNum] = 1;               \
2692} /*lint -save -e717 */ while(0)/* lint -restore */
2693
2694#define fw_clrfield(la, field, num)                         \
2695do {                                                    \
2696    (field)[(num) - la->fireWallBaseNum] = 0;               \
2697} /*lint -save -e717 */ while(0)/* lint -restore */
2698
2699#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2700
2701static void
2702InitPunchFW(struct libalias *la)
2703{
2704
2705	LIBALIAS_LOCK_ASSERT(la);
2706	la->fireWallField = malloc(la->fireWallNumNums);
2707	if (la->fireWallField) {
2708		memset(la->fireWallField, 0, la->fireWallNumNums);
2709		if (la->fireWallFD < 0) {
2710			la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2711		}
2712		ClearAllFWHoles(la);
2713		la->fireWallActiveNum = la->fireWallBaseNum;
2714	}
2715}
2716
2717static void
2718UninitPunchFW(struct libalias *la)
2719{
2720
2721	LIBALIAS_LOCK_ASSERT(la);
2722	ClearAllFWHoles(la);
2723	if (la->fireWallFD >= 0)
2724		close(la->fireWallFD);
2725	la->fireWallFD = -1;
2726	if (la->fireWallField)
2727		free(la->fireWallField);
2728	la->fireWallField = NULL;
2729	la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2730}
2731
2732/* Make a certain link go through the firewall */
2733void
2734PunchFWHole(struct alias_link *lnk)
2735{
2736	struct libalias *la;
2737	int r;			/* Result code */
2738	struct ip_fw rule;	/* On-the-fly built rule */
2739	int fwhole;		/* Where to punch hole */
2740
2741	LIBALIAS_LOCK_ASSERT(la);
2742	la = lnk->la;
2743
2744/* Don't do anything unless we are asked to */
2745	if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2746	    la->fireWallFD < 0 ||
2747	    lnk->link_type != LINK_TCP)
2748		return;
2749
2750	memset(&rule, 0, sizeof rule);
2751
2752/** Build rule **/
2753
2754	/* Find empty slot */
2755	for (fwhole = la->fireWallActiveNum;
2756	    fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2757	    fw_tstfield(la, la->fireWallField, fwhole);
2758	    fwhole++);
2759	if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2760		for (fwhole = la->fireWallBaseNum;
2761		    fwhole < la->fireWallActiveNum &&
2762		    fw_tstfield(la, la->fireWallField, fwhole);
2763		    fwhole++);
2764		if (fwhole == la->fireWallActiveNum) {
2765			/* No rule point empty - we can't punch more holes. */
2766			la->fireWallActiveNum = la->fireWallBaseNum;
2767#ifdef LIBALIAS_DEBUG
2768			fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2769#endif
2770			return;
2771		}
2772	}
2773	/* Start next search at next position */
2774	la->fireWallActiveNum = fwhole + 1;
2775
2776	/*
2777	 * generate two rules of the form
2778	 *
2779	 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2780	 * accept tcp from DAddr DPort to OAddr OPort
2781	 */
2782	if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2783		u_int32_t rulebuf[255];
2784		int i;
2785
2786		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2787		    O_ACCEPT, IPPROTO_TCP,
2788		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2789		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2790		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2791		if (r)
2792			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2793
2794		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2795		    O_ACCEPT, IPPROTO_TCP,
2796		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2797		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2798		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2799		if (r)
2800			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2801	}
2802
2803/* Indicate hole applied */
2804	lnk->data.tcp->fwhole = fwhole;
2805	fw_setfield(la, la->fireWallField, fwhole);
2806}
2807
2808/* Remove a hole in a firewall associated with a particular alias
2809   lnk.  Calling this too often is harmless. */
2810static void
2811ClearFWHole(struct alias_link *lnk)
2812{
2813	struct libalias *la;
2814
2815	LIBALIAS_LOCK_ASSERT(la);
2816	la = lnk->la;
2817	if (lnk->link_type == LINK_TCP) {
2818		int fwhole = lnk->data.tcp->fwhole;	/* Where is the firewall
2819							 * hole? */
2820		struct ip_fw rule;
2821
2822		if (fwhole < 0)
2823			return;
2824
2825		memset(&rule, 0, sizeof rule);	/* useless for ipfw2 */
2826		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2827		    &fwhole, sizeof fwhole));
2828		fw_clrfield(la, la->fireWallField, fwhole);
2829		lnk->data.tcp->fwhole = -1;
2830	}
2831}
2832
2833/* Clear out the entire range dedicated to firewall holes. */
2834static void
2835ClearAllFWHoles(struct libalias *la)
2836{
2837	struct ip_fw rule;	/* On-the-fly built rule */
2838	int i;
2839
2840	LIBALIAS_LOCK_ASSERT(la);
2841	if (la->fireWallFD < 0)
2842		return;
2843
2844	memset(&rule, 0, sizeof rule);
2845	for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2846		int r = i;
2847
2848		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2849	}
2850	/* XXX: third arg correct here ? /phk */
2851	memset(la->fireWallField, 0, la->fireWallNumNums);
2852}
2853
2854#endif
2855
2856void
2857LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2858{
2859
2860	LIBALIAS_LOCK(la);
2861#ifndef NO_FW_PUNCH
2862	la->fireWallBaseNum = base;
2863	la->fireWallNumNums = num;
2864#endif
2865	LIBALIAS_UNLOCK(la);
2866}
2867
2868void
2869LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2870{
2871
2872	LIBALIAS_LOCK(la);
2873	la->skinnyPort = port;
2874	LIBALIAS_UNLOCK(la);
2875}
2876