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