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