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