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