xref: /freebsd/sys/netinet/libalias/alias_db.c (revision d37ea99837e6ad50837fd9fe1771ddf1c3ba6002)
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 *la);
358 static void	UninitPunchFW(struct libalias *la);
359 static void	ClearFWHole(struct alias_link *link);
360 
361 #endif
362 
363 /* Log file control */
364 static void	InitPacketAliasLog(struct libalias *la);
365 static void	UninitPacketAliasLog(struct libalias *la);
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 *link, 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 = link->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 		link->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, link->dst_addr, link->alias_addr,
568 		    link->dst_port, port_net,
569 		    link->link_type, 0);
570 
571 		if (search_result == NULL)
572 			go_ahead = 1;
573 		else if (!(link->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 			    && (link->flags & LINK_PARTIALLY_SPECIFIED)
582 			    && ((link->link_type == LINK_TCP) ||
583 			    (link->link_type == LINK_UDP))) {
584 				if (GetSocket(la, port_net, &link->sockfd, link->link_type)) {
585 					link->alias_port = port_net;
586 					return (0);
587 				}
588 			} else {
589 				link->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 *link;
749 	int i, icount;
750 
751 	icount = 0;
752 	for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
753 		link = LIST_FIRST(&la->linkTableOut[i]);
754 		while (link != NULL) {
755 			struct alias_link *link_next;
756 
757 			link_next = LIST_NEXT(link, list_out);
758 			icount++;
759 			DeleteLink(link);
760 			link = 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 *link;
773 
774 	icount = 0;
775 	link = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
776 	while (link != NULL) {
777 		int idelta;
778 		struct alias_link *link_next;
779 
780 		link_next = LIST_NEXT(link, list_out);
781 		idelta = la->timeStamp - link->timestamp;
782 		switch (link->link_type) {
783 		case LINK_TCP:
784 			if (idelta > link->expire_time) {
785 				struct tcp_dat *tcp_aux;
786 
787 				tcp_aux = link->data.tcp;
788 				if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
789 				    || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) {
790 					DeleteLink(link);
791 					icount++;
792 				}
793 			}
794 			break;
795 		default:
796 			if (idelta > link->expire_time) {
797 				DeleteLink(link);
798 				icount++;
799 			}
800 			break;
801 		}
802 		link = 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 *link)
811 {
812 	struct libalias *la = link->la;
813 
814 /* Don't do anything if the link is marked permanent */
815 	if (la->deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
816 		return;
817 
818 #ifndef NO_FW_PUNCH
819 /* Delete associated firewall hole, if any */
820 	ClearFWHole(link);
821 #endif
822 
823 /* Free memory allocated for LSNAT server pool */
824 	if (link->server != NULL) {
825 		struct server *head, *curr, *next;
826 
827 		head = curr = link->server;
828 		do {
829 			next = curr->next;
830 			free(curr);
831 		} while ((curr = next) != head);
832 	}
833 /* Adjust output table pointers */
834 	LIST_REMOVE(link, list_out);
835 
836 /* Adjust input table pointers */
837 	LIST_REMOVE(link, list_in);
838 
839 /* Close socket, if one has been allocated */
840 	if (link->sockfd != -1) {
841 		la->sockCount--;
842 		close(link->sockfd);
843 	}
844 /* Link-type dependent cleanup */
845 	switch (link->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(link->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 (link->data.frag_ptr != NULL)
865 			free(link->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(link);
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 *link;
896 
897 	link = malloc(sizeof(struct alias_link));
898 	if (link != NULL) {
899 		/* Basic initialization */
900 		link->la = la;
901 		link->src_addr = src_addr;
902 		link->dst_addr = dst_addr;
903 		link->alias_addr = alias_addr;
904 		link->proxy_addr.s_addr = INADDR_ANY;
905 		link->src_port = src_port;
906 		link->dst_port = dst_port;
907 		link->proxy_port = 0;
908 		link->server = NULL;
909 		link->link_type = link_type;
910 		link->sockfd = -1;
911 		link->flags = 0;
912 		link->pflags = 0;
913 		link->timestamp = la->timeStamp;
914 
915 		/* Expiration time */
916 		switch (link_type) {
917 		case LINK_ICMP:
918 			link->expire_time = ICMP_EXPIRE_TIME;
919 			break;
920 		case LINK_UDP:
921 			link->expire_time = UDP_EXPIRE_TIME;
922 			break;
923 		case LINK_TCP:
924 			link->expire_time = TCP_EXPIRE_INITIAL;
925 			break;
926 		case LINK_PPTP:
927 			link->flags |= LINK_PERMANENT;	/* no timeout. */
928 			break;
929 		case LINK_FRAGMENT_ID:
930 			link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
931 			break;
932 		case LINK_FRAGMENT_PTR:
933 			link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
934 			break;
935 		case LINK_ADDR:
936 			break;
937 		default:
938 			link->expire_time = PROTO_EXPIRE_TIME;
939 			break;
940 		}
941 
942 		/* Determine alias flags */
943 		if (dst_addr.s_addr == INADDR_ANY)
944 			link->flags |= LINK_UNKNOWN_DEST_ADDR;
945 		if (dst_port == 0)
946 			link->flags |= LINK_UNKNOWN_DEST_PORT;
947 
948 		/* Determine alias port */
949 		if (GetNewPort(la, link, alias_port_param) != 0) {
950 			free(link);
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 				link->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(link);
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], link, list_out);
1006 
1007 		/* Set up pointers for input lookup table */
1008 		start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1009 		LIST_INSERT_HEAD(&la->linkTableIn[start_point], link, 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 (link);
1021 }
1022 
1023 static struct alias_link *
1024 ReLink(struct alias_link *old_link,
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_link;	/* zero, equal to alias port  */
1035 	struct libalias *la = old_link->la;
1036 
1037 	new_link = 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_link != NULL &&
1042 	    old_link->link_type == LINK_TCP &&
1043 	    old_link->data.tcp->fwhole > 0) {
1044 		PunchFWHole(new_link);
1045 	}
1046 #endif
1047 	DeleteLink(old_link);
1048 	return new_link;
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 *link;
1061 
1062 	i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1063 	LIST_FOREACH(link, &la->linkTableOut[i], list_out) {
1064 		if (link->src_addr.s_addr == src_addr.s_addr
1065 		    && link->server == NULL
1066 		    && link->dst_addr.s_addr == dst_addr.s_addr
1067 		    && link->dst_port == dst_port
1068 		    && link->src_port == src_port
1069 		    && link->link_type == link_type) {
1070 			link->timestamp = la->timeStamp;
1071 			break;
1072 		}
1073 	}
1074 
1075 /* Search for partially specified links. */
1076 	if (link == NULL && replace_partial_links) {
1077 		if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1078 			link = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1079 			    link_type, 0);
1080 			if (link == NULL)
1081 				link = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1082 				    dst_port, link_type, 0);
1083 		}
1084 		if (link == NULL &&
1085 		    (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1086 			link = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1087 			    link_type, 0);
1088 		}
1089 		if (link != NULL) {
1090 			link = ReLink(link,
1091 			    src_addr, dst_addr, link->alias_addr,
1092 			    src_port, dst_port, link->alias_port,
1093 			    link_type);
1094 		}
1095 	}
1096 	return (link);
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 *link;
1108 
1109 	link = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1110 	    link_type, replace_partial_links);
1111 
1112 	if (link == 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 			link = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1122 			    link_type, replace_partial_links);
1123 		}
1124 	}
1125 	return (link);
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 *link;
1140 	struct alias_link *link_fully_specified;
1141 	struct alias_link *link_unknown_all;
1142 	struct alias_link *link_unknown_dst_addr;
1143 	struct alias_link *link_unknown_dst_port;
1144 
1145 /* Initialize pointers */
1146 	link_fully_specified = NULL;
1147 	link_unknown_all = NULL;
1148 	link_unknown_dst_addr = NULL;
1149 	link_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(link, &la->linkTableIn[start_point], list_in) {
1163 		int flags;
1164 
1165 		flags = flags_in | link->flags;
1166 		if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1167 			if (link->alias_addr.s_addr == alias_addr.s_addr
1168 			    && link->alias_port == alias_port
1169 			    && link->dst_addr.s_addr == dst_addr.s_addr
1170 			    && link->dst_port == dst_port
1171 			    && link->link_type == link_type) {
1172 				link_fully_specified = link;
1173 				break;
1174 			}
1175 		} else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1176 		    && (flags & LINK_UNKNOWN_DEST_PORT)) {
1177 			if (link->alias_addr.s_addr == alias_addr.s_addr
1178 			    && link->alias_port == alias_port
1179 			    && link->link_type == link_type) {
1180 				if (link_unknown_all == NULL)
1181 					link_unknown_all = link;
1182 			}
1183 		} else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1184 			if (link->alias_addr.s_addr == alias_addr.s_addr
1185 			    && link->alias_port == alias_port
1186 			    && link->link_type == link_type
1187 			    && link->dst_port == dst_port) {
1188 				if (link_unknown_dst_addr == NULL)
1189 					link_unknown_dst_addr = link;
1190 			}
1191 		} else if (flags & LINK_UNKNOWN_DEST_PORT) {
1192 			if (link->alias_addr.s_addr == alias_addr.s_addr
1193 			    && link->alias_port == alias_port
1194 			    && link->link_type == link_type
1195 			    && link->dst_addr.s_addr == dst_addr.s_addr) {
1196 				if (link_unknown_dst_port == NULL)
1197 					link_unknown_dst_port = link;
1198 			}
1199 		}
1200 	}
1201 
1202 
1203 
1204 	if (link_fully_specified != NULL) {
1205 		link_fully_specified->timestamp = la->timeStamp;
1206 		link = link_fully_specified;
1207 	} else if (link_unknown_dst_port != NULL)
1208 		link = link_unknown_dst_port;
1209 	else if (link_unknown_dst_addr != NULL)
1210 		link = link_unknown_dst_addr;
1211 	else if (link_unknown_all != NULL)
1212 		link = link_unknown_all;
1213 	else
1214 		return (NULL);
1215 
1216 	if (replace_partial_links &&
1217 	    (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) {
1218 		struct in_addr src_addr;
1219 		u_short src_port;
1220 
1221 		if (link->server != NULL) {	/* LSNAT link */
1222 			src_addr = link->server->addr;
1223 			src_port = link->server->port;
1224 			link->server = link->server->next;
1225 		} else {
1226 			src_addr = link->src_addr;
1227 			src_port = link->src_port;
1228 		}
1229 
1230 		link = ReLink(link,
1231 		    src_addr, dst_addr, alias_addr,
1232 		    src_port, dst_port, alias_port,
1233 		    link_type);
1234 	}
1235 	return (link);
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 *link;
1247 
1248 	link = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1249 	    link_type, replace_partial_links);
1250 
1251 	if (link == 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 			link = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1261 			    link_type, replace_partial_links);
1262 		}
1263 	}
1264 	return (link);
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 *link;
1294 
1295 	link = FindLinkIn(la, dst_addr, alias_addr,
1296 	    NO_DEST_PORT, id_alias,
1297 	    LINK_ICMP, 0);
1298 	if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1299 		struct in_addr target_addr;
1300 
1301 		target_addr = FindOriginalAddress(la, alias_addr);
1302 		link = AddLink(la, target_addr, dst_addr, alias_addr,
1303 		    id_alias, NO_DEST_PORT, id_alias,
1304 		    LINK_ICMP);
1305 	}
1306 	return (link);
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 *link;
1317 
1318 	link = FindLinkOut(la, src_addr, dst_addr,
1319 	    id, NO_DEST_PORT,
1320 	    LINK_ICMP, 0);
1321 	if (link == NULL && create) {
1322 		struct in_addr alias_addr;
1323 
1324 		alias_addr = FindAliasAddress(la, src_addr);
1325 		link = AddLink(la, src_addr, dst_addr, alias_addr,
1326 		    id, NO_DEST_PORT, GET_ALIAS_ID,
1327 		    LINK_ICMP);
1328 	}
1329 	return (link);
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 *link;
1339 
1340 	link = FindLinkIn(la, dst_addr, alias_addr,
1341 	    NO_DEST_PORT, ip_id,
1342 	    LINK_FRAGMENT_ID, 0);
1343 
1344 	if (link == NULL) {
1345 		link = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1346 		    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1347 		    LINK_FRAGMENT_ID);
1348 	}
1349 	return (link);
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 *link;
1391 
1392 	link = FindLinkIn(la, dst_addr, alias_addr,
1393 	    NO_DEST_PORT, 0,
1394 	    proto, 1);
1395 
1396 	if (link == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1397 		struct in_addr target_addr;
1398 
1399 		target_addr = FindOriginalAddress(la, alias_addr);
1400 		link = AddLink(la, target_addr, dst_addr, alias_addr,
1401 		    NO_SRC_PORT, NO_DEST_PORT, 0,
1402 		    proto);
1403 	}
1404 	return (link);
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 *link;
1414 
1415 	link = FindLinkOut(la, src_addr, dst_addr,
1416 	    NO_SRC_PORT, NO_DEST_PORT,
1417 	    proto, 1);
1418 
1419 	if (link == NULL) {
1420 		struct in_addr alias_addr;
1421 
1422 		alias_addr = FindAliasAddress(la, src_addr);
1423 		link = AddLink(la, src_addr, dst_addr, alias_addr,
1424 		    NO_SRC_PORT, NO_DEST_PORT, 0,
1425 		    proto);
1426 	}
1427 	return (link);
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 *link;
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 	link = FindLinkIn(la, dst_addr, alias_addr,
1455 	    dst_port, alias_port,
1456 	    link_type, create);
1457 
1458 	if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1459 		struct in_addr target_addr;
1460 
1461 		target_addr = FindOriginalAddress(la, alias_addr);
1462 		link = AddLink(la, target_addr, dst_addr, alias_addr,
1463 		    alias_port, dst_port, alias_port,
1464 		    link_type);
1465 	}
1466 	return (link);
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 *link;
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 	link = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1494 
1495 	if (link == NULL && create) {
1496 		struct in_addr alias_addr;
1497 
1498 		alias_addr = FindAliasAddress(la, src_addr);
1499 		link = AddLink(la, src_addr, dst_addr, alias_addr,
1500 		    src_port, dst_port, GET_ALIAS_PORT,
1501 		    link_type);
1502 	}
1503 	return (link);
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 *link;
1514 
1515 	link = AddLink(la, src_addr, dst_addr, alias_addr,
1516 	    src_call_id, 0, GET_ALIAS_PORT,
1517 	    LINK_PPTP);
1518 
1519 	return (link);
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 *link;
1530 
1531 	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1532 	LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1533 	    if (link->link_type == LINK_PPTP &&
1534 	    link->src_addr.s_addr == src_addr.s_addr &&
1535 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1536 	    link->src_port == src_call_id)
1537 		break;
1538 
1539 	return (link);
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 *link;
1550 
1551 	i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1552 	LIST_FOREACH(link, &la->linkTableOut[i], list_out)
1553 	    if (link->link_type == LINK_PPTP &&
1554 	    link->src_addr.s_addr == src_addr.s_addr &&
1555 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1556 	    link->dst_port == dst_call_id)
1557 		break;
1558 
1559 	return (link);
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 *link;
1570 
1571 	i = StartPointIn(alias_addr, 0, LINK_PPTP);
1572 	LIST_FOREACH(link, &la->linkTableIn[i], list_in)
1573 	    if (link->link_type == LINK_PPTP &&
1574 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1575 	    link->alias_addr.s_addr == alias_addr.s_addr &&
1576 	    link->dst_port == dst_call_id)
1577 		break;
1578 
1579 	return (link);
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 *link;
1589 
1590 	link = FindLinkIn(la, dst_addr, alias_addr,
1591 	    0 /* any */ , alias_call_id,
1592 	    LINK_PPTP, 0);
1593 
1594 
1595 	return (link);
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 *link;
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 	link = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1622 
1623 	if (link == NULL) {
1624 		struct in_addr alias_addr;
1625 
1626 		alias_addr = FindAliasAddress(la, src_addr);
1627 		link = AddLink(la, src_addr, dst_addr, alias_addr,
1628 		    src_port, 0, alias_port,
1629 		    link_type);
1630 	}
1631 	return (link);
1632 }
1633 
1634 
1635 struct in_addr
1636 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1637 {
1638 	struct alias_link *link;
1639 
1640 	link = FindLinkIn(la, la->nullAddress, alias_addr,
1641 	    0, 0, LINK_ADDR, 0);
1642 	if (link == 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 (link->server != NULL) {	/* LSNAT link */
1653 			struct in_addr src_addr;
1654 
1655 			src_addr = link->server->addr;
1656 			link->server = link->server->next;
1657 			return (src_addr);
1658 		} else if (link->src_addr.s_addr == INADDR_ANY)
1659 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1660 			    la->aliasAddress : alias_addr;
1661 		else
1662 			return link->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 *link;
1671 
1672 	link = FindLinkOut(la, original_addr, la->nullAddress,
1673 	    0, 0, LINK_ADDR, 0);
1674 	if (link == NULL) {
1675 		return (la->aliasAddress.s_addr != INADDR_ANY) ?
1676 		    la->aliasAddress : original_addr;
1677 	} else {
1678 		if (link->alias_addr.s_addr == INADDR_ANY)
1679 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1680 			    la->aliasAddress : original_addr;
1681 		else
1682 			return link->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 *link, struct in_addr src_addr)
1704 {
1705 	link->data.frag_addr = src_addr;
1706 }
1707 
1708 
1709 void
1710 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1711 {
1712 	*src_addr = link->data.frag_addr;
1713 }
1714 
1715 
1716 void
1717 SetFragmentPtr(struct alias_link *link, char *fptr)
1718 {
1719 	link->data.frag_ptr = fptr;
1720 }
1721 
1722 
1723 void
1724 GetFragmentPtr(struct alias_link *link, char **fptr)
1725 {
1726 	*fptr = link->data.frag_ptr;
1727 }
1728 
1729 
1730 void
1731 SetStateIn(struct alias_link *link, int state)
1732 {
1733 	/* TCP input state */
1734 	switch (state) {
1735 		case ALIAS_TCP_STATE_DISCONNECTED:
1736 		if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1737 			link->expire_time = TCP_EXPIRE_DEAD;
1738 		else
1739 			link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1740 		break;
1741 	case ALIAS_TCP_STATE_CONNECTED:
1742 		if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1743 			link->expire_time = TCP_EXPIRE_CONNECTED;
1744 		break;
1745 	default:
1746 		abort();
1747 	}
1748 	link->data.tcp->state.in = state;
1749 }
1750 
1751 
1752 void
1753 SetStateOut(struct alias_link *link, int state)
1754 {
1755 	/* TCP output state */
1756 	switch (state) {
1757 		case ALIAS_TCP_STATE_DISCONNECTED:
1758 		if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1759 			link->expire_time = TCP_EXPIRE_DEAD;
1760 		else
1761 			link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1762 		break;
1763 	case ALIAS_TCP_STATE_CONNECTED:
1764 		if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1765 			link->expire_time = TCP_EXPIRE_CONNECTED;
1766 		break;
1767 	default:
1768 		abort();
1769 	}
1770 	link->data.tcp->state.out = state;
1771 }
1772 
1773 
1774 int
1775 GetStateIn(struct alias_link *link)
1776 {
1777 	/* TCP input state */
1778 	return link->data.tcp->state.in;
1779 }
1780 
1781 
1782 int
1783 GetStateOut(struct alias_link *link)
1784 {
1785 	/* TCP output state */
1786 	return link->data.tcp->state.out;
1787 }
1788 
1789 
1790 struct in_addr
1791 GetOriginalAddress(struct alias_link *link)
1792 {
1793 	if (link->src_addr.s_addr == INADDR_ANY)
1794 		return link->la->aliasAddress;
1795 	else
1796 		return (link->src_addr);
1797 }
1798 
1799 
1800 struct in_addr
1801 GetDestAddress(struct alias_link *link)
1802 {
1803 	return (link->dst_addr);
1804 }
1805 
1806 
1807 struct in_addr
1808 GetAliasAddress(struct alias_link *link)
1809 {
1810 	if (link->alias_addr.s_addr == INADDR_ANY)
1811 		return link->la->aliasAddress;
1812 	else
1813 		return link->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 *link)
1833 {
1834 	return (link->src_port);
1835 }
1836 
1837 
1838 u_short
1839 GetAliasPort(struct alias_link *link)
1840 {
1841 	return (link->alias_port);
1842 }
1843 
1844 #ifndef NO_FW_PUNCH
1845 static		u_short
1846 GetDestPort(struct alias_link *link)
1847 {
1848 	return (link->dst_port);
1849 }
1850 
1851 #endif
1852 
1853 void
1854 SetAckModified(struct alias_link *link)
1855 {
1856 /* Indicate that ACK numbers have been modified in a TCP connection */
1857 	link->data.tcp->state.ack_modified = 1;
1858 }
1859 
1860 
1861 struct in_addr
1862 GetProxyAddress(struct alias_link *link)
1863 {
1864 	return link->proxy_addr;
1865 }
1866 
1867 
1868 void
1869 SetProxyAddress(struct alias_link *link, struct in_addr addr)
1870 {
1871 	link->proxy_addr = addr;
1872 }
1873 
1874 
1875 u_short
1876 GetProxyPort(struct alias_link *link)
1877 {
1878 	return link->proxy_port;
1879 }
1880 
1881 
1882 void
1883 SetProxyPort(struct alias_link *link, u_short port)
1884 {
1885 	link->proxy_port = port;
1886 }
1887 
1888 
1889 int
1890 GetAckModified(struct alias_link *link)
1891 {
1892 /* See if ACK numbers have been modified */
1893 	return link->data.tcp->state.ack_modified;
1894 }
1895 
1896 
1897 int
1898 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
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 = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
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 = link->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 *link)
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 = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
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 = link->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 *link, 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 = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
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 = link->data.tcp->state.index;
2011 	link->data.tcp->ack[i] = x;
2012 
2013 	i++;
2014 	if (i == N_LINK_TCP_DATA)
2015 		link->data.tcp->state.index = 0;
2016 	else
2017 		link->data.tcp->state.index = i;
2018 }
2019 
2020 void
2021 SetExpire(struct alias_link *link, int expire)
2022 {
2023 	if (expire == 0) {
2024 		link->flags &= ~LINK_PERMANENT;
2025 		DeleteLink(link);
2026 	} else if (expire == -1) {
2027 		link->flags |= LINK_PERMANENT;
2028 	} else if (expire > 0) {
2029 		link->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 *link, int pflags)
2046 {
2047 
2048 	link->pflags = pflags;;
2049 }
2050 
2051 int
2052 GetProtocolFlags(struct alias_link *link)
2053 {
2054 
2055 	return (link->pflags);
2056 }
2057 
2058 void
2059 SetDestCallId(struct alias_link *link, u_int16_t cid)
2060 {
2061 	struct libalias *la = link->la;
2062 
2063 	la->deleteAllLinks = 1;
2064 	link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2065 	    link->src_port, cid, link->alias_port, link->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 *link;
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 	link = AddLink(la, src_addr, dst_addr, alias_addr,
2207 	    src_port, dst_port, alias_port,
2208 	    link_type);
2209 
2210 	if (link != NULL) {
2211 		link->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 link;
2221 }
2222 
2223 /* Add server to the pool of servers */
2224 int
2225 LibAliasAddServer(struct libalias *la, struct alias_link *link, struct in_addr addr, u_short port)
2226 {
2227 	struct server *server;
2228 
2229 	server = malloc(sizeof(struct server));
2230 
2231 	if (server != NULL) {
2232 		struct server *head;
2233 
2234 		server->addr = addr;
2235 		server->port = port;
2236 
2237 		head = link->server;
2238 		if (head == NULL)
2239 			server->next = server;
2240 		else {
2241 			struct server *s;
2242 
2243 			for (s = head; s->next != head; s = s->next);
2244 			s->next = server;
2245 			server->next = head;
2246 		}
2247 		link->server = server;
2248 		return (0);
2249 	} else
2250 		return (-1);
2251 }
2252 
2253 /* Redirect packets of a given IP protocol from a specific
2254    public address to a private address */
2255 struct alias_link *
2256 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2257     struct in_addr dst_addr,
2258     struct in_addr alias_addr,
2259     u_char proto)
2260 {
2261 	struct alias_link *link;
2262 
2263 	link = AddLink(la, src_addr, dst_addr, alias_addr,
2264 	    NO_SRC_PORT, NO_DEST_PORT, 0,
2265 	    proto);
2266 
2267 	if (link != NULL) {
2268 		link->flags |= LINK_PERMANENT;
2269 	}
2270 #ifdef DEBUG
2271 	else {
2272 		fprintf(stderr, "PacketAliasRedirectProto(): "
2273 		    "call to AddLink() failed\n");
2274 	}
2275 #endif
2276 
2277 	return link;
2278 }
2279 
2280 /* Static address translation */
2281 struct alias_link *
2282 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2283     struct in_addr alias_addr)
2284 {
2285 	struct alias_link *link;
2286 
2287 	link = AddLink(la, src_addr, la->nullAddress, alias_addr,
2288 	    0, 0, 0,
2289 	    LINK_ADDR);
2290 
2291 	if (link != NULL) {
2292 		link->flags |= LINK_PERMANENT;
2293 	}
2294 #ifdef DEBUG
2295 	else {
2296 		fprintf(stderr, "PacketAliasRedirectAddr(): "
2297 		    "call to AddLink() failed\n");
2298 	}
2299 #endif
2300 
2301 	return link;
2302 }
2303 
2304 
2305 /* Mark the aliasing link dynamic */
2306 int
2307 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *link)
2308 {
2309 
2310 	if (link->flags & LINK_PARTIALLY_SPECIFIED)
2311 		return (-1);
2312 	else {
2313 		link->flags &= ~LINK_PERMANENT;
2314 		return (0);
2315 	}
2316 }
2317 
2318 
2319 void
2320 LibAliasRedirectDelete(struct libalias *la, struct alias_link *link)
2321 {
2322 /* This is a dangerous function to put in the API,
2323    because an invalid pointer can crash the program. */
2324 
2325 	la->deleteAllLinks = 1;
2326 	DeleteLink(link);
2327 	la->deleteAllLinks = 0;
2328 }
2329 
2330 
2331 void
2332 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2333 {
2334 	if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2335 	    && la->aliasAddress.s_addr != addr.s_addr)
2336 		CleanupAliasData(la);
2337 
2338 	la->aliasAddress = addr;
2339 }
2340 
2341 
2342 void
2343 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2344 {
2345 	la->targetAddress = target_addr;
2346 }
2347 
2348 static void
2349 finishoff(void)
2350 {
2351 
2352 	while (!LIST_EMPTY(&instancehead))
2353 		LibAliasUninit(LIST_FIRST(&instancehead));
2354 }
2355 
2356 struct libalias *
2357 LibAliasInit(struct libalias *la)
2358 {
2359 	int i;
2360 	struct timeval tv;
2361 	struct timezone tz;
2362 
2363 	if (la == NULL) {
2364 		la = calloc(sizeof *la, 1);
2365 		if (la == NULL)
2366 			return (la);
2367 		if (LIST_EMPTY(&instancehead))
2368 			atexit(finishoff);
2369 		LIST_INSERT_HEAD(&instancehead, la, instancelist);
2370 
2371 		gettimeofday(&tv, &tz);
2372 		la->timeStamp = tv.tv_sec;
2373 		la->lastCleanupTime = tv.tv_sec;
2374 		la->houseKeepingResidual = 0;
2375 
2376 		for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2377 			LIST_INIT(&la->linkTableOut[i]);
2378 		for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2379 			LIST_INIT(&la->linkTableIn[i]);
2380 
2381 	} else {
2382 		la->deleteAllLinks = 1;
2383 		CleanupAliasData(la);
2384 		la->deleteAllLinks = 0;
2385 	}
2386 
2387 	la->aliasAddress.s_addr = INADDR_ANY;
2388 	la->targetAddress.s_addr = INADDR_ANY;
2389 
2390 	la->icmpLinkCount = 0;
2391 	la->udpLinkCount = 0;
2392 	la->tcpLinkCount = 0;
2393 	la->pptpLinkCount = 0;
2394 	la->protoLinkCount = 0;
2395 	la->fragmentIdLinkCount = 0;
2396 	la->fragmentPtrLinkCount = 0;
2397 	la->sockCount = 0;
2398 
2399 	la->cleanupIndex = 0;
2400 
2401 	la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2402 	    | PKT_ALIAS_USE_SOCKETS
2403 	    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2404 #ifndef NO_FW_PUNCH
2405 	la->fireWallFD = -1;
2406 #endif
2407 	return (la);
2408 }
2409 
2410 void
2411 LibAliasUninit(struct libalias *la)
2412 {
2413 	la->deleteAllLinks = 1;
2414 	CleanupAliasData(la);
2415 	la->deleteAllLinks = 0;
2416 	UninitPacketAliasLog(la);
2417 #ifndef NO_FW_PUNCH
2418 	UninitPunchFW(la);
2419 #endif
2420 	LIST_REMOVE(la, instancelist);
2421 	free(la);
2422 }
2423 
2424 /* Change mode for some operations */
2425 unsigned int
2426 LibAliasSetMode(
2427     struct libalias *la,
2428     unsigned int flags,		/* Which state to bring flags to */
2429     unsigned int mask		/* Mask of which flags to affect (use 0 to
2430 				 * do a probe for flag values) */
2431 )
2432 {
2433 /* Enable logging? */
2434 	if (flags & mask & PKT_ALIAS_LOG) {
2435 		InitPacketAliasLog(la);	/* Do the enable */
2436 	} else
2437 /* _Disable_ logging? */
2438 	if (~flags & mask & PKT_ALIAS_LOG) {
2439 		UninitPacketAliasLog(la);
2440 	}
2441 #ifndef NO_FW_PUNCH
2442 /* Start punching holes in the firewall? */
2443 	if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2444 		InitPunchFW(la);
2445 	} else
2446 /* Stop punching holes in the firewall? */
2447 	if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2448 		UninitPunchFW(la);
2449 	}
2450 #endif
2451 
2452 /* Other flags can be set/cleared without special action */
2453 	la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2454 	return la->packetAliasMode;
2455 }
2456 
2457 
2458 int
2459 LibAliasCheckNewLink(struct libalias *la)
2460 {
2461 	return la->newDefaultLink;
2462 }
2463 
2464 
2465 #ifndef NO_FW_PUNCH
2466 
2467 /*****************
2468   Code to support firewall punching.  This shouldn't really be in this
2469   file, but making variables global is evil too.
2470   ****************/
2471 
2472 #ifndef IPFW2
2473 #define IPFW2	1		/* use new ipfw code */
2474 #endif
2475 
2476 /* Firewall include files */
2477 #include <net/if.h>
2478 #include <netinet/ip_fw.h>
2479 #include <string.h>
2480 #include <err.h>
2481 
2482 #if IPFW2			/* support for new firewall code */
2483 /*
2484  * helper function, updates the pointer to cmd with the length
2485  * of the current command, and also cleans up the first word of
2486  * the new command in case it has been clobbered before.
2487  */
2488 static ipfw_insn *
2489 next_cmd(ipfw_insn * cmd)
2490 {
2491 	cmd += F_LEN(cmd);
2492 	bzero(cmd, sizeof(*cmd));
2493 	return cmd;
2494 }
2495 
2496 /*
2497  * A function to fill simple commands of size 1.
2498  * Existing flags are preserved.
2499  */
2500 static ipfw_insn *
2501 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2502     int flags, u_int16_t arg)
2503 {
2504 	cmd->opcode = opcode;
2505 	cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2506 	cmd->arg1 = arg;
2507 	return next_cmd(cmd);
2508 }
2509 
2510 static ipfw_insn *
2511 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2512 {
2513 	ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2514 
2515 	cmd->addr.s_addr = addr;
2516 	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2517 }
2518 
2519 static ipfw_insn *
2520 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2521 {
2522 	ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2523 
2524 	cmd->ports[0] = cmd->ports[1] = port;
2525 	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2526 }
2527 
2528 static int
2529 fill_rule(void *buf, int bufsize, int rulenum,
2530     enum ipfw_opcodes action, int proto,
2531     struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2532 {
2533 	struct ip_fw *rule = (struct ip_fw *)buf;
2534 	ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2535 
2536 	bzero(buf, bufsize);
2537 	rule->rulenum = rulenum;
2538 
2539 	cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2540 	cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2541 	cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2542 	cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2543 	cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2544 
2545 	rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2546 	cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2547 
2548 	rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2549 
2550 	return ((char *)cmd - (char *)buf);
2551 }
2552 
2553 #endif				/* IPFW2 */
2554 
2555 static void	ClearAllFWHoles(struct libalias *la);
2556 
2557 
2558 #define fw_setfield(la, field, num)                         \
2559 do {                                                    \
2560     (field)[(num) - la->fireWallBaseNum] = 1;               \
2561 } /*lint -save -e717 */ while(0)/* lint -restore */
2562 
2563 #define fw_clrfield(la, field, num)                         \
2564 do {                                                    \
2565     (field)[(num) - la->fireWallBaseNum] = 0;               \
2566 } /*lint -save -e717 */ while(0)/* lint -restore */
2567 
2568 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2569 
2570 static void
2571 InitPunchFW(struct libalias *la)
2572 {
2573 
2574 	la->fireWallField = malloc(la->fireWallNumNums);
2575 	if (la->fireWallField) {
2576 		memset(la->fireWallField, 0, la->fireWallNumNums);
2577 		if (la->fireWallFD < 0) {
2578 			la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2579 		}
2580 		ClearAllFWHoles(la);
2581 		la->fireWallActiveNum = la->fireWallBaseNum;
2582 	}
2583 }
2584 
2585 static void
2586 UninitPunchFW(struct libalias *la)
2587 {
2588 	ClearAllFWHoles(la);
2589 	if (la->fireWallFD >= 0)
2590 		close(la->fireWallFD);
2591 	la->fireWallFD = -1;
2592 	if (la->fireWallField)
2593 		free(la->fireWallField);
2594 	la->fireWallField = NULL;
2595 	la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2596 }
2597 
2598 /* Make a certain link go through the firewall */
2599 void
2600 PunchFWHole(struct alias_link *link)
2601 {
2602 	struct libalias *la;
2603 	int r;			/* Result code */
2604 	struct ip_fw rule;	/* On-the-fly built rule */
2605 	int fwhole;		/* Where to punch hole */
2606 
2607 	la = link->la;
2608 
2609 /* Don't do anything unless we are asked to */
2610 	if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2611 	    la->fireWallFD < 0 ||
2612 	    link->link_type != LINK_TCP)
2613 		return;
2614 
2615 	memset(&rule, 0, sizeof rule);
2616 
2617 /** Build rule **/
2618 
2619 	/* Find empty slot */
2620 	for (fwhole = la->fireWallActiveNum;
2621 	    fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2622 	    fw_tstfield(la, la->fireWallField, fwhole);
2623 	    fwhole++);
2624 	if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2625 		for (fwhole = la->fireWallBaseNum;
2626 		    fwhole < la->fireWallActiveNum &&
2627 		    fw_tstfield(la, la->fireWallField, fwhole);
2628 		    fwhole++);
2629 		if (fwhole == la->fireWallActiveNum) {
2630 			/* No rule point empty - we can't punch more holes. */
2631 			la->fireWallActiveNum = la->fireWallBaseNum;
2632 #ifdef DEBUG
2633 			fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2634 #endif
2635 			return;
2636 		}
2637 	}
2638 	/* Start next search at next position */
2639 	la->fireWallActiveNum = fwhole + 1;
2640 
2641 	/*
2642 	 * generate two rules of the form
2643 	 *
2644 	 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2645 	 * accept tcp from DAddr DPort to OAddr OPort
2646 	 */
2647 #if IPFW2
2648 	if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
2649 		u_int32_t rulebuf[255];
2650 		int i;
2651 
2652 		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2653 		    O_ACCEPT, IPPROTO_TCP,
2654 		    GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
2655 		    GetDestAddress(link), ntohs(GetDestPort(link)));
2656 		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2657 		if (r)
2658 			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2659 
2660 		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2661 		    O_ACCEPT, IPPROTO_TCP,
2662 		    GetDestAddress(link), ntohs(GetDestPort(link)),
2663 		    GetOriginalAddress(link), ntohs(GetOriginalPort(link)));
2664 		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2665 		if (r)
2666 			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2667 	}
2668 #else				/* !IPFW2, old code to generate ipfw rule */
2669 
2670 	/* Build generic part of the two rules */
2671 	rule.fw_number = fwhole;
2672 	IP_FW_SETNSRCP(&rule, 1);	/* Number of source ports. */
2673 	IP_FW_SETNDSTP(&rule, 1);	/* Number of destination ports. */
2674 	rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
2675 	rule.fw_prot = IPPROTO_TCP;
2676 	rule.fw_smsk.s_addr = INADDR_BROADCAST;
2677 	rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2678 
2679 	/* Build and apply specific part of the rules */
2680 	rule.fw_src = GetOriginalAddress(link);
2681 	rule.fw_dst = GetDestAddress(link);
2682 	rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2683 	rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2684 
2685 	/*
2686 	 * Skip non-bound links - XXX should not be strictly necessary, but
2687 	 * seems to leave hole if not done.  Leak of non-bound links? (Code
2688 	 * should be left even if the problem is fixed - it is a clear
2689 	 * optimization)
2690 	 */
2691 	if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2692 		r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2693 #ifdef DEBUG
2694 		if (r)
2695 			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2696 #endif
2697 		rule.fw_src = GetDestAddress(link);
2698 		rule.fw_dst = GetOriginalAddress(link);
2699 		rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2700 		rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2701 		r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2702 #ifdef DEBUG
2703 		if (r)
2704 			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2705 #endif
2706 	}
2707 #endif				/* !IPFW2 */
2708 /* Indicate hole applied */
2709 	link->data.tcp->fwhole = fwhole;
2710 	fw_setfield(la, la->fireWallField, fwhole);
2711 }
2712 
2713 /* Remove a hole in a firewall associated with a particular alias
2714    link.  Calling this too often is harmless. */
2715 static void
2716 ClearFWHole(struct alias_link *link)
2717 {
2718 
2719 	struct libalias *la;
2720 
2721 	la = link->la;
2722 	if (link->link_type == LINK_TCP) {
2723 		int fwhole = link->data.tcp->fwhole;	/* Where is the firewall
2724 							 * hole? */
2725 		struct ip_fw rule;
2726 
2727 		if (fwhole < 0)
2728 			return;
2729 
2730 		memset(&rule, 0, sizeof rule);	/* useless for ipfw2 */
2731 #if IPFW2
2732 		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2733 		    &fwhole, sizeof fwhole));
2734 #else				/* !IPFW2 */
2735 		rule.fw_number = fwhole;
2736 		while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2737 		    &rule, sizeof rule));
2738 #endif				/* !IPFW2 */
2739 		fw_clrfield(la, la->fireWallField, fwhole);
2740 		link->data.tcp->fwhole = -1;
2741 	}
2742 }
2743 
2744 /* Clear out the entire range dedicated to firewall holes. */
2745 static void
2746 ClearAllFWHoles(struct libalias *la)
2747 {
2748 	struct ip_fw rule;	/* On-the-fly built rule */
2749 	int i;
2750 
2751 	if (la->fireWallFD < 0)
2752 		return;
2753 
2754 	memset(&rule, 0, sizeof rule);
2755 	for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2756 #if IPFW2
2757 		int r = i;
2758 
2759 		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2760 #else				/* !IPFW2 */
2761 		rule.fw_number = i;
2762 		while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule));
2763 #endif				/* !IPFW2 */
2764 	}
2765 	/* XXX: third arg correct here ? /phk */
2766 	memset(la->fireWallField, 0, la->fireWallNumNums);
2767 }
2768 
2769 #endif
2770 
2771 void
2772 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2773 {
2774 #ifndef NO_FW_PUNCH
2775 	la->fireWallBaseNum = base;
2776 	la->fireWallNumNums = num;
2777 #endif
2778 }
2779 
2780 void
2781 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2782 {
2783 	la->skinnyPort = port;
2784 }
2785