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