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