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