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