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