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