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