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