1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32/*
33    Alias_db.c encapsulates all data structures used for storing
34    packet aliasing data.  Other parts of the aliasing software
35    access data through functions provided in this file.
36
37    Data storage is based on the notion of a "link", which is
38    established for ICMP echo/reply packets, UDP datagrams and
39    TCP stream connections.  A link stores the original source
40    and destination addresses.  For UDP and TCP, it also stores
41    source and destination port numbers, as well as an alias
42    port number.  Links are also used to store information about
43    fragments.
44
45    There is a facility for sweeping through and deleting old
46    links as new packets are sent through.  A simple timeout is
47    used for ICMP and UDP links.  TCP links are left alone unless
48    there is an incomplete connection, in which case the link
49    can be deleted after a certain amount of time.
50
51    Initial version: August, 1996  (cjm)
52
53    Version 1.4: September 16, 1996 (cjm)
54	Facility for handling incoming links added.
55
56    Version 1.6: September 18, 1996 (cjm)
57	ICMP data handling simplified.
58
59    Version 1.7: January 9, 1997 (cjm)
60	Fragment handling simplified.
61	Saves pointers for unresolved fragments.
62	Permits links for unspecified remote ports
63	  or unspecified remote addresses.
64	Fixed bug which did not properly zero port
65	  table entries after a link was deleted.
66	Cleaned up some obsolete comments.
67
68    Version 1.8: January 14, 1997 (cjm)
69	Fixed data type error in StartPoint().
70	(This error did not exist prior to v1.7
71	and was discovered and fixed by Ari Suutari)
72
73    Version 1.9: February 1, 1997
74	Optionally, connections initiated from packet aliasing host
75	machine will will not have their port number aliased unless it
76	conflicts with an aliasing port already being used. (cjm)
77
78	All options earlier being #ifdef'ed are now available through
79	a new interface, SetPacketAliasMode().  This allows run time
80	control (which is now available in PPP+pktAlias through the
81	'alias' keyword). (ee)
82
83	Added ability to create an alias port without
84	either destination address or port specified.
85	port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
86
87	Removed K&R style function headers
88	and general cleanup. (ee)
89
90	Added packetAliasMode to replace compiler #defines's (ee)
91
92	Allocates sockets for partially specified
93	ports if ALIAS_USE_SOCKETS defined. (cjm)
94
95    Version 2.0: March, 1997
96	SetAliasAddress() will now clean up alias links
97	if the aliasing address is changed. (cjm)
98
99	PacketAliasPermanentLink() function added to support permanent
100	links.  (J. Fortes suggested the need for this.)
101	Examples:
102
103	(192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
104
105	(192.168.0.2, port 21)  <-> alias port 3604, known dest addr
106						     unknown dest port
107
108	These permanent links allow for incoming connections to
109	machines on the local network.  They can be given with a
110	user-chosen amount of specificity, with increasing specificity
111	meaning more security. (cjm)
112
113	Quite a bit of rework to the basic engine.  The portTable[]
114	array, which kept track of which ports were in use was replaced
115	by a table/linked list structure. (cjm)
116
117	SetExpire() function added. (cjm)
118
119	DeleteLink() no longer frees memory association with a pointer
120	to a fragment (this bug was first recognized by E. Eklund in
121	v1.9).
122
123    Version 2.1: May, 1997 (cjm)
124	Packet aliasing engine reworked so that it can handle
125	multiple external addresses rather than just a single
126	host address.
127
128	PacketAliasRedirectPort() and PacketAliasRedirectAddr()
129	added to the API.  The first function is a more generalized
130	version of PacketAliasPermanentLink().  The second function
131	implements static network address translation.
132
133    Version 3.2: July, 2000 (salander and satoh)
134	Added FindNewPortGroup to get contiguous range of port values.
135
136	Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
137	link but not actually add one.
138
139	Added FindRtspOut, which is closely derived from FindUdpTcpOut,
140	except that the alias port (from FindNewPortGroup) is provided
141	as input.
142
143    See HISTORY file for additional revisions.
144*/
145
146#ifdef _KERNEL
147#include <machine/stdarg.h>
148#include <sys/param.h>
149#include <sys/kernel.h>
150#include <sys/systm.h>
151#include <sys/lock.h>
152#include <sys/module.h>
153#include <sys/rwlock.h>
154#include <sys/syslog.h>
155#else
156#include <stdarg.h>
157#include <stdlib.h>
158#include <stdio.h>
159#include <sys/errno.h>
160#include <sys/time.h>
161#include <unistd.h>
162#endif
163
164#include <sys/socket.h>
165#include <netinet/tcp.h>
166
167#ifdef _KERNEL
168#include <netinet/libalias/alias.h>
169#include <netinet/libalias/alias_local.h>
170#include <netinet/libalias/alias_mod.h>
171#include <net/if.h>
172#else
173#include "alias.h"
174#include "alias_local.h"
175#include "alias_mod.h"
176#endif
177
178static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
179
180/*
181   Constants (note: constants are also defined
182	      near relevant functions or structs)
183*/
184
185/* Parameters used for cleanup of expired links */
186/* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
187#define ALIAS_CLEANUP_INTERVAL_SECS  64
188#define ALIAS_CLEANUP_MAX_SPOKES     (LINK_TABLE_OUT_SIZE/5)
189
190/* Timeouts (in seconds) for different link types */
191#define ICMP_EXPIRE_TIME             60
192#define UDP_EXPIRE_TIME              60
193#define PROTO_EXPIRE_TIME            60
194#define FRAGMENT_ID_EXPIRE_TIME      10
195#define FRAGMENT_PTR_EXPIRE_TIME     30
196
197/* TCP link expire time for different cases */
198/* When the link has been used and closed - minimal grace time to
199   allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
200#ifndef TCP_EXPIRE_DEAD
201#define TCP_EXPIRE_DEAD           10
202#endif
203
204/* When the link has been used and closed on one side - the other side
205   is allowed to still send data */
206#ifndef TCP_EXPIRE_SINGLEDEAD
207#define TCP_EXPIRE_SINGLEDEAD     90
208#endif
209
210/* When the link isn't yet up */
211#ifndef TCP_EXPIRE_INITIAL
212#define TCP_EXPIRE_INITIAL       300
213#endif
214
215/* When the link is up */
216#ifndef TCP_EXPIRE_CONNECTED
217#define TCP_EXPIRE_CONNECTED   86400
218#endif
219
220/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
221   These constants can be anything except zero, which indicates an
222   unknown port number. */
223
224#define NO_DEST_PORT     1
225#define NO_SRC_PORT      1
226
227/* Matches any/unknown address in FindLinkIn/Out() and AddLink(). */
228static struct in_addr const ANY_ADDR = { INADDR_ANY };
229
230/* Data Structures
231
232    The fundamental data structure used in this program is
233    "struct alias_link".  Whenever a TCP connection is made,
234    a UDP datagram is sent out, or an ICMP echo request is made,
235    a link record is made (if it has not already been created).
236    The link record is identified by the source address/port
237    and the destination address/port. In the case of an ICMP
238    echo request, the source port is treated as being equivalent
239    with the 16-bit ID number of the ICMP packet.
240
241    The link record also can store some auxiliary data.  For
242    TCP connections that have had sequence and acknowledgment
243    modifications, data space is available to track these changes.
244    A state field is used to keep track in changes to the TCP
245    connection state.  ID numbers of fragments can also be
246    stored in the auxiliary space.  Pointers to unresolved
247    fragments can also be stored.
248
249    The link records support two independent chainings.  Lookup
250    tables for input and out tables hold the initial pointers
251    the link chains.  On input, the lookup table indexes on alias
252    port and link type.  On output, the lookup table indexes on
253    source address, destination address, source port, destination
254    port and link type.
255*/
256
257/* used to save changes to ACK/sequence numbers */
258struct ack_data_record {
259	u_long		ack_old;
260	u_long		ack_new;
261	int		delta;
262	int		active;
263};
264
265/* Information about TCP connection */
266struct tcp_state {
267	int		in;	/* State for outside -> inside */
268	int		out;	/* State for inside  -> outside */
269	int		index;	/* Index to ACK data array */
270	/* Indicates whether ACK and sequence numbers been modified */
271	int		ack_modified;
272};
273
274/* Number of distinct ACK number changes
275 * saved for a modified TCP stream */
276#define N_LINK_TCP_DATA   3
277struct tcp_dat {
278	struct tcp_state state;
279	struct ack_data_record ack[N_LINK_TCP_DATA];
280	/* Which firewall record is used for this hole? */
281	int		fwhole;
282};
283
284/* LSNAT server pool (circular list) */
285struct server {
286	struct in_addr	addr;
287	u_short		port;
288	struct server  *next;
289};
290
291/* Main data structure */
292struct alias_link {
293	struct libalias *la;
294	/* Address and port information */
295	struct in_addr	src_addr;
296	struct in_addr	dst_addr;
297	struct in_addr	alias_addr;
298	struct in_addr	proxy_addr;
299	u_short		src_port;
300	u_short		dst_port;
301	u_short		alias_port;
302	u_short		proxy_port;
303	struct server  *server;
304	/* Type of link: TCP, UDP, ICMP, proto, frag */
305	int		link_type;
306/* values for link_type */
307#define LINK_ICMP                     IPPROTO_ICMP
308#define LINK_UDP                      IPPROTO_UDP
309#define LINK_TCP                      IPPROTO_TCP
310#define LINK_FRAGMENT_ID              (IPPROTO_MAX + 1)
311#define LINK_FRAGMENT_PTR             (IPPROTO_MAX + 2)
312#define LINK_ADDR                     (IPPROTO_MAX + 3)
313#define LINK_PPTP                     (IPPROTO_MAX + 4)
314
315	int		flags;	/* indicates special characteristics */
316	int		pflags;	/* protocol-specific flags */
317/* flag bits */
318#define LINK_UNKNOWN_DEST_PORT     0x01
319#define LINK_UNKNOWN_DEST_ADDR     0x02
320#define LINK_PERMANENT             0x04
321#define LINK_PARTIALLY_SPECIFIED   0x03	/* logical-or of first two bits */
322#define LINK_UNFIREWALLED          0x08
323
324	int		timestamp;	/* Time link was last accessed */
325	int		expire_time;	/* Expire time for link */
326#ifndef NO_USE_SOCKETS
327	int		sockfd;		/* socket descriptor */
328#endif
329	/* Linked list of pointers for input and output lookup tables  */
330	LIST_ENTRY    (alias_link) list_out;
331	LIST_ENTRY    (alias_link) list_in;
332	/* Auxiliary data */
333	union {
334		char           *frag_ptr;
335		struct in_addr	frag_addr;
336		struct tcp_dat *tcp;
337	} data;
338};
339
340/* Clean up procedure. */
341static void finishoff(void);
342
343/* Kernel module definition. */
344#ifdef _KERNEL
345MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
346
347MODULE_VERSION(libalias, 1);
348
349static int
350alias_mod_handler(module_t mod, int type, void *data)
351{
352	switch (type) {
353	case MOD_QUIESCE:
354	case MOD_UNLOAD:
355		finishoff();
356	case MOD_LOAD:
357		return (0);
358	default:
359		return (EINVAL);
360	}
361}
362
363static moduledata_t alias_mod = {
364       "alias", alias_mod_handler, NULL
365};
366
367DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
368#endif
369
370/* Internal utility routines (used only in alias_db.c)
371
372Lookup table starting points:
373    StartPointIn()           -- link table initial search point for
374				incoming packets
375    StartPointOut()          -- link table initial search point for
376				outgoing packets
377
378Miscellaneous:
379    SeqDiff()                -- difference between two TCP sequences
380    ShowAliasStats()         -- send alias statistics to a monitor file
381*/
382
383/* Local prototypes */
384static u_int	StartPointIn(struct in_addr, u_short, int);
385
386static		u_int
387StartPointOut(struct in_addr, struct in_addr,
388    u_short, u_short, int);
389
390static int	SeqDiff(u_long, u_long);
391
392#ifndef NO_FW_PUNCH
393/* Firewall control */
394static void	InitPunchFW(struct libalias *);
395static void	UninitPunchFW(struct libalias *);
396static void	ClearFWHole(struct alias_link *);
397
398#endif
399
400/* Log file control */
401static void	ShowAliasStats(struct libalias *);
402static int	InitPacketAliasLog(struct libalias *);
403static void	UninitPacketAliasLog(struct libalias *);
404
405void		SctpShowAliasStats(struct libalias *la);
406
407static u_int
408StartPointIn(struct in_addr alias_addr,
409    u_short alias_port,
410    int link_type)
411{
412	u_int n;
413
414	n = alias_addr.s_addr;
415	if (link_type != LINK_PPTP)
416		n += alias_port;
417	n += link_type;
418	return (n % LINK_TABLE_IN_SIZE);
419}
420
421static u_int
422StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
423    u_short src_port, u_short dst_port, int link_type)
424{
425	u_int n;
426
427	n = src_addr.s_addr;
428	n += dst_addr.s_addr;
429	if (link_type != LINK_PPTP) {
430		n += src_port;
431		n += dst_port;
432	}
433	n += link_type;
434
435	return (n % LINK_TABLE_OUT_SIZE);
436}
437
438static int
439SeqDiff(u_long x, u_long y)
440{
441/* Return the difference between two TCP sequence numbers
442 * This function is encapsulated in case there are any unusual
443 * arithmetic conditions that need to be considered.
444 */
445	return (ntohl(y) - ntohl(x));
446}
447
448#ifdef _KERNEL
449static void
450AliasLog(char *str, const char *format, ...)
451{
452	va_list ap;
453
454	va_start(ap, format);
455	vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
456	va_end(ap);
457}
458#else
459static void
460AliasLog(FILE *stream, const char *format, ...)
461{
462	va_list ap;
463
464	va_start(ap, format);
465	vfprintf(stream, format, ap);
466	va_end(ap);
467	fflush(stream);
468}
469#endif
470
471static void
472ShowAliasStats(struct libalias *la)
473{
474	LIBALIAS_LOCK_ASSERT(la);
475	/* Used for debugging */
476	if (la->logDesc) {
477		int tot  = la->icmpLinkCount + la->udpLinkCount +
478		    (la->sctpLinkCount>>1) + /* sctp counts half associations */
479		    la->tcpLinkCount + la->pptpLinkCount +
480		    la->protoLinkCount + la->fragmentIdLinkCount +
481		    la->fragmentPtrLinkCount;
482
483		AliasLog(la->logDesc,
484		    "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
485		    la->icmpLinkCount,
486		    la->udpLinkCount,
487		    la->tcpLinkCount,
488		    la->sctpLinkCount>>1, /* sctp counts half associations */
489		    la->pptpLinkCount,
490		    la->protoLinkCount,
491		    la->fragmentIdLinkCount,
492		    la->fragmentPtrLinkCount,
493		    tot);
494#ifndef _KERNEL
495		AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
496#endif
497	}
498}
499
500void SctpShowAliasStats(struct libalias *la)
501{
502	ShowAliasStats(la);
503}
504
505/* Internal routines for finding, deleting and adding links
506
507Port Allocation:
508    GetNewPort()             -- find and reserve new alias port number
509    GetSocket()              -- try to allocate a socket for a given port
510
511Link creation and deletion:
512    CleanupAliasData()      - remove all link chains from lookup table
513    IncrementalCleanup()    - look for stale links in a single chain
514    DeleteLink()            - remove link
515    AddLink()               - add link
516    ReLink()                - change link
517
518Link search:
519    FindLinkOut()           - find link for outgoing packets
520    FindLinkIn()            - find link for incoming packets
521
522Port search:
523    FindNewPortGroup()      - find an available group of ports
524*/
525
526/* Local prototypes */
527static int	GetNewPort(struct libalias *, struct alias_link *, int);
528#ifndef NO_USE_SOCKETS
529static u_short	GetSocket(struct libalias *, u_short, int *, int);
530#endif
531static void	CleanupAliasData(struct libalias *);
532static void	IncrementalCleanup(struct libalias *);
533static void	DeleteLink(struct alias_link *);
534
535static struct alias_link *
536ReLink(struct alias_link *,
537    struct in_addr, struct in_addr, struct in_addr,
538    u_short, u_short, int, int);
539
540static struct alias_link *
541FindLinkOut(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
542
543static struct alias_link *
544FindLinkIn(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
545
546#define ALIAS_PORT_BASE            0x08000
547#define ALIAS_PORT_MASK            0x07fff
548#define ALIAS_PORT_MASK_EVEN       0x07ffe
549#define GET_NEW_PORT_MAX_ATTEMPTS       20
550
551#define FIND_EVEN_ALIAS_BASE             1
552
553/* GetNewPort() allocates port numbers.  Note that if a port number
554   is already in use, that does not mean that it cannot be used by
555   another link concurrently.  This is because GetNewPort() looks for
556   unused triplets: (dest addr, dest port, alias port). */
557
558static int
559GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
560{
561	int i;
562	int max_trials;
563	u_short port_sys;
564	u_short port_net;
565
566	LIBALIAS_LOCK_ASSERT(la);
567	/*
568	 * Description of alias_port_param for GetNewPort().  When
569	 * this parameter is zero or positive, it precisely specifies
570	 * the port number.  GetNewPort() will return this number
571	 * without check that it is in use.
572
573	 * When this parameter is GET_ALIAS_PORT, it indicates to get
574	 * a randomly selected port number.
575	 */
576	if (alias_port_param == GET_ALIAS_PORT) {
577		/*
578		 * The aliasing port is automatically selected by one of
579		 * two methods below:
580		 */
581		max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
582
583		if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
584			/*
585			 * When the PKT_ALIAS_SAME_PORTS option is chosen,
586			 * the first try will be the actual source port. If
587			 * this is already in use, the remainder of the
588			 * trials will be random.
589			 */
590			port_net = lnk->src_port;
591			port_sys = ntohs(port_net);
592		} else if (la->aliasPortLower) {
593			/* First trial is a random port in the aliasing range. */
594			port_sys = la->aliasPortLower +
595			    (arc4random() % la->aliasPortLength);
596			port_net = htons(port_sys);
597		} else {
598			/* First trial and all subsequent are random. */
599			port_sys = arc4random() & ALIAS_PORT_MASK;
600			port_sys += ALIAS_PORT_BASE;
601			port_net = htons(port_sys);
602		}
603	} else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
604		lnk->alias_port = (u_short) alias_port_param;
605		return (0);
606	} else {
607#ifdef LIBALIAS_DEBUG
608		fprintf(stderr, "PacketAlias/GetNewPort(): ");
609		fprintf(stderr, "input parameter error\n");
610#endif
611		return (-1);
612	}
613
614	/* Port number search */
615	for (i = 0; i < max_trials; i++) {
616		int go_ahead;
617		struct alias_link *search_result;
618
619		search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
620		    lnk->dst_port, port_net,
621		    lnk->link_type, 0);
622
623		if (search_result == NULL)
624			go_ahead = 1;
625		else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
626		    && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
627			go_ahead = 1;
628		else
629			go_ahead = 0;
630
631		if (go_ahead) {
632#ifndef NO_USE_SOCKETS
633			if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
634			    && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
635			    && ((lnk->link_type == LINK_TCP) ||
636			    (lnk->link_type == LINK_UDP))) {
637				if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
638					lnk->alias_port = port_net;
639					return (0);
640				}
641			} else {
642#endif
643				lnk->alias_port = port_net;
644				return (0);
645#ifndef NO_USE_SOCKETS
646			}
647#endif
648		}
649		if (la->aliasPortLower) {
650			port_sys = la->aliasPortLower +
651			    (arc4random() % la->aliasPortLength);
652			port_net = htons(port_sys);
653		} else {
654			port_sys = arc4random() & ALIAS_PORT_MASK;
655			port_sys += ALIAS_PORT_BASE;
656			port_net = htons(port_sys);
657		}
658	}
659
660#ifdef LIBALIAS_DEBUG
661	fprintf(stderr, "PacketAlias/GetnewPort(): ");
662	fprintf(stderr, "could not find free port\n");
663#endif
664
665	return (-1);
666}
667
668#ifndef NO_USE_SOCKETS
669static		u_short
670GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
671{
672	int err;
673	int sock;
674	struct sockaddr_in sock_addr;
675
676	LIBALIAS_LOCK_ASSERT(la);
677	if (link_type == LINK_TCP)
678		sock = socket(AF_INET, SOCK_STREAM, 0);
679	else if (link_type == LINK_UDP)
680		sock = socket(AF_INET, SOCK_DGRAM, 0);
681	else {
682#ifdef LIBALIAS_DEBUG
683		fprintf(stderr, "PacketAlias/GetSocket(): ");
684		fprintf(stderr, "incorrect link type\n");
685#endif
686		return (0);
687	}
688
689	if (sock < 0) {
690#ifdef LIBALIAS_DEBUG
691		fprintf(stderr, "PacketAlias/GetSocket(): ");
692		fprintf(stderr, "socket() error %d\n", *sockfd);
693#endif
694		return (0);
695	}
696	sock_addr.sin_family = AF_INET;
697	sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
698	sock_addr.sin_port = port_net;
699
700	err = bind(sock,
701	    (struct sockaddr *)&sock_addr,
702	    sizeof(sock_addr));
703	if (err == 0) {
704		la->sockCount++;
705		*sockfd = sock;
706		return (1);
707	} else {
708		close(sock);
709		return (0);
710	}
711}
712#endif
713
714/* FindNewPortGroup() returns a base port number for an available
715   range of contiguous port numbers. Note that if a port number
716   is already in use, that does not mean that it cannot be used by
717   another link concurrently.  This is because FindNewPortGroup()
718   looks for unused triplets: (dest addr, dest port, alias port). */
719
720int
721FindNewPortGroup(struct libalias *la,
722    struct in_addr dst_addr,
723    struct in_addr alias_addr,
724    u_short src_port,
725    u_short dst_port,
726    u_short port_count,
727    u_char proto,
728    u_char align)
729{
730	int i, j;
731	int max_trials;
732	u_short port_sys;
733	int link_type;
734
735	LIBALIAS_LOCK_ASSERT(la);
736	/*
737	 * Get link_type from protocol
738	 */
739
740	switch (proto) {
741	case IPPROTO_UDP:
742		link_type = LINK_UDP;
743		break;
744	case IPPROTO_TCP:
745		link_type = LINK_TCP;
746		break;
747	default:
748		return (0);
749		break;
750	}
751
752	/*
753	 * The aliasing port is automatically selected by one of two
754	 * methods below:
755	 */
756	max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
757
758	if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
759		/*
760		 * When the ALIAS_SAME_PORTS option is chosen, the first
761		 * try will be the actual source port. If this is already
762		 * in use, the remainder of the trials will be random.
763		 */
764		port_sys = ntohs(src_port);
765
766	} else {
767		/* First trial and all subsequent are random. */
768		if (align == FIND_EVEN_ALIAS_BASE)
769			port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
770		else
771			port_sys = arc4random() & ALIAS_PORT_MASK;
772
773		port_sys += ALIAS_PORT_BASE;
774	}
775
776	/* Port number search */
777	for (i = 0; i < max_trials; i++) {
778		struct alias_link *search_result;
779
780		for (j = 0; j < port_count; j++)
781			if ((search_result = FindLinkIn(la, dst_addr,
782			    alias_addr, dst_port, htons(port_sys + j),
783			    link_type, 0)) != NULL)
784				break;
785
786		/* Found a good range, return base */
787		if (j == port_count)
788			return (htons(port_sys));
789
790		/* Find a new base to try */
791		if (align == FIND_EVEN_ALIAS_BASE)
792			port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
793		else
794			port_sys = arc4random() & ALIAS_PORT_MASK;
795
796		port_sys += ALIAS_PORT_BASE;
797	}
798
799#ifdef LIBALIAS_DEBUG
800	fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
801	fprintf(stderr, "could not find free port(s)\n");
802#endif
803
804	return (0);
805}
806
807static void
808CleanupAliasData(struct libalias *la)
809{
810	struct alias_link *lnk;
811	int i;
812
813	LIBALIAS_LOCK_ASSERT(la);
814	for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
815		lnk = LIST_FIRST(&la->linkTableOut[i]);
816		while (lnk != NULL) {
817			struct alias_link *link_next = LIST_NEXT(lnk, list_out);
818			DeleteLink(lnk);
819			lnk = link_next;
820		}
821	}
822
823	la->cleanupIndex = 0;
824}
825
826static void
827IncrementalCleanup(struct libalias *la)
828{
829	struct alias_link *lnk, *lnk_tmp;
830
831	LIBALIAS_LOCK_ASSERT(la);
832	LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
833	    list_out, lnk_tmp) {
834		if (la->timeStamp - lnk->timestamp > lnk->expire_time)
835			DeleteLink(lnk);
836	}
837
838	if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
839		la->cleanupIndex = 0;
840}
841
842static void
843DeleteLink(struct alias_link *lnk)
844{
845	struct libalias *la = lnk->la;
846
847	LIBALIAS_LOCK_ASSERT(la);
848	/* Don't do anything if the link is marked permanent */
849	if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
850		return;
851
852#ifndef NO_FW_PUNCH
853	/* Delete associated firewall hole, if any */
854	ClearFWHole(lnk);
855#endif
856
857	/* Free memory allocated for LSNAT server pool */
858	if (lnk->server != NULL) {
859		struct server *head, *curr, *next;
860
861		head = curr = lnk->server;
862		do {
863			next = curr->next;
864			free(curr);
865		} while ((curr = next) != head);
866	}
867	/* Adjust output table pointers */
868	LIST_REMOVE(lnk, list_out);
869
870	/* Adjust input table pointers */
871	LIST_REMOVE(lnk, list_in);
872#ifndef NO_USE_SOCKETS
873	/* Close socket, if one has been allocated */
874	if (lnk->sockfd != -1) {
875		la->sockCount--;
876		close(lnk->sockfd);
877	}
878#endif
879	/* Link-type dependent cleanup */
880	switch (lnk->link_type) {
881	case LINK_ICMP:
882		la->icmpLinkCount--;
883		break;
884	case LINK_UDP:
885		la->udpLinkCount--;
886		break;
887	case LINK_TCP:
888		la->tcpLinkCount--;
889		free(lnk->data.tcp);
890		break;
891	case LINK_PPTP:
892		la->pptpLinkCount--;
893		break;
894	case LINK_FRAGMENT_ID:
895		la->fragmentIdLinkCount--;
896		break;
897	case LINK_FRAGMENT_PTR:
898		la->fragmentPtrLinkCount--;
899		if (lnk->data.frag_ptr != NULL)
900			free(lnk->data.frag_ptr);
901		break;
902	case LINK_ADDR:
903		break;
904	default:
905		la->protoLinkCount--;
906		break;
907	}
908
909	/* Free memory */
910	free(lnk);
911
912	/* Write statistics, if logging enabled */
913	if (la->packetAliasMode & PKT_ALIAS_LOG) {
914		ShowAliasStats(la);
915	}
916}
917
918struct alias_link *
919AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
920    struct in_addr alias_addr, u_short src_port, u_short dst_port,
921    int alias_port_param, int link_type)
922{
923	u_int start_point;
924	struct alias_link *lnk;
925
926	LIBALIAS_LOCK_ASSERT(la);
927	lnk = malloc(sizeof(struct alias_link));
928	if (lnk != NULL) {
929		/* Basic initialization */
930		lnk->la = la;
931		lnk->src_addr = src_addr;
932		lnk->dst_addr = dst_addr;
933		lnk->alias_addr = alias_addr;
934		lnk->proxy_addr.s_addr = INADDR_ANY;
935		lnk->src_port = src_port;
936		lnk->dst_port = dst_port;
937		lnk->proxy_port = 0;
938		lnk->server = NULL;
939		lnk->link_type = link_type;
940#ifndef NO_USE_SOCKETS
941		lnk->sockfd = -1;
942#endif
943		lnk->flags = 0;
944		lnk->pflags = 0;
945		lnk->timestamp = la->timeStamp;
946
947		/* Expiration time */
948		switch (link_type) {
949		case LINK_ICMP:
950			lnk->expire_time = ICMP_EXPIRE_TIME;
951			break;
952		case LINK_UDP:
953			lnk->expire_time = UDP_EXPIRE_TIME;
954			break;
955		case LINK_TCP:
956			lnk->expire_time = TCP_EXPIRE_INITIAL;
957			break;
958		case LINK_PPTP:
959			lnk->flags |= LINK_PERMANENT;	/* no timeout. */
960			break;
961		case LINK_FRAGMENT_ID:
962			lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
963			break;
964		case LINK_FRAGMENT_PTR:
965			lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
966			break;
967		case LINK_ADDR:
968			break;
969		default:
970			lnk->expire_time = PROTO_EXPIRE_TIME;
971			break;
972		}
973
974		/* Determine alias flags */
975		if (dst_addr.s_addr == INADDR_ANY)
976			lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
977		if (dst_port == 0)
978			lnk->flags |= LINK_UNKNOWN_DEST_PORT;
979
980		/* Determine alias port */
981		if (GetNewPort(la, lnk, alias_port_param) != 0) {
982			free(lnk);
983			return (NULL);
984		}
985		/* Link-type dependent initialization */
986		switch (link_type) {
987			struct tcp_dat *aux_tcp;
988
989		case LINK_ICMP:
990			la->icmpLinkCount++;
991			break;
992		case LINK_UDP:
993			la->udpLinkCount++;
994			break;
995		case LINK_TCP:
996			aux_tcp = malloc(sizeof(struct tcp_dat));
997			if (aux_tcp != NULL) {
998				int i;
999
1000				la->tcpLinkCount++;
1001				aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1002				aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1003				aux_tcp->state.index = 0;
1004				aux_tcp->state.ack_modified = 0;
1005				for (i = 0; i < N_LINK_TCP_DATA; i++)
1006					aux_tcp->ack[i].active = 0;
1007				aux_tcp->fwhole = -1;
1008				lnk->data.tcp = aux_tcp;
1009			} else {
1010#ifdef LIBALIAS_DEBUG
1011				fprintf(stderr, "PacketAlias/AddLink: ");
1012				fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1013#endif
1014				free(lnk);
1015				return (NULL);
1016			}
1017			break;
1018		case LINK_PPTP:
1019			la->pptpLinkCount++;
1020			break;
1021		case LINK_FRAGMENT_ID:
1022			la->fragmentIdLinkCount++;
1023			break;
1024		case LINK_FRAGMENT_PTR:
1025			la->fragmentPtrLinkCount++;
1026			break;
1027		case LINK_ADDR:
1028			break;
1029		default:
1030			la->protoLinkCount++;
1031			break;
1032		}
1033
1034		/* Set up pointers for output lookup table */
1035		start_point = StartPointOut(src_addr, dst_addr,
1036		    src_port, dst_port, link_type);
1037		LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1038
1039		/* Set up pointers for input lookup table */
1040		start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1041		LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1042	} else {
1043#ifdef LIBALIAS_DEBUG
1044		fprintf(stderr, "PacketAlias/AddLink(): ");
1045		fprintf(stderr, "malloc() call failed.\n");
1046#endif
1047	}
1048	if (la->packetAliasMode & PKT_ALIAS_LOG) {
1049		ShowAliasStats(la);
1050	}
1051	return (lnk);
1052}
1053
1054/*
1055 * If alias_port_param is less than zero, alias port will be automatically
1056 * chosen. If greater than zero, equal to alias port
1057 */
1058static struct alias_link *
1059ReLink(struct alias_link *old_lnk,
1060    struct in_addr src_addr,
1061    struct in_addr dst_addr,
1062    struct in_addr alias_addr,
1063    u_short src_port,
1064    u_short dst_port,
1065    int alias_port_param,
1066    int link_type)
1067{
1068	struct alias_link *new_lnk;
1069	struct libalias *la = old_lnk->la;
1070
1071	LIBALIAS_LOCK_ASSERT(la);
1072	new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1073	    src_port, dst_port, alias_port_param,
1074	    link_type);
1075#ifndef NO_FW_PUNCH
1076	if (new_lnk != NULL &&
1077	    old_lnk->link_type == LINK_TCP &&
1078	    old_lnk->data.tcp->fwhole > 0) {
1079		PunchFWHole(new_lnk);
1080	}
1081#endif
1082	DeleteLink(old_lnk);
1083	return (new_lnk);
1084}
1085
1086static struct alias_link *
1087_FindLinkOut(struct libalias *la, struct in_addr src_addr,
1088    struct in_addr dst_addr,
1089    u_short src_port,
1090    u_short dst_port,
1091    int link_type,
1092    int replace_partial_links)
1093{
1094	u_int i;
1095	struct alias_link *lnk;
1096
1097	LIBALIAS_LOCK_ASSERT(la);
1098	i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1099	LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1100		if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1101		    lnk->src_addr.s_addr == src_addr.s_addr &&
1102		    lnk->src_port == src_port &&
1103		    lnk->dst_port == dst_port &&
1104		    lnk->link_type == link_type &&
1105		    lnk->server == NULL) {
1106			lnk->timestamp = la->timeStamp;
1107			break;
1108		}
1109	}
1110
1111	/* Search for partially specified links. */
1112	if (lnk == NULL && replace_partial_links) {
1113		if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1114			lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1115			    link_type, 0);
1116			if (lnk == NULL)
1117				lnk = _FindLinkOut(la, src_addr, ANY_ADDR, src_port,
1118				    dst_port, link_type, 0);
1119		}
1120		if (lnk == NULL &&
1121		    (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1122			lnk = _FindLinkOut(la, src_addr, ANY_ADDR, src_port, 0,
1123			    link_type, 0);
1124		}
1125		if (lnk != NULL) {
1126			lnk = ReLink(lnk,
1127			    src_addr, dst_addr, lnk->alias_addr,
1128			    src_port, dst_port, lnk->alias_port,
1129			    link_type);
1130		}
1131	}
1132	return (lnk);
1133}
1134
1135static struct alias_link *
1136FindLinkOut(struct libalias *la, struct in_addr src_addr,
1137    struct in_addr dst_addr,
1138    u_short src_port,
1139    u_short dst_port,
1140    int link_type,
1141    int replace_partial_links)
1142{
1143	struct alias_link *lnk;
1144
1145	LIBALIAS_LOCK_ASSERT(la);
1146	lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1147	    link_type, replace_partial_links);
1148
1149	if (lnk == NULL) {
1150		/*
1151		 * The following allows permanent links to be specified as
1152		 * using the default source address (i.e. device interface
1153		 * address) without knowing in advance what that address
1154		 * is.
1155		 */
1156		if (la->aliasAddress.s_addr != INADDR_ANY &&
1157		    src_addr.s_addr == la->aliasAddress.s_addr) {
1158			lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port,
1159			    link_type, replace_partial_links);
1160		}
1161	}
1162	return (lnk);
1163}
1164
1165static struct alias_link *
1166_FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1167    struct in_addr alias_addr,
1168    u_short dst_port,
1169    u_short alias_port,
1170    int link_type,
1171    int replace_partial_links)
1172{
1173	int flags_in;
1174	u_int start_point;
1175	struct alias_link *lnk;
1176	struct alias_link *lnk_fully_specified;
1177	struct alias_link *lnk_unknown_all;
1178	struct alias_link *lnk_unknown_dst_addr;
1179	struct alias_link *lnk_unknown_dst_port;
1180
1181	LIBALIAS_LOCK_ASSERT(la);
1182	/* Initialize pointers */
1183	lnk_fully_specified = NULL;
1184	lnk_unknown_all = NULL;
1185	lnk_unknown_dst_addr = NULL;
1186	lnk_unknown_dst_port = NULL;
1187
1188	/* If either the dest addr or port is unknown, the search
1189	 * loop will have to know about this. */
1190	flags_in = 0;
1191	if (dst_addr.s_addr == INADDR_ANY)
1192		flags_in |= LINK_UNKNOWN_DEST_ADDR;
1193	if (dst_port == 0)
1194		flags_in |= LINK_UNKNOWN_DEST_PORT;
1195
1196	/* Search loop */
1197	start_point = StartPointIn(alias_addr, alias_port, link_type);
1198	LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1199		int flags;
1200
1201		flags = flags_in | lnk->flags;
1202		if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1203			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1204			    && lnk->alias_port == alias_port
1205			    && lnk->dst_addr.s_addr == dst_addr.s_addr
1206			    && lnk->dst_port == dst_port
1207			    && lnk->link_type == link_type) {
1208				lnk_fully_specified = lnk;
1209				break;
1210			}
1211		} else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1212		    && (flags & LINK_UNKNOWN_DEST_PORT)) {
1213			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1214			    && lnk->alias_port == alias_port
1215			    && lnk->link_type == link_type) {
1216				if (lnk_unknown_all == NULL)
1217					lnk_unknown_all = lnk;
1218			}
1219		} else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1220			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1221			    && lnk->alias_port == alias_port
1222			    && lnk->link_type == link_type
1223			    && lnk->dst_port == dst_port) {
1224				if (lnk_unknown_dst_addr == NULL)
1225					lnk_unknown_dst_addr = lnk;
1226			}
1227		} else if (flags & LINK_UNKNOWN_DEST_PORT) {
1228			if (lnk->alias_addr.s_addr == alias_addr.s_addr
1229			    && lnk->alias_port == alias_port
1230			    && lnk->link_type == link_type
1231			    && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1232				if (lnk_unknown_dst_port == NULL)
1233					lnk_unknown_dst_port = lnk;
1234			}
1235		}
1236	}
1237
1238	if (lnk_fully_specified != NULL) {
1239		lnk_fully_specified->timestamp = la->timeStamp;
1240		lnk = lnk_fully_specified;
1241	} else if (lnk_unknown_dst_port != NULL)
1242		lnk = lnk_unknown_dst_port;
1243	else if (lnk_unknown_dst_addr != NULL)
1244		lnk = lnk_unknown_dst_addr;
1245	else if (lnk_unknown_all != NULL)
1246		lnk = lnk_unknown_all;
1247	else
1248		return (NULL);
1249
1250	if (replace_partial_links &&
1251	    (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1252		struct in_addr src_addr;
1253		u_short src_port;
1254
1255		if (lnk->server != NULL) {	/* LSNAT link */
1256			src_addr = lnk->server->addr;
1257			src_port = lnk->server->port;
1258			lnk->server = lnk->server->next;
1259		} else {
1260			src_addr = lnk->src_addr;
1261			src_port = lnk->src_port;
1262		}
1263
1264		if (link_type == LINK_SCTP) {
1265			lnk->src_addr = src_addr;
1266			lnk->src_port = src_port;
1267			return (lnk);
1268		}
1269		lnk = ReLink(lnk,
1270		    src_addr, dst_addr, alias_addr,
1271		    src_port, dst_port, alias_port,
1272		    link_type);
1273	}
1274	return (lnk);
1275}
1276
1277static struct alias_link *
1278FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1279    struct in_addr alias_addr,
1280    u_short dst_port,
1281    u_short alias_port,
1282    int link_type,
1283    int replace_partial_links)
1284{
1285	struct alias_link *lnk;
1286
1287	LIBALIAS_LOCK_ASSERT(la);
1288	lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1289	    link_type, replace_partial_links);
1290
1291	if (lnk == NULL) {
1292		/*
1293		 * The following allows permanent links to be specified as
1294		 * using the default aliasing address (i.e. device
1295		 * interface address) without knowing in advance what that
1296		 * address is.
1297		 */
1298		if (la->aliasAddress.s_addr != INADDR_ANY &&
1299		    alias_addr.s_addr == la->aliasAddress.s_addr) {
1300			lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port,
1301			    link_type, replace_partial_links);
1302		}
1303	}
1304	return (lnk);
1305}
1306
1307/* External routines for finding/adding links
1308
1309-- "external" means outside alias_db.c, but within alias*.c --
1310
1311    FindIcmpIn(), FindIcmpOut()
1312    FindFragmentIn1(), FindFragmentIn2()
1313    AddFragmentPtrLink(), FindFragmentPtr()
1314    FindProtoIn(), FindProtoOut()
1315    FindUdpTcpIn(), FindUdpTcpOut()
1316    AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1317    FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1318    FindOriginalAddress(), FindAliasAddress()
1319
1320(prototypes in alias_local.h)
1321*/
1322
1323struct alias_link *
1324FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1325    struct in_addr alias_addr,
1326    u_short id_alias,
1327    int create)
1328{
1329	struct alias_link *lnk;
1330
1331	LIBALIAS_LOCK_ASSERT(la);
1332	lnk = FindLinkIn(la, dst_addr, alias_addr,
1333	    NO_DEST_PORT, id_alias,
1334	    LINK_ICMP, 0);
1335	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1336		struct in_addr target_addr;
1337
1338		target_addr = FindOriginalAddress(la, alias_addr);
1339		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1340		    id_alias, NO_DEST_PORT, id_alias,
1341		    LINK_ICMP);
1342	}
1343	return (lnk);
1344}
1345
1346struct alias_link *
1347FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1348    struct in_addr dst_addr,
1349    u_short id,
1350    int create)
1351{
1352	struct alias_link *lnk;
1353
1354	LIBALIAS_LOCK_ASSERT(la);
1355	lnk = FindLinkOut(la, src_addr, dst_addr,
1356	    id, NO_DEST_PORT,
1357	    LINK_ICMP, 0);
1358	if (lnk == NULL && create) {
1359		struct in_addr alias_addr;
1360
1361		alias_addr = FindAliasAddress(la, src_addr);
1362		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1363		    id, NO_DEST_PORT, GET_ALIAS_ID,
1364		    LINK_ICMP);
1365	}
1366	return (lnk);
1367}
1368
1369struct alias_link *
1370FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1371    struct in_addr alias_addr,
1372    u_short ip_id)
1373{
1374	struct alias_link *lnk;
1375
1376	LIBALIAS_LOCK_ASSERT(la);
1377	lnk = FindLinkIn(la, dst_addr, alias_addr,
1378	    NO_DEST_PORT, ip_id,
1379	    LINK_FRAGMENT_ID, 0);
1380
1381	if (lnk == NULL) {
1382		lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr,
1383		    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1384		    LINK_FRAGMENT_ID);
1385	}
1386	return (lnk);
1387}
1388
1389/* Doesn't add a link if one is not found. */
1390struct alias_link *
1391FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,
1392    struct in_addr alias_addr, u_short ip_id)
1393{
1394	LIBALIAS_LOCK_ASSERT(la);
1395	return FindLinkIn(la, dst_addr, alias_addr,
1396	    NO_DEST_PORT, ip_id,
1397	    LINK_FRAGMENT_ID, 0);
1398}
1399
1400struct alias_link *
1401AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1402    u_short ip_id)
1403{
1404	LIBALIAS_LOCK_ASSERT(la);
1405	return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR,
1406	    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1407	    LINK_FRAGMENT_PTR);
1408}
1409
1410struct alias_link *
1411FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1412    u_short ip_id)
1413{
1414	LIBALIAS_LOCK_ASSERT(la);
1415	return FindLinkIn(la, dst_addr, ANY_ADDR,
1416	    NO_DEST_PORT, ip_id,
1417	    LINK_FRAGMENT_PTR, 0);
1418}
1419
1420struct alias_link *
1421FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1422    struct in_addr alias_addr,
1423    u_char proto)
1424{
1425	struct alias_link *lnk;
1426
1427	LIBALIAS_LOCK_ASSERT(la);
1428	lnk = FindLinkIn(la, dst_addr, alias_addr,
1429	    NO_DEST_PORT, 0,
1430	    proto, 1);
1431
1432	if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1433		struct in_addr target_addr;
1434
1435		target_addr = FindOriginalAddress(la, alias_addr);
1436		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1437		    NO_SRC_PORT, NO_DEST_PORT, 0,
1438		    proto);
1439	}
1440	return (lnk);
1441}
1442
1443struct alias_link *
1444FindProtoOut(struct libalias *la, struct in_addr src_addr,
1445    struct in_addr dst_addr,
1446    u_char proto)
1447{
1448	struct alias_link *lnk;
1449
1450	LIBALIAS_LOCK_ASSERT(la);
1451	lnk = FindLinkOut(la, src_addr, dst_addr,
1452	    NO_SRC_PORT, NO_DEST_PORT,
1453	    proto, 1);
1454
1455	if (lnk == NULL) {
1456		struct in_addr alias_addr;
1457
1458		alias_addr = FindAliasAddress(la, src_addr);
1459		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1460		    NO_SRC_PORT, NO_DEST_PORT, 0,
1461		    proto);
1462	}
1463	return (lnk);
1464}
1465
1466struct alias_link *
1467FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1468    struct in_addr alias_addr,
1469    u_short dst_port,
1470    u_short alias_port,
1471    u_char proto,
1472    int create)
1473{
1474	int link_type;
1475	struct alias_link *lnk;
1476
1477	LIBALIAS_LOCK_ASSERT(la);
1478	switch (proto) {
1479	case IPPROTO_UDP:
1480		link_type = LINK_UDP;
1481		break;
1482	case IPPROTO_TCP:
1483		link_type = LINK_TCP;
1484		break;
1485	default:
1486		return (NULL);
1487		break;
1488	}
1489
1490	lnk = FindLinkIn(la, dst_addr, alias_addr,
1491	    dst_port, alias_port,
1492	    link_type, create);
1493
1494	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1495		struct in_addr target_addr;
1496
1497		target_addr = FindOriginalAddress(la, alias_addr);
1498		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1499		    alias_port, dst_port, alias_port,
1500		    link_type);
1501	}
1502	return (lnk);
1503}
1504
1505struct alias_link *
1506FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1507    struct in_addr dst_addr,
1508    u_short src_port,
1509    u_short dst_port,
1510    u_char proto,
1511    int create)
1512{
1513	int link_type;
1514	struct alias_link *lnk;
1515
1516	LIBALIAS_LOCK_ASSERT(la);
1517	switch (proto) {
1518	case IPPROTO_UDP:
1519		link_type = LINK_UDP;
1520		break;
1521	case IPPROTO_TCP:
1522		link_type = LINK_TCP;
1523		break;
1524	default:
1525		return (NULL);
1526		break;
1527	}
1528
1529	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1530
1531	if (lnk == NULL && create) {
1532		struct in_addr alias_addr;
1533
1534		alias_addr = FindAliasAddress(la, src_addr);
1535		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1536		    src_port, dst_port, GET_ALIAS_PORT,
1537		    link_type);
1538	}
1539	return (lnk);
1540}
1541
1542struct alias_link *
1543AddPptp(struct libalias *la, struct in_addr src_addr,
1544    struct in_addr dst_addr,
1545    struct in_addr alias_addr,
1546    u_int16_t src_call_id)
1547{
1548	struct alias_link *lnk;
1549
1550	LIBALIAS_LOCK_ASSERT(la);
1551	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1552	    src_call_id, 0, GET_ALIAS_PORT,
1553	    LINK_PPTP);
1554
1555	return (lnk);
1556}
1557
1558struct alias_link *
1559FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1560    struct in_addr dst_addr,
1561    u_int16_t src_call_id)
1562{
1563	u_int i;
1564	struct alias_link *lnk;
1565
1566	LIBALIAS_LOCK_ASSERT(la);
1567	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1568	LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1569		if (lnk->link_type == LINK_PPTP &&
1570		    lnk->src_addr.s_addr == src_addr.s_addr &&
1571		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1572		    lnk->src_port == src_call_id)
1573			break;
1574
1575	return (lnk);
1576}
1577
1578struct alias_link *
1579FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1580    struct in_addr dst_addr,
1581    u_int16_t dst_call_id)
1582{
1583	u_int i;
1584	struct alias_link *lnk;
1585
1586	LIBALIAS_LOCK_ASSERT(la);
1587	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1588	LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1589		if (lnk->link_type == LINK_PPTP &&
1590		    lnk->src_addr.s_addr == src_addr.s_addr &&
1591		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1592		    lnk->dst_port == dst_call_id)
1593			break;
1594
1595	return (lnk);
1596}
1597
1598struct alias_link *
1599FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1600    struct in_addr alias_addr,
1601    u_int16_t dst_call_id)
1602{
1603	u_int i;
1604	struct alias_link *lnk;
1605
1606	LIBALIAS_LOCK_ASSERT(la);
1607	i = StartPointIn(alias_addr, 0, LINK_PPTP);
1608	LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1609		if (lnk->link_type == LINK_PPTP &&
1610		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1611		    lnk->alias_addr.s_addr == alias_addr.s_addr &&
1612		    lnk->dst_port == dst_call_id)
1613			break;
1614
1615	return (lnk);
1616}
1617
1618struct alias_link *
1619FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1620    struct in_addr alias_addr,
1621    u_int16_t alias_call_id)
1622{
1623	struct alias_link *lnk;
1624
1625	LIBALIAS_LOCK_ASSERT(la);
1626	lnk = FindLinkIn(la, dst_addr, alias_addr,
1627	    0 /* any */ , alias_call_id,
1628	    LINK_PPTP, 0);
1629
1630	return (lnk);
1631}
1632
1633struct alias_link *
1634FindRtspOut(struct libalias *la, struct in_addr src_addr,
1635    struct in_addr dst_addr,
1636    u_short src_port,
1637    u_short alias_port,
1638    u_char proto)
1639{
1640	int link_type;
1641	struct alias_link *lnk;
1642
1643	LIBALIAS_LOCK_ASSERT(la);
1644	switch (proto) {
1645	case IPPROTO_UDP:
1646		link_type = LINK_UDP;
1647		break;
1648	case IPPROTO_TCP:
1649		link_type = LINK_TCP;
1650		break;
1651	default:
1652		return (NULL);
1653		break;
1654	}
1655
1656	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1657
1658	if (lnk == NULL) {
1659		struct in_addr alias_addr;
1660
1661		alias_addr = FindAliasAddress(la, src_addr);
1662		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1663		    src_port, 0, alias_port,
1664		    link_type);
1665	}
1666	return (lnk);
1667}
1668
1669struct in_addr
1670FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1671{
1672	struct alias_link *lnk;
1673
1674	LIBALIAS_LOCK_ASSERT(la);
1675	lnk = FindLinkIn(la, ANY_ADDR, alias_addr,
1676	    0, 0, LINK_ADDR, 0);
1677	if (lnk == NULL) {
1678		if (la->targetAddress.s_addr == INADDR_ANY)
1679			return (alias_addr);
1680		else if (la->targetAddress.s_addr == INADDR_NONE)
1681			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1682			    la->aliasAddress : alias_addr;
1683		else
1684			return (la->targetAddress);
1685	} else {
1686		if (lnk->server != NULL) {	/* LSNAT link */
1687			struct in_addr src_addr;
1688
1689			src_addr = lnk->server->addr;
1690			lnk->server = lnk->server->next;
1691			return (src_addr);
1692		} else if (lnk->src_addr.s_addr == INADDR_ANY)
1693			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1694			    la->aliasAddress : alias_addr;
1695		else
1696			return (lnk->src_addr);
1697	}
1698}
1699
1700struct in_addr
1701FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1702{
1703	struct alias_link *lnk;
1704
1705	LIBALIAS_LOCK_ASSERT(la);
1706	lnk = FindLinkOut(la, original_addr, ANY_ADDR,
1707	    0, 0, LINK_ADDR, 0);
1708	if (lnk == NULL) {
1709		return (la->aliasAddress.s_addr != INADDR_ANY) ?
1710		    la->aliasAddress : original_addr;
1711	} else {
1712		if (lnk->alias_addr.s_addr == INADDR_ANY)
1713			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1714			    la->aliasAddress : original_addr;
1715		else
1716			return (lnk->alias_addr);
1717	}
1718}
1719
1720/* External routines for getting or changing link data
1721   (external to alias_db.c, but internal to alias*.c)
1722
1723    SetFragmentData(), GetFragmentData()
1724    SetFragmentPtr(), GetFragmentPtr()
1725    SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1726    GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1727    GetOriginalPort(), GetAliasPort()
1728    SetAckModified(), GetAckModified()
1729    GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1730    SetProtocolFlags(), GetProtocolFlags()
1731    SetDestCallId()
1732*/
1733
1734void
1735SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1736{
1737	lnk->data.frag_addr = src_addr;
1738}
1739
1740void
1741GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1742{
1743	*src_addr = lnk->data.frag_addr;
1744}
1745
1746void
1747SetFragmentPtr(struct alias_link *lnk, void *fptr)
1748{
1749	lnk->data.frag_ptr = fptr;
1750}
1751
1752void
1753GetFragmentPtr(struct alias_link *lnk, void **fptr)
1754{
1755	*fptr = lnk->data.frag_ptr;
1756}
1757
1758void
1759SetStateIn(struct alias_link *lnk, int state)
1760{
1761	/* TCP input state */
1762	switch (state) {
1763		case ALIAS_TCP_STATE_DISCONNECTED:
1764		if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1765			lnk->expire_time = TCP_EXPIRE_DEAD;
1766		else
1767			lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1768		break;
1769	case ALIAS_TCP_STATE_CONNECTED:
1770		if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1771			lnk->expire_time = TCP_EXPIRE_CONNECTED;
1772		break;
1773	default:
1774#ifdef _KERNEL
1775		panic("libalias:SetStateIn() unknown state");
1776#else
1777		abort();
1778#endif
1779	}
1780	lnk->data.tcp->state.in = state;
1781}
1782
1783void
1784SetStateOut(struct alias_link *lnk, int state)
1785{
1786	/* TCP output state */
1787	switch (state) {
1788		case ALIAS_TCP_STATE_DISCONNECTED:
1789		if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1790			lnk->expire_time = TCP_EXPIRE_DEAD;
1791		else
1792			lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1793		break;
1794	case ALIAS_TCP_STATE_CONNECTED:
1795		if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1796			lnk->expire_time = TCP_EXPIRE_CONNECTED;
1797		break;
1798	default:
1799#ifdef _KERNEL
1800		panic("libalias:SetStateOut() unknown state");
1801#else
1802		abort();
1803#endif
1804	}
1805	lnk->data.tcp->state.out = state;
1806}
1807
1808int
1809GetStateIn(struct alias_link *lnk)
1810{
1811	/* TCP input state */
1812	return (lnk->data.tcp->state.in);
1813}
1814
1815int
1816GetStateOut(struct alias_link *lnk)
1817{
1818	/* TCP output state */
1819	return (lnk->data.tcp->state.out);
1820}
1821
1822struct in_addr
1823GetOriginalAddress(struct alias_link *lnk)
1824{
1825	if (lnk->src_addr.s_addr == INADDR_ANY)
1826		return (lnk->la->aliasAddress);
1827	else
1828		return (lnk->src_addr);
1829}
1830
1831struct in_addr
1832GetDestAddress(struct alias_link *lnk)
1833{
1834	return (lnk->dst_addr);
1835}
1836
1837struct in_addr
1838GetAliasAddress(struct alias_link *lnk)
1839{
1840	if (lnk->alias_addr.s_addr == INADDR_ANY)
1841		return (lnk->la->aliasAddress);
1842	else
1843		return (lnk->alias_addr);
1844}
1845
1846struct in_addr
1847GetDefaultAliasAddress(struct libalias *la)
1848{
1849	LIBALIAS_LOCK_ASSERT(la);
1850	return (la->aliasAddress);
1851}
1852
1853void
1854SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1855{
1856	LIBALIAS_LOCK_ASSERT(la);
1857	la->aliasAddress = alias_addr;
1858}
1859
1860u_short
1861GetOriginalPort(struct alias_link *lnk)
1862{
1863	return (lnk->src_port);
1864}
1865
1866u_short
1867GetAliasPort(struct alias_link *lnk)
1868{
1869	return (lnk->alias_port);
1870}
1871
1872#ifndef NO_FW_PUNCH
1873static u_short
1874GetDestPort(struct alias_link *lnk)
1875{
1876	return (lnk->dst_port);
1877}
1878
1879#endif
1880
1881/* Indicate that ACK numbers have been modified in a TCP connection */
1882void
1883SetAckModified(struct alias_link *lnk)
1884{
1885	lnk->data.tcp->state.ack_modified = 1;
1886}
1887
1888struct in_addr
1889GetProxyAddress(struct alias_link *lnk)
1890{
1891	return (lnk->proxy_addr);
1892}
1893
1894void
1895SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1896{
1897	lnk->proxy_addr = addr;
1898}
1899
1900u_short
1901GetProxyPort(struct alias_link *lnk)
1902{
1903	return (lnk->proxy_port);
1904}
1905
1906void
1907SetProxyPort(struct alias_link *lnk, u_short port)
1908{
1909	lnk->proxy_port = port;
1910}
1911
1912/* See if ACK numbers have been modified */
1913int
1914GetAckModified(struct alias_link *lnk)
1915{
1916	return (lnk->data.tcp->state.ack_modified);
1917}
1918
1919/*
1920 * Find out how much the ACK number has been altered for an
1921 * incoming TCP packet.  To do this, a circular list of ACK
1922 * numbers where the TCP packet size was altered is searched.
1923 */
1924// XXX ip free
1925int
1926GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1927{
1928	int i, j;
1929	int delta, ack_diff_min;
1930
1931	delta = 0;
1932	ack_diff_min = -1;
1933	i = lnk->data.tcp->state.index;
1934	for (j = 0; j < N_LINK_TCP_DATA; j++) {
1935		struct ack_data_record x;
1936
1937		if (i == 0)
1938			i = N_LINK_TCP_DATA;
1939		i--;
1940		x = lnk->data.tcp->ack[i];
1941		if (x.active == 1) {
1942			int ack_diff;
1943
1944			ack_diff = SeqDiff(x.ack_new, ack);
1945			if (ack_diff >= 0) {
1946				if (ack_diff_min >= 0) {
1947					if (ack_diff < ack_diff_min) {
1948						delta = x.delta;
1949						ack_diff_min = ack_diff;
1950					}
1951				} else {
1952					delta = x.delta;
1953					ack_diff_min = ack_diff;
1954				}
1955			}
1956		}
1957	}
1958	return (delta);
1959}
1960
1961/*
1962 * Find out how much the sequence number has been altered for an
1963 * outgoing TCP packet.  To do this, a circular list of ACK numbers
1964 * where the TCP packet size was altered is searched.
1965 */
1966// XXX ip free
1967int
1968GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
1969{
1970	int i, j;
1971	int delta, seq_diff_min;
1972
1973	delta = 0;
1974	seq_diff_min = -1;
1975	i = lnk->data.tcp->state.index;
1976	for (j = 0; j < N_LINK_TCP_DATA; j++) {
1977		struct ack_data_record x;
1978
1979		if (i == 0)
1980			i = N_LINK_TCP_DATA;
1981		i--;
1982		x = lnk->data.tcp->ack[i];
1983		if (x.active == 1) {
1984			int seq_diff;
1985
1986			seq_diff = SeqDiff(x.ack_old, seq);
1987			if (seq_diff >= 0) {
1988				if (seq_diff_min >= 0) {
1989					if (seq_diff < seq_diff_min) {
1990						delta = x.delta;
1991						seq_diff_min = seq_diff;
1992					}
1993				} else {
1994					delta = x.delta;
1995					seq_diff_min = seq_diff;
1996				}
1997			}
1998		}
1999	}
2000	return (delta);
2001}
2002
2003/*
2004 * When a TCP packet has been altered in length, save this
2005 * information in a circular list.  If enough packets have been
2006 * altered, then this list will begin to overwrite itself.
2007 */
2008// XXX ip free
2009void
2010AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
2011    u_long th_seq, u_int th_off)
2012{
2013	struct ack_data_record x;
2014	int hlen, tlen, dlen;
2015	int i;
2016
2017	hlen = (ip_hl + th_off) << 2;
2018	tlen = ntohs(ip_len);
2019	dlen = tlen - hlen;
2020
2021	x.ack_old = htonl(ntohl(th_seq) + dlen);
2022	x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
2023	x.delta = delta;
2024	x.active = 1;
2025
2026	i = lnk->data.tcp->state.index;
2027	lnk->data.tcp->ack[i] = x;
2028
2029	i++;
2030	if (i == N_LINK_TCP_DATA)
2031		lnk->data.tcp->state.index = 0;
2032	else
2033		lnk->data.tcp->state.index = i;
2034}
2035
2036void
2037SetExpire(struct alias_link *lnk, int expire)
2038{
2039	if (expire == 0) {
2040		lnk->flags &= ~LINK_PERMANENT;
2041		DeleteLink(lnk);
2042	} else if (expire == -1) {
2043		lnk->flags |= LINK_PERMANENT;
2044	} else if (expire > 0) {
2045		lnk->expire_time = expire;
2046	} else {
2047#ifdef LIBALIAS_DEBUG
2048		fprintf(stderr, "PacketAlias/SetExpire(): ");
2049		fprintf(stderr, "error in expire parameter\n");
2050#endif
2051	}
2052}
2053
2054void
2055SetProtocolFlags(struct alias_link *lnk, int pflags)
2056{
2057	lnk->pflags = pflags;
2058}
2059
2060int
2061GetProtocolFlags(struct alias_link *lnk)
2062{
2063	return (lnk->pflags);
2064}
2065
2066void
2067SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2068{
2069	struct libalias *la = lnk->la;
2070
2071	LIBALIAS_LOCK_ASSERT(la);
2072	la->deleteAllLinks = 1;
2073	ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2074	    lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2075	la->deleteAllLinks = 0;
2076}
2077
2078/* Miscellaneous Functions
2079
2080    HouseKeeping()
2081    InitPacketAliasLog()
2082    UninitPacketAliasLog()
2083*/
2084
2085/*
2086    Whenever an outgoing or incoming packet is handled, HouseKeeping()
2087    is called to find and remove timed-out aliasing links.  Logic exists
2088    to sweep through the entire table and linked list structure
2089    every 60 seconds.
2090
2091    (prototype in alias_local.h)
2092*/
2093
2094void
2095HouseKeeping(struct libalias *la)
2096{
2097	int i, n;
2098#ifndef _KERNEL
2099	struct timeval tv;
2100#endif
2101
2102	LIBALIAS_LOCK_ASSERT(la);
2103	/*
2104	 * Save system time (seconds) in global variable timeStamp for use
2105	 * by other functions. This is done so as not to unnecessarily
2106	 * waste timeline by making system calls.
2107	 */
2108#ifdef _KERNEL
2109	la->timeStamp = time_uptime;
2110#else
2111	gettimeofday(&tv, NULL);
2112	la->timeStamp = tv.tv_sec;
2113#endif
2114
2115	/* Compute number of spokes (output table link chains) to cover */
2116	n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2117	n /= ALIAS_CLEANUP_INTERVAL_SECS;
2118
2119	/* Handle different cases */
2120	if (n > 0) {
2121		if (n > ALIAS_CLEANUP_MAX_SPOKES)
2122			n = ALIAS_CLEANUP_MAX_SPOKES;
2123		la->lastCleanupTime = la->timeStamp;
2124		for (i = 0; i < n; i++)
2125			IncrementalCleanup(la);
2126	} else if (n < 0) {
2127#ifdef LIBALIAS_DEBUG
2128		fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2129		fprintf(stderr, "something unexpected in time values\n");
2130#endif
2131		la->lastCleanupTime = la->timeStamp;
2132	}
2133}
2134
2135/* Init the log file and enable logging */
2136static int
2137InitPacketAliasLog(struct libalias *la)
2138{
2139	LIBALIAS_LOCK_ASSERT(la);
2140	if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2141#ifdef _KERNEL
2142		if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2143			;
2144#else
2145		if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2146			fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2147#endif
2148		else
2149			return (ENOMEM); /* log initialization failed */
2150		la->packetAliasMode |= PKT_ALIAS_LOG;
2151	}
2152
2153	return (1);
2154}
2155
2156/* Close the log-file and disable logging. */
2157static void
2158UninitPacketAliasLog(struct libalias *la)
2159{
2160	LIBALIAS_LOCK_ASSERT(la);
2161	if (la->logDesc) {
2162#ifdef _KERNEL
2163		free(la->logDesc);
2164#else
2165		fclose(la->logDesc);
2166#endif
2167		la->logDesc = NULL;
2168	}
2169	la->packetAliasMode &= ~PKT_ALIAS_LOG;
2170}
2171
2172/* Outside world interfaces
2173
2174-- "outside world" means other than alias*.c routines --
2175
2176    PacketAliasRedirectPort()
2177    PacketAliasAddServer()
2178    PacketAliasRedirectProto()
2179    PacketAliasRedirectAddr()
2180    PacketAliasRedirectDynamic()
2181    PacketAliasRedirectDelete()
2182    PacketAliasSetAddress()
2183    PacketAliasInit()
2184    PacketAliasUninit()
2185    PacketAliasSetMode()
2186
2187(prototypes in alias.h)
2188*/
2189
2190/* Redirection from a specific public addr:port to a
2191   private addr:port */
2192struct alias_link *
2193LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2194    struct in_addr dst_addr, u_short dst_port,
2195    struct in_addr alias_addr, u_short alias_port,
2196    u_char proto)
2197{
2198	int link_type;
2199	struct alias_link *lnk;
2200
2201	LIBALIAS_LOCK(la);
2202	switch (proto) {
2203	case IPPROTO_UDP:
2204		link_type = LINK_UDP;
2205		break;
2206	case IPPROTO_TCP:
2207		link_type = LINK_TCP;
2208		break;
2209	case IPPROTO_SCTP:
2210		link_type = LINK_SCTP;
2211		break;
2212	default:
2213#ifdef LIBALIAS_DEBUG
2214		fprintf(stderr, "PacketAliasRedirectPort(): ");
2215		fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
2216#endif
2217		lnk = NULL;
2218		goto getout;
2219	}
2220
2221	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2222	    src_port, dst_port, alias_port,
2223	    link_type);
2224
2225	if (lnk != NULL) {
2226		lnk->flags |= LINK_PERMANENT;
2227	}
2228#ifdef LIBALIAS_DEBUG
2229	else {
2230		fprintf(stderr, "PacketAliasRedirectPort(): "
2231		    "call to AddLink() failed\n");
2232	}
2233#endif
2234
2235getout:
2236	LIBALIAS_UNLOCK(la);
2237	return (lnk);
2238}
2239
2240/* Add server to the pool of servers */
2241int
2242LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2243{
2244	struct server *server;
2245	int res;
2246
2247	LIBALIAS_LOCK(la);
2248	(void)la;
2249
2250	server = malloc(sizeof(struct server));
2251
2252	if (server != NULL) {
2253		struct server *head;
2254
2255		server->addr = addr;
2256		server->port = port;
2257
2258		head = lnk->server;
2259		if (head == NULL)
2260			server->next = server;
2261		else {
2262			struct server *s;
2263
2264			for (s = head; s->next != head; s = s->next)
2265				;
2266			s->next = server;
2267			server->next = head;
2268		}
2269		lnk->server = server;
2270		res = 0;
2271	} else
2272		res = -1;
2273
2274	LIBALIAS_UNLOCK(la);
2275	return (res);
2276}
2277
2278/* Redirect packets of a given IP protocol from a specific
2279   public address to a private address */
2280struct alias_link *
2281LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2282    struct in_addr dst_addr,
2283    struct in_addr alias_addr,
2284    u_char proto)
2285{
2286	struct alias_link *lnk;
2287
2288	LIBALIAS_LOCK(la);
2289	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2290	    NO_SRC_PORT, NO_DEST_PORT, 0,
2291	    proto);
2292
2293	if (lnk != NULL) {
2294		lnk->flags |= LINK_PERMANENT;
2295	}
2296#ifdef LIBALIAS_DEBUG
2297	else {
2298		fprintf(stderr, "PacketAliasRedirectProto(): "
2299		    "call to AddLink() failed\n");
2300	}
2301#endif
2302
2303	LIBALIAS_UNLOCK(la);
2304	return (lnk);
2305}
2306
2307/* Static address translation */
2308struct alias_link *
2309LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2310    struct in_addr alias_addr)
2311{
2312	struct alias_link *lnk;
2313
2314	LIBALIAS_LOCK(la);
2315	lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr,
2316	    0, 0, 0,
2317	    LINK_ADDR);
2318
2319	if (lnk != NULL) {
2320		lnk->flags |= LINK_PERMANENT;
2321	}
2322#ifdef LIBALIAS_DEBUG
2323	else {
2324		fprintf(stderr, "PacketAliasRedirectAddr(): "
2325		    "call to AddLink() failed\n");
2326	}
2327#endif
2328
2329	LIBALIAS_UNLOCK(la);
2330	return (lnk);
2331}
2332
2333/* Mark the aliasing link dynamic */
2334int
2335LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2336{
2337	int res;
2338
2339	LIBALIAS_LOCK(la);
2340	(void)la;
2341
2342	if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2343		res = -1;
2344	else {
2345		lnk->flags &= ~LINK_PERMANENT;
2346		res = 0;
2347	}
2348	LIBALIAS_UNLOCK(la);
2349	return (res);
2350}
2351
2352/* This is a dangerous function to put in the API,
2353   because an invalid pointer can crash the program. */
2354void
2355LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2356{
2357	LIBALIAS_LOCK(la);
2358	la->deleteAllLinks = 1;
2359	DeleteLink(lnk);
2360	la->deleteAllLinks = 0;
2361	LIBALIAS_UNLOCK(la);
2362}
2363
2364void
2365LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2366{
2367	LIBALIAS_LOCK(la);
2368	if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2369	    && la->aliasAddress.s_addr != addr.s_addr)
2370		CleanupAliasData(la);
2371
2372	la->aliasAddress = addr;
2373	LIBALIAS_UNLOCK(la);
2374}
2375
2376void
2377LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
2378    u_short port_high)
2379{
2380	LIBALIAS_LOCK(la);
2381	la->aliasPortLower = port_low;
2382	/* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
2383	la->aliasPortLength = port_high - port_low + 1;
2384	LIBALIAS_UNLOCK(la);
2385}
2386
2387void
2388LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2389{
2390	LIBALIAS_LOCK(la);
2391	la->targetAddress = target_addr;
2392	LIBALIAS_UNLOCK(la);
2393}
2394
2395static void
2396finishoff(void)
2397{
2398	while (!LIST_EMPTY(&instancehead))
2399		LibAliasUninit(LIST_FIRST(&instancehead));
2400}
2401
2402struct libalias *
2403LibAliasInit(struct libalias *la)
2404{
2405	int i;
2406#ifndef _KERNEL
2407	struct timeval tv;
2408#endif
2409
2410	if (la == NULL) {
2411#ifdef _KERNEL
2412#undef malloc	/* XXX: ugly */
2413		la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2414#else
2415		la = calloc(sizeof *la, 1);
2416		if (la == NULL)
2417			return (la);
2418#endif
2419
2420#ifndef _KERNEL
2421		/* kernel cleans up on module unload */
2422		if (LIST_EMPTY(&instancehead))
2423			atexit(finishoff);
2424#endif
2425		LIST_INSERT_HEAD(&instancehead, la, instancelist);
2426
2427#ifdef _KERNEL
2428		la->timeStamp = time_uptime;
2429		la->lastCleanupTime = time_uptime;
2430#else
2431		gettimeofday(&tv, NULL);
2432		la->timeStamp = tv.tv_sec;
2433		la->lastCleanupTime = tv.tv_sec;
2434#endif
2435
2436		for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2437			LIST_INIT(&la->linkTableOut[i]);
2438		for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2439			LIST_INIT(&la->linkTableIn[i]);
2440#ifdef _KERNEL
2441		AliasSctpInit(la);
2442#endif
2443		LIBALIAS_LOCK_INIT(la);
2444		LIBALIAS_LOCK(la);
2445	} else {
2446		LIBALIAS_LOCK(la);
2447		la->deleteAllLinks = 1;
2448		CleanupAliasData(la);
2449		la->deleteAllLinks = 0;
2450#ifdef _KERNEL
2451		AliasSctpTerm(la);
2452		AliasSctpInit(la);
2453#endif
2454	}
2455
2456	la->aliasAddress.s_addr = INADDR_ANY;
2457	la->targetAddress.s_addr = INADDR_ANY;
2458
2459	la->icmpLinkCount = 0;
2460	la->udpLinkCount = 0;
2461	la->tcpLinkCount = 0;
2462	la->sctpLinkCount = 0;
2463	la->pptpLinkCount = 0;
2464	la->protoLinkCount = 0;
2465	la->fragmentIdLinkCount = 0;
2466	la->fragmentPtrLinkCount = 0;
2467	la->sockCount = 0;
2468
2469	la->cleanupIndex = 0;
2470
2471	la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2472#ifndef NO_USE_SOCKETS
2473	    | PKT_ALIAS_USE_SOCKETS
2474#endif
2475	    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2476#ifndef NO_FW_PUNCH
2477	la->fireWallFD = -1;
2478#endif
2479#ifndef _KERNEL
2480	LibAliasRefreshModules();
2481#endif
2482	LIBALIAS_UNLOCK(la);
2483	return (la);
2484}
2485
2486void
2487LibAliasUninit(struct libalias *la)
2488{
2489	LIBALIAS_LOCK(la);
2490#ifdef _KERNEL
2491	AliasSctpTerm(la);
2492#endif
2493	la->deleteAllLinks = 1;
2494	CleanupAliasData(la);
2495	la->deleteAllLinks = 0;
2496	UninitPacketAliasLog(la);
2497#ifndef NO_FW_PUNCH
2498	UninitPunchFW(la);
2499#endif
2500	LIST_REMOVE(la, instancelist);
2501	LIBALIAS_UNLOCK(la);
2502	LIBALIAS_LOCK_DESTROY(la);
2503	free(la);
2504}
2505
2506/* Change mode for some operations */
2507unsigned int
2508LibAliasSetMode(
2509    struct libalias *la,
2510    unsigned int flags,		/* Which state to bring flags to */
2511    unsigned int mask		/* Mask of which flags to affect (use 0 to
2512				 * do a probe for flag values) */
2513)
2514{
2515	int res = -1;
2516
2517	LIBALIAS_LOCK(la);
2518	if (flags & mask & PKT_ALIAS_LOG) {
2519		/* Enable logging */
2520		if (InitPacketAliasLog(la) == ENOMEM)
2521			goto getout;
2522	} else if (~flags & mask & PKT_ALIAS_LOG)
2523		/* _Disable_ logging */
2524		UninitPacketAliasLog(la);
2525
2526#ifndef NO_FW_PUNCH
2527	if (flags & mask & PKT_ALIAS_PUNCH_FW)
2528		/* Start punching holes in the firewall? */
2529		InitPunchFW(la);
2530	else if (~flags & mask & PKT_ALIAS_PUNCH_FW)
2531		/* Stop punching holes in the firewall? */
2532		UninitPunchFW(la);
2533#endif
2534
2535	/* Other flags can be set/cleared without special action */
2536	la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2537	res = la->packetAliasMode;
2538getout:
2539	LIBALIAS_UNLOCK(la);
2540	return (res);
2541}
2542
2543/* never used and never worked, to be removed in FreeBSD 14 */
2544int
2545LibAliasCheckNewLink(struct libalias *la)
2546{
2547	(void)la;
2548	return (0);
2549}
2550
2551#ifndef NO_FW_PUNCH
2552
2553/*****************
2554  Code to support firewall punching.  This shouldn't really be in this
2555  file, but making variables global is evil too.
2556  ****************/
2557
2558/* Firewall include files */
2559#include <net/if.h>
2560#include <netinet/ip_fw.h>
2561#include <string.h>
2562#include <err.h>
2563
2564/*
2565 * helper function, updates the pointer to cmd with the length
2566 * of the current command, and also cleans up the first word of
2567 * the new command in case it has been clobbered before.
2568 */
2569static ipfw_insn *
2570next_cmd(ipfw_insn * cmd)
2571{
2572	cmd += F_LEN(cmd);
2573	bzero(cmd, sizeof(*cmd));
2574	return (cmd);
2575}
2576
2577/*
2578 * A function to fill simple commands of size 1.
2579 * Existing flags are preserved.
2580 */
2581static ipfw_insn *
2582fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2583    int flags, u_int16_t arg)
2584{
2585	cmd->opcode = opcode;
2586	cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2587	cmd->arg1 = arg;
2588	return next_cmd(cmd);
2589}
2590
2591static ipfw_insn *
2592fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2593{
2594	ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2595
2596	cmd->addr.s_addr = addr;
2597	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2598}
2599
2600static ipfw_insn *
2601fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2602{
2603	ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2604
2605	cmd->ports[0] = cmd->ports[1] = port;
2606	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2607}
2608
2609static int
2610fill_rule(void *buf, int bufsize, int rulenum,
2611    enum ipfw_opcodes action, int proto,
2612    struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2613{
2614	struct ip_fw *rule = (struct ip_fw *)buf;
2615	ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2616
2617	bzero(buf, bufsize);
2618	rule->rulenum = rulenum;
2619
2620	cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2621	cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2622	cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2623	cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2624	cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2625
2626	rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2627	cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2628
2629	rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2630
2631	return ((char *)cmd - (char *)buf);
2632}
2633
2634static void ClearAllFWHoles(struct libalias *la);
2635
2636#define fw_setfield(la, field, num)			\
2637do {						\
2638    (field)[(num) - la->fireWallBaseNum] = 1;		\
2639} /*lint -save -e717 */ while(0)/* lint -restore */
2640
2641#define fw_clrfield(la, field, num)			\
2642do {							\
2643    (field)[(num) - la->fireWallBaseNum] = 0;		\
2644} /*lint -save -e717 */ while(0)/* lint -restore */
2645
2646#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2647
2648static void
2649InitPunchFW(struct libalias *la)
2650{
2651	la->fireWallField = malloc(la->fireWallNumNums);
2652	if (la->fireWallField) {
2653		memset(la->fireWallField, 0, la->fireWallNumNums);
2654		if (la->fireWallFD < 0) {
2655			la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2656		}
2657		ClearAllFWHoles(la);
2658		la->fireWallActiveNum = la->fireWallBaseNum;
2659	}
2660}
2661
2662static void
2663UninitPunchFW(struct libalias *la)
2664{
2665	ClearAllFWHoles(la);
2666	if (la->fireWallFD >= 0)
2667		close(la->fireWallFD);
2668	la->fireWallFD = -1;
2669	if (la->fireWallField)
2670		free(la->fireWallField);
2671	la->fireWallField = NULL;
2672	la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2673}
2674
2675/* Make a certain link go through the firewall */
2676void
2677PunchFWHole(struct alias_link *lnk)
2678{
2679	struct libalias *la;
2680	int r;			/* Result code */
2681	struct ip_fw rule;	/* On-the-fly built rule */
2682	int fwhole;		/* Where to punch hole */
2683
2684	la = lnk->la;
2685
2686	/* Don't do anything unless we are asked to */
2687	if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2688	    la->fireWallFD < 0 ||
2689	    lnk->link_type != LINK_TCP)
2690		return;
2691
2692	memset(&rule, 0, sizeof rule);
2693
2694	/** Build rule **/
2695
2696	/* Find empty slot */
2697	for (fwhole = la->fireWallActiveNum;
2698	    fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2699	    fw_tstfield(la, la->fireWallField, fwhole);
2700	    fwhole++);
2701	if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2702		for (fwhole = la->fireWallBaseNum;
2703		    fwhole < la->fireWallActiveNum &&
2704		    fw_tstfield(la, la->fireWallField, fwhole);
2705		    fwhole++);
2706		if (fwhole == la->fireWallActiveNum) {
2707			/* No rule point empty - we can't punch more holes. */
2708			la->fireWallActiveNum = la->fireWallBaseNum;
2709#ifdef LIBALIAS_DEBUG
2710			fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2711#endif
2712			return;
2713		}
2714	}
2715	/* Start next search at next position */
2716	la->fireWallActiveNum = fwhole + 1;
2717
2718	/*
2719	 * generate two rules of the form
2720	 *
2721	 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2722	 * accept tcp from DAddr DPort to OAddr OPort
2723	 */
2724	if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2725		u_int32_t rulebuf[255];
2726		int i;
2727
2728		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2729		    O_ACCEPT, IPPROTO_TCP,
2730		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2731		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2732		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2733		if (r)
2734			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2735
2736		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2737		    O_ACCEPT, IPPROTO_TCP,
2738		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2739		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2740		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2741		if (r)
2742			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2743	}
2744
2745	/* Indicate hole applied */
2746	lnk->data.tcp->fwhole = fwhole;
2747	fw_setfield(la, la->fireWallField, fwhole);
2748}
2749
2750/* Remove a hole in a firewall associated with a particular alias
2751   lnk.  Calling this too often is harmless. */
2752static void
2753ClearFWHole(struct alias_link *lnk)
2754{
2755	struct libalias *la;
2756
2757	la = lnk->la;
2758	if (lnk->link_type == LINK_TCP) {
2759		int fwhole = lnk->data.tcp->fwhole;  /* Where is the firewall hole? */
2760		struct ip_fw rule;
2761
2762		if (fwhole < 0)
2763			return;
2764
2765		memset(&rule, 0, sizeof rule);	/* useless for ipfw2 */
2766		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2767		    &fwhole, sizeof fwhole));
2768		fw_clrfield(la, la->fireWallField, fwhole);
2769		lnk->data.tcp->fwhole = -1;
2770	}
2771}
2772
2773/* Clear out the entire range dedicated to firewall holes. */
2774static void
2775ClearAllFWHoles(struct libalias *la)
2776{
2777	struct ip_fw rule;	/* On-the-fly built rule */
2778	int i;
2779
2780	if (la->fireWallFD < 0)
2781		return;
2782
2783	memset(&rule, 0, sizeof rule);
2784	for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2785		int r = i;
2786
2787		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2788	}
2789	/* XXX: third arg correct here ? /phk */
2790	memset(la->fireWallField, 0, la->fireWallNumNums);
2791}
2792
2793#endif /* !NO_FW_PUNCH */
2794
2795void
2796LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2797{
2798	LIBALIAS_LOCK(la);
2799#ifndef NO_FW_PUNCH
2800	la->fireWallBaseNum = base;
2801	la->fireWallNumNums = num;
2802#endif
2803	LIBALIAS_UNLOCK(la);
2804}
2805
2806void
2807LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2808{
2809	LIBALIAS_LOCK(la);
2810	la->skinnyPort = port;
2811	LIBALIAS_UNLOCK(la);
2812}
2813
2814/*
2815 * Find the address to redirect incoming packets
2816 */
2817struct in_addr
2818FindSctpRedirectAddress(struct libalias *la,  struct sctp_nat_msg *sm)
2819{
2820	struct alias_link *lnk;
2821	struct in_addr redir;
2822
2823	LIBALIAS_LOCK_ASSERT(la);
2824	lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2825	    sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2826	if (lnk != NULL) {
2827		/* port redirect */
2828		return (lnk->src_addr);
2829	} else {
2830		redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2831		if (redir.s_addr == la->aliasAddress.s_addr ||
2832		    redir.s_addr == la->targetAddress.s_addr) {
2833			/* No address found */
2834			lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2835			    NO_DEST_PORT, 0, LINK_SCTP, 1);
2836			if (lnk != NULL)
2837				/* redirect proto */
2838				return (lnk->src_addr);
2839		}
2840		return (redir); /* address redirect */
2841	}
2842}
2843