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