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