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