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