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