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