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