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