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