xref: /freebsd/sys/netinet/libalias/alias_db.c (revision 33b8c039a960bcff3471baf5929558c4d1500727)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #ifdef _KERNEL
33 #include <machine/stdarg.h>
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/lock.h>
38 #include <sys/module.h>
39 #include <sys/rwlock.h>
40 #include <sys/syslog.h>
41 #else
42 #include <stdarg.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <sys/errno.h>
46 #include <sys/time.h>
47 #include <unistd.h>
48 #endif
49 
50 #include <sys/socket.h>
51 #include <netinet/tcp.h>
52 
53 #ifdef _KERNEL
54 #include <netinet/libalias/alias.h>
55 #include <netinet/libalias/alias_local.h>
56 #include <netinet/libalias/alias_mod.h>
57 #include <net/if.h>
58 #else
59 #include "alias.h"
60 #include "alias_local.h"
61 #include "alias_mod.h"
62 #endif
63 
64 #include "alias_db.h"
65 
66 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
67 int LibAliasTime;
68 
69 /* Kernel module definition. */
70 #ifdef _KERNEL
71 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
72 
73 MODULE_VERSION(libalias, 1);
74 
75 static int
76 alias_mod_handler(module_t mod, int type, void *data)
77 {
78 	switch (type) {
79 	case MOD_QUIESCE:
80 	case MOD_UNLOAD:
81 		finishoff();
82 	case MOD_LOAD:
83 		return (0);
84 	default:
85 		return (EINVAL);
86 	}
87 }
88 
89 static moduledata_t alias_mod = {
90        "alias", alias_mod_handler, NULL
91 };
92 
93 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
94 #endif
95 
96 SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out);
97 SPLAY_GENERATE(splay_in, group_in, in, cmp_in);
98 
99 static struct group_in *
100 StartPointIn(struct libalias *la,
101     struct in_addr alias_addr, u_short alias_port, int link_type,
102     int create)
103 {
104 	struct group_in *grp;
105 	struct group_in needle = {
106 		.alias_addr = alias_addr,
107 		.alias_port = alias_port,
108 		.link_type = link_type
109 	};
110 
111 	grp = SPLAY_FIND(splay_in, &la->linkSplayIn, &needle);
112 	if (grp != NULL || !create || (grp = malloc(sizeof(*grp))) == NULL)
113 		return (grp);
114 	grp->alias_addr = alias_addr;
115 	grp->alias_port = alias_port;
116 	grp->link_type = link_type;
117 	LIST_INIT(&grp->full);
118 	LIST_INIT(&grp->partial);
119 	SPLAY_INSERT(splay_in, &la->linkSplayIn, grp);
120 	return (grp);
121 }
122 #undef INGUARD
123 
124 static int
125 SeqDiff(u_long x, u_long y)
126 {
127 /* Return the difference between two TCP sequence numbers
128  * This function is encapsulated in case there are any unusual
129  * arithmetic conditions that need to be considered.
130  */
131 	return (ntohl(y) - ntohl(x));
132 }
133 
134 #ifdef _KERNEL
135 static void
136 AliasLog(char *str, const char *format, ...)
137 {
138 	va_list ap;
139 
140 	va_start(ap, format);
141 	vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
142 	va_end(ap);
143 }
144 #else
145 static void
146 AliasLog(FILE *stream, const char *format, ...)
147 {
148 	va_list ap;
149 
150 	va_start(ap, format);
151 	vfprintf(stream, format, ap);
152 	va_end(ap);
153 	fflush(stream);
154 }
155 #endif
156 
157 static void
158 ShowAliasStats(struct libalias *la)
159 {
160 	LIBALIAS_LOCK_ASSERT(la);
161 	/* Used for debugging */
162 	if (la->logDesc) {
163 		int tot  = la->icmpLinkCount + la->udpLinkCount +
164 		    (la->sctpLinkCount>>1) + /* sctp counts half associations */
165 		    la->tcpLinkCount + la->pptpLinkCount +
166 		    la->protoLinkCount + la->fragmentIdLinkCount +
167 		    la->fragmentPtrLinkCount;
168 
169 		AliasLog(la->logDesc,
170 		    "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
171 		    la->icmpLinkCount,
172 		    la->udpLinkCount,
173 		    la->tcpLinkCount,
174 		    la->sctpLinkCount>>1, /* sctp counts half associations */
175 		    la->pptpLinkCount,
176 		    la->protoLinkCount,
177 		    la->fragmentIdLinkCount,
178 		    la->fragmentPtrLinkCount,
179 		    tot);
180 #ifndef _KERNEL
181 		AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
182 #endif
183 	}
184 }
185 
186 void SctpShowAliasStats(struct libalias *la)
187 {
188 	ShowAliasStats(la);
189 }
190 
191 /* get random port in network byte order */
192 static u_short
193 _RandomPort(struct libalias *la) {
194 	u_short port;
195 
196 	port = la->aliasPortLower +
197 	    arc4random_uniform(la->aliasPortLength);
198 
199 	return ntohs(port);
200 }
201 
202 /* GetNewPort() allocates port numbers.  Note that if a port number
203    is already in use, that does not mean that it cannot be used by
204    another link concurrently.  This is because GetNewPort() looks for
205    unused triplets: (dest addr, dest port, alias port). */
206 
207 static int
208 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
209 {
210 	int i;
211 	int max_trials;
212 	u_short port;
213 
214 	LIBALIAS_LOCK_ASSERT(la);
215 	/*
216 	 * Description of alias_port_param for GetNewPort().  When
217 	 * this parameter is zero or positive, it precisely specifies
218 	 * the port number.  GetNewPort() will return this number
219 	 * without check that it is in use.
220 	*
221 	 * The aliasing port is automatically selected by one of
222 	 * two methods below:
223 	 *
224 	 * When this parameter is GET_ALIAS_PORT, it indicates to get
225 	 * a randomly selected port number.
226 	 */
227 	if (alias_port_param >= 0 && alias_port_param < 0x10000) {
228 		lnk->alias_port = (u_short) alias_port_param;
229 		return (0);
230 	}
231 	if (alias_port_param != GET_ALIAS_PORT) {
232 #ifdef LIBALIAS_DEBUG
233 		fprintf(stderr, "PacketAlias/GetNewPort(): ");
234 		fprintf(stderr, "input parameter error\n");
235 #endif
236 		return (-1);
237 	}
238 
239 	max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
240 
241 	/*
242 	 * When the PKT_ALIAS_SAME_PORTS option is chosen,
243 	 * the first try will be the actual source port. If
244 	 * this is already in use, the remainder of the
245 	 * trials will be random.
246 	 */
247 	port = (la->packetAliasMode & PKT_ALIAS_SAME_PORTS)
248 	    ? lnk->src_port
249 	    : _RandomPort(la);
250 
251 	/* Port number search */
252 	for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
253 		struct group_in *grp;
254 		struct alias_link *search_result;
255 
256 		grp = StartPointIn(la, lnk->alias_addr, port, lnk->link_type, 0);
257 		if (grp == NULL)
258 			break;
259 
260 		LIST_FOREACH(search_result, &grp->full, all.in) {
261 			if (lnk->dst_addr.s_addr == search_result->dst_addr.s_addr &&
262 			    lnk->dst_port == search_result->dst_port)
263 			    break;     /* found match */
264 		}
265 		if (search_result == NULL)
266 			break;
267 	}
268 
269 	if (i >= max_trials) {
270 #ifdef LIBALIAS_DEBUG
271 		fprintf(stderr, "PacketAlias/GetNewPort(): ");
272 		fprintf(stderr, "could not find free port\n");
273 #endif
274 		return (-1);
275 	}
276 
277 #ifndef NO_USE_SOCKETS
278 	if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) &&
279 	    (lnk->flags & LINK_PARTIALLY_SPECIFIED) &&
280 	    ((lnk->link_type == LINK_TCP) ||
281 	     (lnk->link_type == LINK_UDP))) {
282 		if (!GetSocket(la, port, &lnk->sockfd, lnk->link_type)) {
283 			return (-1);
284 		}
285 	}
286 #endif
287 	lnk->alias_port = port;
288 
289 	return (0);
290 }
291 
292 #ifndef NO_USE_SOCKETS
293 static		u_short
294 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
295 {
296 	int err;
297 	int sock;
298 	struct sockaddr_in sock_addr;
299 
300 	LIBALIAS_LOCK_ASSERT(la);
301 	if (link_type == LINK_TCP)
302 		sock = socket(AF_INET, SOCK_STREAM, 0);
303 	else if (link_type == LINK_UDP)
304 		sock = socket(AF_INET, SOCK_DGRAM, 0);
305 	else {
306 #ifdef LIBALIAS_DEBUG
307 		fprintf(stderr, "PacketAlias/GetSocket(): ");
308 		fprintf(stderr, "incorrect link type\n");
309 #endif
310 		return (0);
311 	}
312 
313 	if (sock < 0) {
314 #ifdef LIBALIAS_DEBUG
315 		fprintf(stderr, "PacketAlias/GetSocket(): ");
316 		fprintf(stderr, "socket() error %d\n", *sockfd);
317 #endif
318 		return (0);
319 	}
320 	sock_addr.sin_family = AF_INET;
321 	sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
322 	sock_addr.sin_port = port_net;
323 
324 	err = bind(sock,
325 	    (struct sockaddr *)&sock_addr,
326 	    sizeof(sock_addr));
327 	if (err == 0) {
328 		la->sockCount++;
329 		*sockfd = sock;
330 		return (1);
331 	} else {
332 		close(sock);
333 		return (0);
334 	}
335 }
336 #endif
337 
338 /* FindNewPortGroup() returns a base port number for an available
339    range of contiguous port numbers. Note that if a port number
340    is already in use, that does not mean that it cannot be used by
341    another link concurrently.  This is because FindNewPortGroup()
342    looks for unused triplets: (dest addr, dest port, alias port). */
343 
344 int
345 FindNewPortGroup(struct libalias *la,
346     struct in_addr dst_addr,
347     struct in_addr alias_addr,
348     u_short src_port,
349     u_short dst_port,
350     u_short port_count,
351     u_char proto,
352     u_char align)
353 {
354 	int i, j;
355 	int max_trials;
356 	u_short port;
357 	int link_type;
358 
359 	LIBALIAS_LOCK_ASSERT(la);
360 	/*
361 	 * Get link_type from protocol
362 	 */
363 
364 	switch (proto) {
365 	case IPPROTO_UDP:
366 		link_type = LINK_UDP;
367 		break;
368 	case IPPROTO_TCP:
369 		link_type = LINK_TCP;
370 		break;
371 	default:
372 		return (0);
373 		break;
374 	}
375 
376 	/*
377 	 * The aliasing port is automatically selected by one of two
378 	 * methods below:
379 	 */
380 	max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
381 
382 	if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
383 		/*
384 		 * When the ALIAS_SAME_PORTS option is chosen, the first
385 		 * try will be the actual source port. If this is already
386 		 * in use, the remainder of the trials will be random.
387 		 */
388 		port = src_port;
389 
390 	} else {
391 		port = _RandomPort(la);
392 	}
393 
394 	/* Port number search */
395 	for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
396 		struct alias_link *search_result;
397 
398 		if (align)
399 			port &= htons(0xfffe);
400 
401 		for (j = 0; j < port_count; j++) {
402 			u_short port_j = ntohs(port) + j;
403 
404 			if ((search_result = FindLinkIn(la, dst_addr,
405 			    alias_addr, dst_port, htons(port_j),
406 			    link_type, 0)) != NULL)
407 				break;
408 		}
409 
410 		/* Found a good range, return base */
411 		if (j == port_count)
412 			return (port);
413 	}
414 
415 #ifdef LIBALIAS_DEBUG
416 	fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
417 	fprintf(stderr, "could not find free port(s)\n");
418 #endif
419 
420 	return (0);
421 }
422 
423 static void
424 CleanupAliasData(struct libalias *la, int deletePermanent)
425 {
426 	struct alias_link *lnk, *lnk_tmp;
427 
428 	LIBALIAS_LOCK_ASSERT(la);
429 
430 	/* permanent entries may stay */
431 	TAILQ_FOREACH_SAFE(lnk, &la->checkExpire, expire.list, lnk_tmp)
432 		DeleteLink(&lnk, deletePermanent);
433 }
434 static void
435 CleanupLink(struct libalias *la, struct alias_link **lnk, int deletePermanent)
436 {
437 	LIBALIAS_LOCK_ASSERT(la);
438 
439 	if (lnk == NULL || *lnk == NULL)
440 		return;
441 
442 	if (LibAliasTime - (*lnk)->timestamp > (*lnk)->expire.time) {
443 		DeleteLink(lnk, deletePermanent);
444 		if ((*lnk) == NULL)
445 			return;
446 	}
447 
448 	/* move to end, swap may fail on a single entry list */
449 	TAILQ_REMOVE(&la->checkExpire, (*lnk), expire.list);
450 	TAILQ_INSERT_TAIL(&la->checkExpire, (*lnk), expire.list);
451 }
452 
453 static struct alias_link *
454 UseLink(struct libalias *la, struct alias_link *lnk)
455 {
456 	CleanupLink(la, &lnk, 0);
457 	if (lnk != NULL)
458 		lnk->timestamp = LibAliasTime;
459 	return (lnk);
460 }
461 
462 static void
463 DeleteLink(struct alias_link **plnk, int deletePermanent)
464 {
465 	struct alias_link *lnk = *plnk;
466 	struct libalias *la = lnk->la;
467 
468 	LIBALIAS_LOCK_ASSERT(la);
469 	/* Don't do anything if the link is marked permanent */
470 	if (!deletePermanent && (lnk->flags & LINK_PERMANENT))
471 		return;
472 
473 #ifndef NO_FW_PUNCH
474 	/* Delete associated firewall hole, if any */
475 	ClearFWHole(lnk);
476 #endif
477 
478 	switch (lnk->link_type) {
479 	case LINK_PPTP:
480 		LIST_REMOVE(lnk, pptp.list);
481 		break;
482 	default: {
483 		struct group_in *grp;
484 
485 		/* Free memory allocated for LSNAT server pool */
486 		if (lnk->server != NULL) {
487 			struct server *head, *curr, *next;
488 
489 			head = curr = lnk->server;
490 			do {
491 				next = curr->next;
492 				free(curr);
493 			} while ((curr = next) != head);
494 		} else {
495 			/* Adjust output table pointers */
496 			SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
497 		}
498 
499 		/* Adjust input table pointers */
500 		LIST_REMOVE(lnk, all.in);
501 
502 		/* Remove intermediate node, if empty */
503 		grp = StartPointIn(la, lnk->alias_addr, lnk->alias_port, lnk->link_type, 0);
504 		if (grp != NULL &&
505 		    LIST_EMPTY(&grp->full) &&
506 		    LIST_EMPTY(&grp->partial)) {
507 			SPLAY_REMOVE(splay_in, &la->linkSplayIn, grp);
508 			free(grp);
509 		}
510 	}
511 		break;
512 	}
513 
514 	/* remove from housekeeping */
515 	TAILQ_REMOVE(&la->checkExpire, lnk, expire.list);
516 
517 #ifndef NO_USE_SOCKETS
518 	/* Close socket, if one has been allocated */
519 	if (lnk->sockfd != -1) {
520 		la->sockCount--;
521 		close(lnk->sockfd);
522 	}
523 #endif
524 	/* Link-type dependent cleanup */
525 	switch (lnk->link_type) {
526 	case LINK_ICMP:
527 		la->icmpLinkCount--;
528 		break;
529 	case LINK_UDP:
530 		la->udpLinkCount--;
531 		break;
532 	case LINK_TCP:
533 		la->tcpLinkCount--;
534 		free(lnk->data.tcp);
535 		break;
536 	case LINK_PPTP:
537 		la->pptpLinkCount--;
538 		break;
539 	case LINK_FRAGMENT_ID:
540 		la->fragmentIdLinkCount--;
541 		break;
542 	case LINK_FRAGMENT_PTR:
543 		la->fragmentPtrLinkCount--;
544 		if (lnk->data.frag_ptr != NULL)
545 			free(lnk->data.frag_ptr);
546 		break;
547 	case LINK_ADDR:
548 		break;
549 	default:
550 		la->protoLinkCount--;
551 		break;
552 	}
553 
554 	/* Free memory */
555 	free(lnk);
556 	*plnk = NULL;
557 
558 	/* Write statistics, if logging enabled */
559 	if (la->packetAliasMode & PKT_ALIAS_LOG) {
560 		ShowAliasStats(la);
561 	}
562 }
563 
564 struct alias_link *
565 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
566     struct in_addr alias_addr, u_short src_port, u_short dst_port,
567     int alias_port_param, int link_type)
568 {
569 	struct alias_link *lnk;
570 
571 	LIBALIAS_LOCK_ASSERT(la);
572 
573 	lnk = malloc(sizeof(struct alias_link));
574 	if (lnk == NULL) {
575 #ifdef LIBALIAS_DEBUG
576 		fprintf(stderr, "PacketAlias/AddLink(): ");
577 		fprintf(stderr, "malloc() call failed.\n");
578 #endif
579 		return (NULL);
580 	}
581 	/* Basic initialization */
582 	lnk->la = la;
583 	lnk->src_addr = src_addr;
584 	lnk->dst_addr = dst_addr;
585 	lnk->alias_addr = alias_addr;
586 	lnk->proxy_addr.s_addr = INADDR_ANY;
587 	lnk->src_port = src_port;
588 	lnk->dst_port = dst_port;
589 	lnk->proxy_port = 0;
590 	lnk->server = NULL;
591 	lnk->link_type = link_type;
592 #ifndef NO_USE_SOCKETS
593 	lnk->sockfd = -1;
594 #endif
595 	lnk->flags = 0;
596 	lnk->pflags = 0;
597 	lnk->timestamp = LibAliasTime;
598 
599 	/* Expiration time */
600 	switch (link_type) {
601 	case LINK_ICMP:
602 		lnk->expire.time = ICMP_EXPIRE_TIME;
603 		break;
604 	case LINK_UDP:
605 		lnk->expire.time = UDP_EXPIRE_TIME;
606 		break;
607 	case LINK_TCP:
608 		lnk->expire.time = TCP_EXPIRE_INITIAL;
609 		break;
610 	case LINK_FRAGMENT_ID:
611 		lnk->expire.time = FRAGMENT_ID_EXPIRE_TIME;
612 		break;
613 	case LINK_FRAGMENT_PTR:
614 		lnk->expire.time = FRAGMENT_PTR_EXPIRE_TIME;
615 		break;
616 	case LINK_ADDR:
617 		break;
618 	default:
619 		lnk->expire.time = PROTO_EXPIRE_TIME;
620 		break;
621 	}
622 
623 	/* Determine alias flags */
624 	if (dst_addr.s_addr == INADDR_ANY)
625 		lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
626 	if (dst_port == 0)
627 		lnk->flags |= LINK_UNKNOWN_DEST_PORT;
628 
629 	/* Determine alias port */
630 	if (GetNewPort(la, lnk, alias_port_param) != 0) {
631 		free(lnk);
632 		return (NULL);
633 	}
634 	/* Link-type dependent initialization */
635 	switch (link_type) {
636 	case LINK_ICMP:
637 		la->icmpLinkCount++;
638 		break;
639 	case LINK_UDP:
640 		la->udpLinkCount++;
641 		break;
642 	case LINK_TCP: {
643 		struct tcp_dat *aux_tcp;
644 		int i;
645 
646 		aux_tcp = malloc(sizeof(struct tcp_dat));
647 		if (aux_tcp == NULL) {
648 #ifdef LIBALIAS_DEBUG
649 			fprintf(stderr, "PacketAlias/AddLink: ");
650 			fprintf(stderr, " cannot allocate auxiliary TCP data\n");
651 #endif
652 			free(lnk);
653 			return (NULL);
654 		}
655 
656 		la->tcpLinkCount++;
657 		aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
658 		aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
659 		aux_tcp->state.index = 0;
660 		aux_tcp->state.ack_modified = 0;
661 		for (i = 0; i < N_LINK_TCP_DATA; i++)
662 			aux_tcp->ack[i].active = 0;
663 		aux_tcp->fwhole = -1;
664 		lnk->data.tcp = aux_tcp;
665 	}
666 		break;
667 	case LINK_PPTP:
668 		la->pptpLinkCount++;
669 		break;
670 	case LINK_FRAGMENT_ID:
671 		la->fragmentIdLinkCount++;
672 		break;
673 	case LINK_FRAGMENT_PTR:
674 		la->fragmentPtrLinkCount++;
675 		break;
676 	case LINK_ADDR:
677 		break;
678 	default:
679 		la->protoLinkCount++;
680 		break;
681 	}
682 
683 	switch (link_type) {
684 	case LINK_PPTP:
685 		LIST_INSERT_HEAD(&la->pptpList, lnk, pptp.list);
686 		break;
687 	default: {
688 		struct group_in *grp;
689 
690 		grp = StartPointIn(la, alias_addr, lnk->alias_port, link_type, 1);
691 		if (grp == NULL) {
692 			free(lnk);
693 			return (NULL);
694 		}
695 
696 		/* Set up pointers for output lookup table */
697 		SPLAY_INSERT(splay_out, &la->linkSplayOut, lnk);
698 
699 		/* Set up pointers for input lookup table */
700 		if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
701 			LIST_INSERT_HEAD(&grp->partial, lnk, all.in);
702 		else
703 			LIST_INSERT_HEAD(&grp->full, lnk, all.in);
704 	}
705 		break;
706 	}
707 
708 	/* Include the element into the housekeeping list */
709 	TAILQ_INSERT_TAIL(&la->checkExpire, lnk, expire.list);
710 
711 	if (la->packetAliasMode & PKT_ALIAS_LOG)
712 		ShowAliasStats(la);
713 
714 	return (lnk);
715 }
716 
717 /*
718  * If alias_port_param is less than zero, alias port will be automatically
719  * chosen. If greater than zero, equal to alias port
720  */
721 static struct alias_link *
722 ReLink(struct alias_link *old_lnk,
723     struct in_addr src_addr,
724     struct in_addr dst_addr,
725     struct in_addr alias_addr,
726     u_short src_port,
727     u_short dst_port,
728     int alias_port_param,
729     int link_type,
730     int deletePermanent)
731 {
732 	struct alias_link *new_lnk;
733 	struct libalias *la = old_lnk->la;
734 
735 	LIBALIAS_LOCK_ASSERT(la);
736 	new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
737 	    src_port, dst_port, alias_port_param,
738 	    link_type);
739 #ifndef NO_FW_PUNCH
740 	if (new_lnk != NULL &&
741 	    old_lnk->link_type == LINK_TCP &&
742 	    old_lnk->data.tcp->fwhole > 0) {
743 		PunchFWHole(new_lnk);
744 	}
745 #endif
746 	DeleteLink(&old_lnk, deletePermanent);
747 	return (new_lnk);
748 }
749 
750 static struct alias_link *
751 _SearchLinkOut(struct libalias *la, struct in_addr src_addr,
752     struct in_addr dst_addr,
753     u_short src_port,
754     u_short dst_port,
755     int link_type) {
756 	struct alias_link *lnk;
757 	struct alias_link needle = {
758 		.src_addr = src_addr,
759 		.dst_addr = dst_addr,
760 		.src_port = src_port,
761 		.dst_port = dst_port,
762 		.link_type = link_type
763 	};
764 
765 	lnk = SPLAY_FIND(splay_out, &la->linkSplayOut, &needle);
766 	return (UseLink(la, lnk));
767 }
768 
769 static struct alias_link *
770 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
771     struct in_addr dst_addr,
772     u_short src_port,
773     u_short dst_port,
774     int link_type,
775     int replace_partial_links)
776 {
777 	struct alias_link *lnk;
778 
779 	LIBALIAS_LOCK_ASSERT(la);
780 	lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type);
781 	if (lnk != NULL || !replace_partial_links)
782 		return (lnk);
783 
784 	/* Search for partially specified links. */
785 	if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
786 		lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, 0,
787 		    link_type);
788 		if (lnk == NULL)
789 			lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port,
790 			    dst_port, link_type);
791 	}
792 	if (lnk == NULL &&
793 	    (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
794 		lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, 0,
795 		    link_type);
796 	}
797 	if (lnk != NULL) {
798 		lnk = ReLink(lnk,
799 		    src_addr, dst_addr, lnk->alias_addr,
800 		    src_port, dst_port, lnk->alias_port,
801 		    link_type, 0);
802 	}
803 	return (lnk);
804 }
805 
806 static struct alias_link *
807 FindLinkOut(struct libalias *la, struct in_addr src_addr,
808     struct in_addr dst_addr,
809     u_short src_port,
810     u_short dst_port,
811     int link_type,
812     int replace_partial_links)
813 {
814 	struct alias_link *lnk;
815 
816 	LIBALIAS_LOCK_ASSERT(la);
817 	lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
818 	    link_type, replace_partial_links);
819 
820 	if (lnk == NULL) {
821 		/*
822 		 * The following allows permanent links to be specified as
823 		 * using the default source address (i.e. device interface
824 		 * address) without knowing in advance what that address
825 		 * is.
826 		 */
827 		if (la->aliasAddress.s_addr != INADDR_ANY &&
828 		    src_addr.s_addr == la->aliasAddress.s_addr) {
829 			lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port,
830 			    link_type, replace_partial_links);
831 		}
832 	}
833 	return (lnk);
834 }
835 
836 static struct alias_link *
837 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
838     struct in_addr alias_addr,
839     u_short dst_port,
840     u_short alias_port,
841     int link_type,
842     int replace_partial_links)
843 {
844 	int flags_in;
845 	struct group_in *grp;
846 	struct alias_link *lnk;
847 	struct alias_link *lnk_unknown_all;
848 	struct alias_link *lnk_unknown_dst_addr;
849 	struct alias_link *lnk_unknown_dst_port;
850 	struct in_addr src_addr;
851 	u_short src_port;
852 
853 	LIBALIAS_LOCK_ASSERT(la);
854 	/* Initialize pointers */
855 	lnk_unknown_all = NULL;
856 	lnk_unknown_dst_addr = NULL;
857 	lnk_unknown_dst_port = NULL;
858 
859 	/* If either the dest addr or port is unknown, the search
860 	 * loop will have to know about this. */
861 	flags_in = 0;
862 	if (dst_addr.s_addr == INADDR_ANY)
863 		flags_in |= LINK_UNKNOWN_DEST_ADDR;
864 	if (dst_port == 0)
865 		flags_in |= LINK_UNKNOWN_DEST_PORT;
866 
867 	/* Search loop */
868 	grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
869 	if (grp == NULL)
870 		return (NULL);
871 
872 	switch (flags_in) {
873 	case 0:
874 		LIST_FOREACH(lnk, &grp->full, all.in) {
875 			if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
876 			    lnk->dst_port == dst_port)
877 				return (UseLink(la, lnk));
878 		}
879 		break;
880 	case LINK_UNKNOWN_DEST_PORT:
881 		LIST_FOREACH(lnk, &grp->full, all.in) {
882 			if(lnk->dst_addr.s_addr == dst_addr.s_addr) {
883 				lnk_unknown_dst_port = lnk;
884 				break;
885 			}
886 		}
887 		break;
888 	case LINK_UNKNOWN_DEST_ADDR:
889 		LIST_FOREACH(lnk, &grp->full, all.in) {
890 			if(lnk->dst_port == dst_port) {
891 				lnk_unknown_dst_addr = lnk;
892 				break;
893 			}
894 		}
895 		break;
896 	case LINK_PARTIALLY_SPECIFIED:
897 		lnk_unknown_all = LIST_FIRST(&grp->full);
898 		break;
899 	}
900 
901 	if (lnk_unknown_dst_port == NULL) {
902 		LIST_FOREACH(lnk, &grp->partial, all.in) {
903 			int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED;
904 
905 			if (flags == LINK_PARTIALLY_SPECIFIED &&
906 			    lnk_unknown_all == NULL)
907 				lnk_unknown_all = lnk;
908 			if (flags == LINK_UNKNOWN_DEST_ADDR &&
909 			    lnk->dst_port == dst_port &&
910 			    lnk_unknown_dst_addr == NULL)
911 				lnk_unknown_dst_addr = lnk;
912 			if (flags == LINK_UNKNOWN_DEST_PORT &&
913 			    lnk->dst_addr.s_addr == dst_addr.s_addr) {
914 				lnk_unknown_dst_port = lnk;
915 				break;
916 			}
917 		}
918 	}
919 
920 	lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port
921 	    : (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr
922 	    : lnk_unknown_all;
923 
924 	if (lnk == NULL || !replace_partial_links)
925 		return (lnk);
926 
927 	if (lnk->server != NULL) {	/* LSNAT link */
928 		src_addr = lnk->server->addr;
929 		src_port = lnk->server->port;
930 		lnk->server = lnk->server->next;
931 	} else {
932 		src_addr = lnk->src_addr;
933 		src_port = lnk->src_port;
934 	}
935 
936 	if (link_type == LINK_SCTP) {
937 		lnk->src_addr = src_addr;
938 		lnk->src_port = src_port;
939 	} else {
940 		lnk = ReLink(lnk,
941 		    src_addr, dst_addr, alias_addr,
942 		    src_port, dst_port, alias_port,
943 		    link_type, 0);
944 	}
945 	return (lnk);
946 }
947 
948 static struct alias_link *
949 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
950     struct in_addr alias_addr,
951     u_short dst_port,
952     u_short alias_port,
953     int link_type,
954     int replace_partial_links)
955 {
956 	struct alias_link *lnk;
957 
958 	LIBALIAS_LOCK_ASSERT(la);
959 	lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
960 	    link_type, replace_partial_links);
961 
962 	if (lnk == NULL) {
963 		/*
964 		 * The following allows permanent links to be specified as
965 		 * using the default aliasing address (i.e. device
966 		 * interface address) without knowing in advance what that
967 		 * address is.
968 		 */
969 		if (la->aliasAddress.s_addr != INADDR_ANY &&
970 		    alias_addr.s_addr == la->aliasAddress.s_addr) {
971 			lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port,
972 			    link_type, replace_partial_links);
973 		}
974 	}
975 	return (lnk);
976 }
977 
978 /* External routines for finding/adding links
979 
980 -- "external" means outside alias_db.c, but within alias*.c --
981 
982     FindIcmpIn(), FindIcmpOut()
983     FindFragmentIn1(), FindFragmentIn2()
984     AddFragmentPtrLink(), FindFragmentPtr()
985     FindProtoIn(), FindProtoOut()
986     FindUdpTcpIn(), FindUdpTcpOut()
987     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
988     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
989     FindOriginalAddress(), FindAliasAddress()
990 
991 (prototypes in alias_local.h)
992 */
993 
994 struct alias_link *
995 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
996     struct in_addr alias_addr,
997     u_short id_alias,
998     int create)
999 {
1000 	struct alias_link *lnk;
1001 
1002 	LIBALIAS_LOCK_ASSERT(la);
1003 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1004 	    NO_DEST_PORT, id_alias,
1005 	    LINK_ICMP, 0);
1006 	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1007 		struct in_addr target_addr;
1008 
1009 		target_addr = FindOriginalAddress(la, alias_addr);
1010 		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1011 		    id_alias, NO_DEST_PORT, id_alias,
1012 		    LINK_ICMP);
1013 	}
1014 	return (lnk);
1015 }
1016 
1017 struct alias_link *
1018 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1019     struct in_addr dst_addr,
1020     u_short id,
1021     int create)
1022 {
1023 	struct alias_link *lnk;
1024 
1025 	LIBALIAS_LOCK_ASSERT(la);
1026 	lnk = FindLinkOut(la, src_addr, dst_addr,
1027 	    id, NO_DEST_PORT,
1028 	    LINK_ICMP, 0);
1029 	if (lnk == NULL && create) {
1030 		struct in_addr alias_addr;
1031 
1032 		alias_addr = FindAliasAddress(la, src_addr);
1033 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1034 		    id, NO_DEST_PORT, GET_ALIAS_ID,
1035 		    LINK_ICMP);
1036 	}
1037 	return (lnk);
1038 }
1039 
1040 struct alias_link *
1041 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1042     struct in_addr alias_addr,
1043     u_short ip_id)
1044 {
1045 	struct alias_link *lnk;
1046 
1047 	LIBALIAS_LOCK_ASSERT(la);
1048 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1049 	    NO_DEST_PORT, ip_id,
1050 	    LINK_FRAGMENT_ID, 0);
1051 
1052 	if (lnk == NULL) {
1053 		lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr,
1054 		    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1055 		    LINK_FRAGMENT_ID);
1056 	}
1057 	return (lnk);
1058 }
1059 
1060 /* Doesn't add a link if one is not found. */
1061 struct alias_link *
1062 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,
1063     struct in_addr alias_addr, u_short ip_id)
1064 {
1065 	LIBALIAS_LOCK_ASSERT(la);
1066 	return FindLinkIn(la, dst_addr, alias_addr,
1067 	    NO_DEST_PORT, ip_id,
1068 	    LINK_FRAGMENT_ID, 0);
1069 }
1070 
1071 struct alias_link *
1072 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1073     u_short ip_id)
1074 {
1075 	LIBALIAS_LOCK_ASSERT(la);
1076 	return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR,
1077 	    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1078 	    LINK_FRAGMENT_PTR);
1079 }
1080 
1081 struct alias_link *
1082 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1083     u_short ip_id)
1084 {
1085 	LIBALIAS_LOCK_ASSERT(la);
1086 	return FindLinkIn(la, dst_addr, ANY_ADDR,
1087 	    NO_DEST_PORT, ip_id,
1088 	    LINK_FRAGMENT_PTR, 0);
1089 }
1090 
1091 struct alias_link *
1092 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1093     struct in_addr alias_addr,
1094     u_char proto)
1095 {
1096 	struct alias_link *lnk;
1097 
1098 	LIBALIAS_LOCK_ASSERT(la);
1099 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1100 	    NO_DEST_PORT, 0,
1101 	    proto, 1);
1102 
1103 	if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1104 		struct in_addr target_addr;
1105 
1106 		target_addr = FindOriginalAddress(la, alias_addr);
1107 		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1108 		    NO_SRC_PORT, NO_DEST_PORT, 0,
1109 		    proto);
1110 	}
1111 	return (lnk);
1112 }
1113 
1114 struct alias_link *
1115 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1116     struct in_addr dst_addr,
1117     u_char proto)
1118 {
1119 	struct alias_link *lnk;
1120 
1121 	LIBALIAS_LOCK_ASSERT(la);
1122 	lnk = FindLinkOut(la, src_addr, dst_addr,
1123 	    NO_SRC_PORT, NO_DEST_PORT,
1124 	    proto, 1);
1125 
1126 	if (lnk == NULL) {
1127 		struct in_addr alias_addr;
1128 
1129 		alias_addr = FindAliasAddress(la, src_addr);
1130 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1131 		    NO_SRC_PORT, NO_DEST_PORT, 0,
1132 		    proto);
1133 	}
1134 	return (lnk);
1135 }
1136 
1137 struct alias_link *
1138 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1139     struct in_addr alias_addr,
1140     u_short dst_port,
1141     u_short alias_port,
1142     u_char proto,
1143     int create)
1144 {
1145 	int link_type;
1146 	struct alias_link *lnk;
1147 
1148 	LIBALIAS_LOCK_ASSERT(la);
1149 	switch (proto) {
1150 	case IPPROTO_UDP:
1151 		link_type = LINK_UDP;
1152 		break;
1153 	case IPPROTO_TCP:
1154 		link_type = LINK_TCP;
1155 		break;
1156 	default:
1157 		return (NULL);
1158 		break;
1159 	}
1160 
1161 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1162 	    dst_port, alias_port,
1163 	    link_type, create);
1164 
1165 	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1166 		struct in_addr target_addr;
1167 
1168 		target_addr = FindOriginalAddress(la, alias_addr);
1169 		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1170 		    alias_port, dst_port, alias_port,
1171 		    link_type);
1172 	}
1173 	return (lnk);
1174 }
1175 
1176 struct alias_link *
1177 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1178     struct in_addr dst_addr,
1179     u_short src_port,
1180     u_short dst_port,
1181     u_char proto,
1182     int create)
1183 {
1184 	int link_type;
1185 	struct alias_link *lnk;
1186 
1187 	LIBALIAS_LOCK_ASSERT(la);
1188 	switch (proto) {
1189 	case IPPROTO_UDP:
1190 		link_type = LINK_UDP;
1191 		break;
1192 	case IPPROTO_TCP:
1193 		link_type = LINK_TCP;
1194 		break;
1195 	default:
1196 		return (NULL);
1197 		break;
1198 	}
1199 
1200 	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1201 
1202 	if (lnk == NULL && create) {
1203 		struct in_addr alias_addr;
1204 
1205 		alias_addr = FindAliasAddress(la, src_addr);
1206 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1207 		    src_port, dst_port, GET_ALIAS_PORT,
1208 		    link_type);
1209 	}
1210 	return (lnk);
1211 }
1212 
1213 struct alias_link *
1214 AddPptp(struct libalias *la, struct in_addr src_addr,
1215     struct in_addr dst_addr,
1216     struct in_addr alias_addr,
1217     u_int16_t src_call_id)
1218 {
1219 	struct alias_link *lnk;
1220 
1221 	LIBALIAS_LOCK_ASSERT(la);
1222 	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1223 	    src_call_id, 0, GET_ALIAS_PORT,
1224 	    LINK_PPTP);
1225 
1226 	return (lnk);
1227 }
1228 
1229 struct alias_link *
1230 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1231     struct in_addr dst_addr,
1232     u_int16_t src_call_id)
1233 {
1234 	struct alias_link *lnk;
1235 
1236 	LIBALIAS_LOCK_ASSERT(la);
1237 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1238 		if (lnk->src_addr.s_addr == src_addr.s_addr &&
1239 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1240 		    lnk->src_port == src_call_id)
1241 			break;
1242 
1243 	return (UseLink(la, lnk));
1244 }
1245 
1246 struct alias_link *
1247 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1248     struct in_addr dst_addr,
1249     u_int16_t dst_call_id)
1250 {
1251 	struct alias_link *lnk;
1252 
1253 	LIBALIAS_LOCK_ASSERT(la);
1254 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1255 		if (lnk->src_addr.s_addr == src_addr.s_addr &&
1256 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1257 		    lnk->dst_port == dst_call_id)
1258 			break;
1259 
1260 	return (UseLink(la, lnk));
1261 }
1262 
1263 struct alias_link *
1264 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1265     struct in_addr alias_addr,
1266     u_int16_t dst_call_id)
1267 {
1268 	struct alias_link *lnk;
1269 
1270 	LIBALIAS_LOCK_ASSERT(la);
1271 
1272 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1273 		if (lnk->dst_port == dst_call_id &&
1274 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1275 		    lnk->alias_addr.s_addr == alias_addr.s_addr)
1276 			break;
1277 
1278 	return (UseLink(la, lnk));
1279 }
1280 
1281 struct alias_link *
1282 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1283     struct in_addr alias_addr,
1284     u_int16_t alias_call_id)
1285 {
1286 	struct alias_link *lnk;
1287 
1288 	LIBALIAS_LOCK_ASSERT(la);
1289 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1290 		if (lnk->alias_port == alias_call_id &&
1291 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1292 		    lnk->alias_addr.s_addr == alias_addr.s_addr)
1293 			break;
1294 
1295 	return (lnk);
1296 }
1297 
1298 struct alias_link *
1299 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1300     struct in_addr dst_addr,
1301     u_short src_port,
1302     u_short alias_port,
1303     u_char proto)
1304 {
1305 	int link_type;
1306 	struct alias_link *lnk;
1307 
1308 	LIBALIAS_LOCK_ASSERT(la);
1309 	switch (proto) {
1310 	case IPPROTO_UDP:
1311 		link_type = LINK_UDP;
1312 		break;
1313 	case IPPROTO_TCP:
1314 		link_type = LINK_TCP;
1315 		break;
1316 	default:
1317 		return (NULL);
1318 		break;
1319 	}
1320 
1321 	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1322 
1323 	if (lnk == NULL) {
1324 		struct in_addr alias_addr;
1325 
1326 		alias_addr = FindAliasAddress(la, src_addr);
1327 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1328 		    src_port, 0, alias_port,
1329 		    link_type);
1330 	}
1331 	return (lnk);
1332 }
1333 
1334 struct in_addr
1335 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1336 {
1337 	struct alias_link *lnk;
1338 
1339 	LIBALIAS_LOCK_ASSERT(la);
1340 	lnk = FindLinkIn(la, ANY_ADDR, alias_addr,
1341 	    0, 0, LINK_ADDR, 0);
1342 	if (lnk == NULL) {
1343 		if (la->targetAddress.s_addr == INADDR_ANY)
1344 			return (alias_addr);
1345 		else if (la->targetAddress.s_addr == INADDR_NONE)
1346 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1347 			    la->aliasAddress : alias_addr;
1348 		else
1349 			return (la->targetAddress);
1350 	} else {
1351 		if (lnk->server != NULL) {	/* LSNAT link */
1352 			struct in_addr src_addr;
1353 
1354 			src_addr = lnk->server->addr;
1355 			lnk->server = lnk->server->next;
1356 			return (src_addr);
1357 		} else if (lnk->src_addr.s_addr == INADDR_ANY)
1358 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1359 			    la->aliasAddress : alias_addr;
1360 		else
1361 			return (lnk->src_addr);
1362 	}
1363 }
1364 
1365 struct in_addr
1366 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1367 {
1368 	struct alias_link *lnk;
1369 
1370 	LIBALIAS_LOCK_ASSERT(la);
1371 	lnk = FindLinkOut(la, original_addr, ANY_ADDR,
1372 	    0, 0, LINK_ADDR, 0);
1373 	if (lnk == NULL) {
1374 		return (la->aliasAddress.s_addr != INADDR_ANY) ?
1375 		    la->aliasAddress : original_addr;
1376 	} else {
1377 		if (lnk->alias_addr.s_addr == INADDR_ANY)
1378 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1379 			    la->aliasAddress : original_addr;
1380 		else
1381 			return (lnk->alias_addr);
1382 	}
1383 }
1384 
1385 /* External routines for getting or changing link data
1386    (external to alias_db.c, but internal to alias*.c)
1387 
1388     SetFragmentData(), GetFragmentData()
1389     SetFragmentPtr(), GetFragmentPtr()
1390     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1391     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1392     GetOriginalPort(), GetAliasPort()
1393     SetAckModified(), GetAckModified()
1394     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1395     SetProtocolFlags(), GetProtocolFlags()
1396     SetDestCallId()
1397 */
1398 
1399 void
1400 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1401 {
1402 	lnk->data.frag_addr = src_addr;
1403 }
1404 
1405 void
1406 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1407 {
1408 	*src_addr = lnk->data.frag_addr;
1409 }
1410 
1411 void
1412 SetFragmentPtr(struct alias_link *lnk, void *fptr)
1413 {
1414 	lnk->data.frag_ptr = fptr;
1415 }
1416 
1417 void
1418 GetFragmentPtr(struct alias_link *lnk, void **fptr)
1419 {
1420 	*fptr = lnk->data.frag_ptr;
1421 }
1422 
1423 void
1424 SetStateIn(struct alias_link *lnk, int state)
1425 {
1426 	/* TCP input state */
1427 	switch (state) {
1428 		case ALIAS_TCP_STATE_DISCONNECTED:
1429 		if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1430 			lnk->expire.time = TCP_EXPIRE_DEAD;
1431 		else
1432 			lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1433 		break;
1434 	case ALIAS_TCP_STATE_CONNECTED:
1435 		if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1436 			lnk->expire.time = TCP_EXPIRE_CONNECTED;
1437 		break;
1438 	default:
1439 #ifdef _KERNEL
1440 		panic("libalias:SetStateIn() unknown state");
1441 #else
1442 		abort();
1443 #endif
1444 	}
1445 	lnk->data.tcp->state.in = state;
1446 }
1447 
1448 void
1449 SetStateOut(struct alias_link *lnk, int state)
1450 {
1451 	/* TCP output state */
1452 	switch (state) {
1453 		case ALIAS_TCP_STATE_DISCONNECTED:
1454 		if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1455 			lnk->expire.time = TCP_EXPIRE_DEAD;
1456 		else
1457 			lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1458 		break;
1459 	case ALIAS_TCP_STATE_CONNECTED:
1460 		if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1461 			lnk->expire.time = TCP_EXPIRE_CONNECTED;
1462 		break;
1463 	default:
1464 #ifdef _KERNEL
1465 		panic("libalias:SetStateOut() unknown state");
1466 #else
1467 		abort();
1468 #endif
1469 	}
1470 	lnk->data.tcp->state.out = state;
1471 }
1472 
1473 int
1474 GetStateIn(struct alias_link *lnk)
1475 {
1476 	/* TCP input state */
1477 	return (lnk->data.tcp->state.in);
1478 }
1479 
1480 int
1481 GetStateOut(struct alias_link *lnk)
1482 {
1483 	/* TCP output state */
1484 	return (lnk->data.tcp->state.out);
1485 }
1486 
1487 struct in_addr
1488 GetOriginalAddress(struct alias_link *lnk)
1489 {
1490 	if (lnk->src_addr.s_addr == INADDR_ANY)
1491 		return (lnk->la->aliasAddress);
1492 	else
1493 		return (lnk->src_addr);
1494 }
1495 
1496 struct in_addr
1497 GetDestAddress(struct alias_link *lnk)
1498 {
1499 	return (lnk->dst_addr);
1500 }
1501 
1502 struct in_addr
1503 GetAliasAddress(struct alias_link *lnk)
1504 {
1505 	if (lnk->alias_addr.s_addr == INADDR_ANY)
1506 		return (lnk->la->aliasAddress);
1507 	else
1508 		return (lnk->alias_addr);
1509 }
1510 
1511 struct in_addr
1512 GetDefaultAliasAddress(struct libalias *la)
1513 {
1514 	LIBALIAS_LOCK_ASSERT(la);
1515 	return (la->aliasAddress);
1516 }
1517 
1518 void
1519 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1520 {
1521 	LIBALIAS_LOCK_ASSERT(la);
1522 	la->aliasAddress = alias_addr;
1523 }
1524 
1525 u_short
1526 GetOriginalPort(struct alias_link *lnk)
1527 {
1528 	return (lnk->src_port);
1529 }
1530 
1531 u_short
1532 GetAliasPort(struct alias_link *lnk)
1533 {
1534 	return (lnk->alias_port);
1535 }
1536 
1537 #ifndef NO_FW_PUNCH
1538 static u_short
1539 GetDestPort(struct alias_link *lnk)
1540 {
1541 	return (lnk->dst_port);
1542 }
1543 
1544 #endif
1545 
1546 /* Indicate that ACK numbers have been modified in a TCP connection */
1547 void
1548 SetAckModified(struct alias_link *lnk)
1549 {
1550 	lnk->data.tcp->state.ack_modified = 1;
1551 }
1552 
1553 struct in_addr
1554 GetProxyAddress(struct alias_link *lnk)
1555 {
1556 	return (lnk->proxy_addr);
1557 }
1558 
1559 void
1560 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1561 {
1562 	lnk->proxy_addr = addr;
1563 }
1564 
1565 u_short
1566 GetProxyPort(struct alias_link *lnk)
1567 {
1568 	return (lnk->proxy_port);
1569 }
1570 
1571 void
1572 SetProxyPort(struct alias_link *lnk, u_short port)
1573 {
1574 	lnk->proxy_port = port;
1575 }
1576 
1577 /* See if ACK numbers have been modified */
1578 int
1579 GetAckModified(struct alias_link *lnk)
1580 {
1581 	return (lnk->data.tcp->state.ack_modified);
1582 }
1583 
1584 /*
1585  * Find out how much the ACK number has been altered for an
1586  * incoming TCP packet.  To do this, a circular list of ACK
1587  * numbers where the TCP packet size was altered is searched.
1588  */
1589 // XXX ip free
1590 int
1591 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1592 {
1593 	int i, j;
1594 	int delta, ack_diff_min;
1595 
1596 	delta = 0;
1597 	ack_diff_min = -1;
1598 	i = lnk->data.tcp->state.index;
1599 	for (j = 0; j < N_LINK_TCP_DATA; j++) {
1600 		struct ack_data_record x;
1601 
1602 		if (i == 0)
1603 			i = N_LINK_TCP_DATA;
1604 		i--;
1605 		x = lnk->data.tcp->ack[i];
1606 		if (x.active == 1) {
1607 			int ack_diff;
1608 
1609 			ack_diff = SeqDiff(x.ack_new, ack);
1610 			if (ack_diff >= 0) {
1611 				if (ack_diff_min >= 0) {
1612 					if (ack_diff < ack_diff_min) {
1613 						delta = x.delta;
1614 						ack_diff_min = ack_diff;
1615 					}
1616 				} else {
1617 					delta = x.delta;
1618 					ack_diff_min = ack_diff;
1619 				}
1620 			}
1621 		}
1622 	}
1623 	return (delta);
1624 }
1625 
1626 /*
1627  * Find out how much the sequence number has been altered for an
1628  * outgoing TCP packet.  To do this, a circular list of ACK numbers
1629  * where the TCP packet size was altered is searched.
1630  */
1631 // XXX ip free
1632 int
1633 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
1634 {
1635 	int i, j;
1636 	int delta, seq_diff_min;
1637 
1638 	delta = 0;
1639 	seq_diff_min = -1;
1640 	i = lnk->data.tcp->state.index;
1641 	for (j = 0; j < N_LINK_TCP_DATA; j++) {
1642 		struct ack_data_record x;
1643 
1644 		if (i == 0)
1645 			i = N_LINK_TCP_DATA;
1646 		i--;
1647 		x = lnk->data.tcp->ack[i];
1648 		if (x.active == 1) {
1649 			int seq_diff;
1650 
1651 			seq_diff = SeqDiff(x.ack_old, seq);
1652 			if (seq_diff >= 0) {
1653 				if (seq_diff_min >= 0) {
1654 					if (seq_diff < seq_diff_min) {
1655 						delta = x.delta;
1656 						seq_diff_min = seq_diff;
1657 					}
1658 				} else {
1659 					delta = x.delta;
1660 					seq_diff_min = seq_diff;
1661 				}
1662 			}
1663 		}
1664 	}
1665 	return (delta);
1666 }
1667 
1668 /*
1669  * When a TCP packet has been altered in length, save this
1670  * information in a circular list.  If enough packets have been
1671  * altered, then this list will begin to overwrite itself.
1672  */
1673 // XXX ip free
1674 void
1675 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
1676     u_long th_seq, u_int th_off)
1677 {
1678 	struct ack_data_record x;
1679 	int hlen, tlen, dlen;
1680 	int i;
1681 
1682 	hlen = (ip_hl + th_off) << 2;
1683 	tlen = ntohs(ip_len);
1684 	dlen = tlen - hlen;
1685 
1686 	x.ack_old = htonl(ntohl(th_seq) + dlen);
1687 	x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
1688 	x.delta = delta;
1689 	x.active = 1;
1690 
1691 	i = lnk->data.tcp->state.index;
1692 	lnk->data.tcp->ack[i] = x;
1693 
1694 	i++;
1695 	if (i == N_LINK_TCP_DATA)
1696 		lnk->data.tcp->state.index = 0;
1697 	else
1698 		lnk->data.tcp->state.index = i;
1699 }
1700 
1701 void
1702 SetExpire(struct alias_link *lnk, int expire)
1703 {
1704 	if (expire == 0) {
1705 		lnk->flags &= ~LINK_PERMANENT;
1706 		DeleteLink(&lnk, 0);
1707 	} else if (expire == -1) {
1708 		lnk->flags |= LINK_PERMANENT;
1709 	} else if (expire > 0) {
1710 		lnk->expire.time = expire;
1711 	} else {
1712 #ifdef LIBALIAS_DEBUG
1713 		fprintf(stderr, "PacketAlias/SetExpire(): ");
1714 		fprintf(stderr, "error in expire parameter\n");
1715 #endif
1716 	}
1717 }
1718 
1719 void
1720 SetProtocolFlags(struct alias_link *lnk, int pflags)
1721 {
1722 	lnk->pflags = pflags;
1723 }
1724 
1725 int
1726 GetProtocolFlags(struct alias_link *lnk)
1727 {
1728 	return (lnk->pflags);
1729 }
1730 
1731 void
1732 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
1733 {
1734 	LIBALIAS_LOCK_ASSERT(lnk->la);
1735 	ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
1736 	    lnk->src_port, cid, lnk->alias_port, lnk->link_type, 1);
1737 }
1738 
1739 /* Miscellaneous Functions
1740 
1741     HouseKeeping()
1742     InitPacketAliasLog()
1743     UninitPacketAliasLog()
1744 */
1745 
1746 /*
1747     Whenever an outgoing or incoming packet is handled, HouseKeeping()
1748     is called to find and remove timed-out aliasing links.  Logic exists
1749     to sweep through the entire table and linked list structure
1750     every 60 seconds.
1751 
1752     (prototype in alias_local.h)
1753 */
1754 
1755 void
1756 HouseKeeping(struct libalias *la)
1757 {
1758 	static unsigned int packets = 0;
1759 	static unsigned int packet_limit = 1000;
1760 
1761 	LIBALIAS_LOCK_ASSERT(la);
1762 	packets++;
1763 
1764 	/*
1765 	 * User space time/gettimeofday/... is very expensive.
1766 	 * Kernel space cache trashing is unnecessary.
1767 	 *
1768 	 * Save system time (seconds) in global variable LibAliasTime
1769 	 * for use by other functions. This is done so as not to
1770 	 * unnecessarily waste timeline by making system calls.
1771 	 *
1772 	 * Reduce the amount of house keeping work substantially by
1773 	 * sampling over the packets.
1774 	 */
1775 	if (packets % packet_limit == 0) {
1776 		time_t now;
1777 
1778 #ifdef _KERNEL
1779 		now = time_uptime;
1780 #else
1781 		now = time(NULL);
1782 #endif
1783 		if (now != LibAliasTime) {
1784 			/* retry three times a second */
1785 			packet_limit = packets / 3;
1786 			packets = 0;
1787 			LibAliasTime = now;
1788 		}
1789 
1790 	}
1791 	/* Do a cleanup for the first packets of the new second only */
1792 	if (packets < (la->udpLinkCount + la->tcpLinkCount)) {
1793 		struct alias_link * lnk = TAILQ_FIRST(&la->checkExpire);
1794 
1795 		CleanupLink(la, &lnk, 0);
1796 	}
1797 }
1798 
1799 /* Init the log file and enable logging */
1800 static int
1801 InitPacketAliasLog(struct libalias *la)
1802 {
1803 	LIBALIAS_LOCK_ASSERT(la);
1804 	if (~la->packetAliasMode & PKT_ALIAS_LOG) {
1805 #ifdef _KERNEL
1806 		if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
1807 			;
1808 #else
1809 		if ((la->logDesc = fopen("/var/log/alias.log", "w")))
1810 			fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1811 #endif
1812 		else
1813 			return (ENOMEM); /* log initialization failed */
1814 		la->packetAliasMode |= PKT_ALIAS_LOG;
1815 	}
1816 
1817 	return (1);
1818 }
1819 
1820 /* Close the log-file and disable logging. */
1821 static void
1822 UninitPacketAliasLog(struct libalias *la)
1823 {
1824 	LIBALIAS_LOCK_ASSERT(la);
1825 	if (la->logDesc) {
1826 #ifdef _KERNEL
1827 		free(la->logDesc);
1828 #else
1829 		fclose(la->logDesc);
1830 #endif
1831 		la->logDesc = NULL;
1832 	}
1833 	la->packetAliasMode &= ~PKT_ALIAS_LOG;
1834 }
1835 
1836 /* Outside world interfaces
1837 
1838 -- "outside world" means other than alias*.c routines --
1839 
1840     PacketAliasRedirectPort()
1841     PacketAliasAddServer()
1842     PacketAliasRedirectProto()
1843     PacketAliasRedirectAddr()
1844     PacketAliasRedirectDynamic()
1845     PacketAliasRedirectDelete()
1846     PacketAliasSetAddress()
1847     PacketAliasInit()
1848     PacketAliasUninit()
1849     PacketAliasSetMode()
1850 
1851 (prototypes in alias.h)
1852 */
1853 
1854 /* Redirection from a specific public addr:port to a
1855    private addr:port */
1856 struct alias_link *
1857 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
1858     struct in_addr dst_addr, u_short dst_port,
1859     struct in_addr alias_addr, u_short alias_port,
1860     u_char proto)
1861 {
1862 	int link_type;
1863 	struct alias_link *lnk;
1864 
1865 	LIBALIAS_LOCK(la);
1866 	switch (proto) {
1867 	case IPPROTO_UDP:
1868 		link_type = LINK_UDP;
1869 		break;
1870 	case IPPROTO_TCP:
1871 		link_type = LINK_TCP;
1872 		break;
1873 	case IPPROTO_SCTP:
1874 		link_type = LINK_SCTP;
1875 		break;
1876 	default:
1877 #ifdef LIBALIAS_DEBUG
1878 		fprintf(stderr, "PacketAliasRedirectPort(): ");
1879 		fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
1880 #endif
1881 		lnk = NULL;
1882 		goto getout;
1883 	}
1884 
1885 	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1886 	    src_port, dst_port, alias_port,
1887 	    link_type);
1888 
1889 	if (lnk != NULL) {
1890 		lnk->flags |= LINK_PERMANENT;
1891 	}
1892 #ifdef LIBALIAS_DEBUG
1893 	else {
1894 		fprintf(stderr, "PacketAliasRedirectPort(): "
1895 		    "call to AddLink() failed\n");
1896 	}
1897 #endif
1898 
1899 getout:
1900 	LIBALIAS_UNLOCK(la);
1901 	return (lnk);
1902 }
1903 
1904 /* Add server to the pool of servers */
1905 int
1906 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
1907 {
1908 	struct server *server;
1909 	int res;
1910 
1911 	LIBALIAS_LOCK(la);
1912 	(void)la;
1913 
1914 	switch (lnk->link_type) {
1915 	case LINK_PPTP:
1916 		server = NULL;
1917 		break;
1918 	default:
1919 		server = malloc(sizeof(struct server));
1920 		break;
1921 	}
1922 
1923 	if (server != NULL) {
1924 		struct server *head;
1925 
1926 		server->addr = addr;
1927 		server->port = port;
1928 
1929 		head = lnk->server;
1930 		if (head == NULL) {
1931 			server->next = server;
1932 			/* not usable for outgoing connections */
1933 			SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
1934 		} else {
1935 			struct server *s;
1936 
1937 			for (s = head; s->next != head; s = s->next)
1938 				;
1939 			s->next = server;
1940 			server->next = head;
1941 		}
1942 		lnk->server = server;
1943 		res = 0;
1944 	} else
1945 		res = -1;
1946 
1947 	LIBALIAS_UNLOCK(la);
1948 	return (res);
1949 }
1950 
1951 /* Redirect packets of a given IP protocol from a specific
1952    public address to a private address */
1953 struct alias_link *
1954 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
1955     struct in_addr dst_addr,
1956     struct in_addr alias_addr,
1957     u_char proto)
1958 {
1959 	struct alias_link *lnk;
1960 
1961 	LIBALIAS_LOCK(la);
1962 	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1963 	    NO_SRC_PORT, NO_DEST_PORT, 0,
1964 	    proto);
1965 
1966 	if (lnk != NULL) {
1967 		lnk->flags |= LINK_PERMANENT;
1968 	}
1969 #ifdef LIBALIAS_DEBUG
1970 	else {
1971 		fprintf(stderr, "PacketAliasRedirectProto(): "
1972 		    "call to AddLink() failed\n");
1973 	}
1974 #endif
1975 
1976 	LIBALIAS_UNLOCK(la);
1977 	return (lnk);
1978 }
1979 
1980 /* Static address translation */
1981 struct alias_link *
1982 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
1983     struct in_addr alias_addr)
1984 {
1985 	struct alias_link *lnk;
1986 
1987 	LIBALIAS_LOCK(la);
1988 	lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr,
1989 	    0, 0, 0,
1990 	    LINK_ADDR);
1991 
1992 	if (lnk != NULL) {
1993 		lnk->flags |= LINK_PERMANENT;
1994 	}
1995 #ifdef LIBALIAS_DEBUG
1996 	else {
1997 		fprintf(stderr, "PacketAliasRedirectAddr(): "
1998 		    "call to AddLink() failed\n");
1999 	}
2000 #endif
2001 
2002 	LIBALIAS_UNLOCK(la);
2003 	return (lnk);
2004 }
2005 
2006 /* Mark the aliasing link dynamic */
2007 int
2008 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2009 {
2010 	int res;
2011 
2012 	LIBALIAS_LOCK(la);
2013 	(void)la;
2014 
2015 	if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2016 		res = -1;
2017 	else {
2018 		lnk->flags &= ~LINK_PERMANENT;
2019 		res = 0;
2020 	}
2021 	LIBALIAS_UNLOCK(la);
2022 	return (res);
2023 }
2024 
2025 /* This is a dangerous function to put in the API,
2026    because an invalid pointer can crash the program. */
2027 void
2028 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2029 {
2030 	LIBALIAS_LOCK(la);
2031 	(void)la;
2032 	DeleteLink(&lnk, 1);
2033 	LIBALIAS_UNLOCK(la);
2034 }
2035 
2036 void
2037 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2038 {
2039 	LIBALIAS_LOCK(la);
2040 	if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2041 	    && la->aliasAddress.s_addr != addr.s_addr)
2042 		CleanupAliasData(la, 0);
2043 
2044 	la->aliasAddress = addr;
2045 	LIBALIAS_UNLOCK(la);
2046 }
2047 
2048 void
2049 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
2050     u_short port_high)
2051 {
2052 	LIBALIAS_LOCK(la);
2053 	la->aliasPortLower = port_low;
2054 	/* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
2055 	la->aliasPortLength = port_high - port_low + 1;
2056 	LIBALIAS_UNLOCK(la);
2057 }
2058 
2059 void
2060 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2061 {
2062 	LIBALIAS_LOCK(la);
2063 	la->targetAddress = target_addr;
2064 	LIBALIAS_UNLOCK(la);
2065 }
2066 
2067 static void
2068 finishoff(void)
2069 {
2070 	while (!LIST_EMPTY(&instancehead))
2071 		LibAliasUninit(LIST_FIRST(&instancehead));
2072 }
2073 
2074 struct libalias *
2075 LibAliasInit(struct libalias *la)
2076 {
2077 	if (la == NULL) {
2078 #ifdef _KERNEL
2079 #undef malloc	/* XXX: ugly */
2080 		la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2081 #else
2082 		la = calloc(sizeof *la, 1);
2083 		if (la == NULL)
2084 			return (la);
2085 #endif
2086 
2087 #ifndef _KERNEL
2088 		/* kernel cleans up on module unload */
2089 		if (LIST_EMPTY(&instancehead))
2090 			atexit(finishoff);
2091 #endif
2092 		LIST_INSERT_HEAD(&instancehead, la, instancelist);
2093 
2094 #ifdef _KERNEL
2095 		LibAliasTime = time_uptime;
2096 #else
2097 		LibAliasTime = time(NULL);
2098 #endif
2099 
2100 		SPLAY_INIT(&la->linkSplayIn);
2101 		SPLAY_INIT(&la->linkSplayOut);
2102 		LIST_INIT(&la->pptpList);
2103 		TAILQ_INIT(&la->checkExpire);
2104 #ifdef _KERNEL
2105 		AliasSctpInit(la);
2106 #endif
2107 		LIBALIAS_LOCK_INIT(la);
2108 		LIBALIAS_LOCK(la);
2109 	} else {
2110 		LIBALIAS_LOCK(la);
2111 		CleanupAliasData(la, 1);
2112 #ifdef _KERNEL
2113 		AliasSctpTerm(la);
2114 		AliasSctpInit(la);
2115 #endif
2116 	}
2117 
2118 	la->aliasAddress.s_addr = INADDR_ANY;
2119 	la->targetAddress.s_addr = INADDR_ANY;
2120 	la->aliasPortLower = 0x8000;
2121 	la->aliasPortLength = 0x8000;
2122 
2123 	la->icmpLinkCount = 0;
2124 	la->udpLinkCount = 0;
2125 	la->tcpLinkCount = 0;
2126 	la->sctpLinkCount = 0;
2127 	la->pptpLinkCount = 0;
2128 	la->protoLinkCount = 0;
2129 	la->fragmentIdLinkCount = 0;
2130 	la->fragmentPtrLinkCount = 0;
2131 	la->sockCount = 0;
2132 
2133 	la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2134 #ifndef NO_USE_SOCKETS
2135 	    | PKT_ALIAS_USE_SOCKETS
2136 #endif
2137 	    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2138 #ifndef NO_FW_PUNCH
2139 	la->fireWallFD = -1;
2140 #endif
2141 #ifndef _KERNEL
2142 	LibAliasRefreshModules();
2143 #endif
2144 	LIBALIAS_UNLOCK(la);
2145 	return (la);
2146 }
2147 
2148 void
2149 LibAliasUninit(struct libalias *la)
2150 {
2151 	LIBALIAS_LOCK(la);
2152 #ifdef _KERNEL
2153 	AliasSctpTerm(la);
2154 #endif
2155 	CleanupAliasData(la, 1);
2156 	UninitPacketAliasLog(la);
2157 #ifndef NO_FW_PUNCH
2158 	UninitPunchFW(la);
2159 #endif
2160 	LIST_REMOVE(la, instancelist);
2161 	LIBALIAS_UNLOCK(la);
2162 	LIBALIAS_LOCK_DESTROY(la);
2163 	free(la);
2164 }
2165 
2166 /* Change mode for some operations */
2167 unsigned int
2168 LibAliasSetMode(
2169     struct libalias *la,
2170     unsigned int flags,		/* Which state to bring flags to */
2171     unsigned int mask		/* Mask of which flags to affect (use 0 to
2172 				 * do a probe for flag values) */
2173 )
2174 {
2175 	int res = -1;
2176 
2177 	LIBALIAS_LOCK(la);
2178 	if (flags & mask & PKT_ALIAS_LOG) {
2179 		/* Enable logging */
2180 		if (InitPacketAliasLog(la) == ENOMEM)
2181 			goto getout;
2182 	} else if (~flags & mask & PKT_ALIAS_LOG)
2183 		/* _Disable_ logging */
2184 		UninitPacketAliasLog(la);
2185 
2186 #ifndef NO_FW_PUNCH
2187 	if (flags & mask & PKT_ALIAS_PUNCH_FW)
2188 		/* Start punching holes in the firewall? */
2189 		InitPunchFW(la);
2190 	else if (~flags & mask & PKT_ALIAS_PUNCH_FW)
2191 		/* Stop punching holes in the firewall? */
2192 		UninitPunchFW(la);
2193 #endif
2194 
2195 	/* Other flags can be set/cleared without special action */
2196 	la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2197 	res = la->packetAliasMode;
2198 getout:
2199 	LIBALIAS_UNLOCK(la);
2200 	return (res);
2201 }
2202 
2203 #ifndef NO_FW_PUNCH
2204 
2205 /*****************
2206   Code to support firewall punching.  This shouldn't really be in this
2207   file, but making variables global is evil too.
2208   ****************/
2209 
2210 /* Firewall include files */
2211 #include <net/if.h>
2212 #include <netinet/ip_fw.h>
2213 #include <string.h>
2214 #include <err.h>
2215 
2216 /*
2217  * helper function, updates the pointer to cmd with the length
2218  * of the current command, and also cleans up the first word of
2219  * the new command in case it has been clobbered before.
2220  */
2221 static ipfw_insn *
2222 next_cmd(ipfw_insn * cmd)
2223 {
2224 	cmd += F_LEN(cmd);
2225 	bzero(cmd, sizeof(*cmd));
2226 	return (cmd);
2227 }
2228 
2229 /*
2230  * A function to fill simple commands of size 1.
2231  * Existing flags are preserved.
2232  */
2233 static ipfw_insn *
2234 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2235     int flags, u_int16_t arg)
2236 {
2237 	cmd->opcode = opcode;
2238 	cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2239 	cmd->arg1 = arg;
2240 	return next_cmd(cmd);
2241 }
2242 
2243 static ipfw_insn *
2244 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2245 {
2246 	ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2247 
2248 	cmd->addr.s_addr = addr;
2249 	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2250 }
2251 
2252 static ipfw_insn *
2253 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2254 {
2255 	ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2256 
2257 	cmd->ports[0] = cmd->ports[1] = port;
2258 	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2259 }
2260 
2261 static int
2262 fill_rule(void *buf, int bufsize, int rulenum,
2263     enum ipfw_opcodes action, int proto,
2264     struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2265 {
2266 	struct ip_fw *rule = (struct ip_fw *)buf;
2267 	ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2268 
2269 	bzero(buf, bufsize);
2270 	rule->rulenum = rulenum;
2271 
2272 	cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2273 	cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2274 	cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2275 	cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2276 	cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2277 
2278 	rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2279 	cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2280 
2281 	rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2282 
2283 	return ((char *)cmd - (char *)buf);
2284 }
2285 
2286 static void
2287 InitPunchFW(struct libalias *la)
2288 {
2289 	la->fireWallField = malloc(la->fireWallNumNums);
2290 	if (la->fireWallField) {
2291 		memset(la->fireWallField, 0, la->fireWallNumNums);
2292 		if (la->fireWallFD < 0) {
2293 			la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2294 		}
2295 		ClearAllFWHoles(la);
2296 		la->fireWallActiveNum = la->fireWallBaseNum;
2297 	}
2298 }
2299 
2300 static void
2301 UninitPunchFW(struct libalias *la)
2302 {
2303 	ClearAllFWHoles(la);
2304 	if (la->fireWallFD >= 0)
2305 		close(la->fireWallFD);
2306 	la->fireWallFD = -1;
2307 	if (la->fireWallField)
2308 		free(la->fireWallField);
2309 	la->fireWallField = NULL;
2310 	la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2311 }
2312 
2313 /* Make a certain link go through the firewall */
2314 void
2315 PunchFWHole(struct alias_link *lnk)
2316 {
2317 	struct libalias *la;
2318 	int r;			/* Result code */
2319 	struct ip_fw rule;	/* On-the-fly built rule */
2320 	int fwhole;		/* Where to punch hole */
2321 
2322 	la = lnk->la;
2323 
2324 	/* Don't do anything unless we are asked to */
2325 	if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2326 	    la->fireWallFD < 0 ||
2327 	    lnk->link_type != LINK_TCP)
2328 		return;
2329 
2330 	memset(&rule, 0, sizeof rule);
2331 
2332 	/** Build rule **/
2333 
2334 	/* Find empty slot */
2335 	for (fwhole = la->fireWallActiveNum;
2336 	    fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2337 	    fw_tstfield(la, la->fireWallField, fwhole);
2338 	    fwhole++);
2339 	if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2340 		for (fwhole = la->fireWallBaseNum;
2341 		    fwhole < la->fireWallActiveNum &&
2342 		    fw_tstfield(la, la->fireWallField, fwhole);
2343 		    fwhole++);
2344 		if (fwhole == la->fireWallActiveNum) {
2345 			/* No rule point empty - we can't punch more holes. */
2346 			la->fireWallActiveNum = la->fireWallBaseNum;
2347 #ifdef LIBALIAS_DEBUG
2348 			fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2349 #endif
2350 			return;
2351 		}
2352 	}
2353 	/* Start next search at next position */
2354 	la->fireWallActiveNum = fwhole + 1;
2355 
2356 	/*
2357 	 * generate two rules of the form
2358 	 *
2359 	 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2360 	 * accept tcp from DAddr DPort to OAddr OPort
2361 	 */
2362 	if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2363 		u_int32_t rulebuf[255];
2364 		int i;
2365 
2366 		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2367 		    O_ACCEPT, IPPROTO_TCP,
2368 		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2369 		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2370 		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2371 		if (r)
2372 			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2373 
2374 		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2375 		    O_ACCEPT, IPPROTO_TCP,
2376 		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2377 		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2378 		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2379 		if (r)
2380 			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2381 	}
2382 
2383 	/* Indicate hole applied */
2384 	lnk->data.tcp->fwhole = fwhole;
2385 	fw_setfield(la, la->fireWallField, fwhole);
2386 }
2387 
2388 /* Remove a hole in a firewall associated with a particular alias
2389    lnk.  Calling this too often is harmless. */
2390 static void
2391 ClearFWHole(struct alias_link *lnk)
2392 {
2393 	struct libalias *la;
2394 
2395 	la = lnk->la;
2396 	if (lnk->link_type == LINK_TCP) {
2397 		int fwhole = lnk->data.tcp->fwhole;  /* Where is the firewall hole? */
2398 		struct ip_fw rule;
2399 
2400 		if (fwhole < 0)
2401 			return;
2402 
2403 		memset(&rule, 0, sizeof rule);	/* useless for ipfw2 */
2404 		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2405 		    &fwhole, sizeof fwhole));
2406 		fw_clrfield(la, la->fireWallField, fwhole);
2407 		lnk->data.tcp->fwhole = -1;
2408 	}
2409 }
2410 
2411 /* Clear out the entire range dedicated to firewall holes. */
2412 static void
2413 ClearAllFWHoles(struct libalias *la)
2414 {
2415 	struct ip_fw rule;	/* On-the-fly built rule */
2416 	int i;
2417 
2418 	if (la->fireWallFD < 0)
2419 		return;
2420 
2421 	memset(&rule, 0, sizeof rule);
2422 	for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2423 		int r = i;
2424 
2425 		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2426 	}
2427 	/* XXX: third arg correct here ? /phk */
2428 	memset(la->fireWallField, 0, la->fireWallNumNums);
2429 }
2430 
2431 #endif /* !NO_FW_PUNCH */
2432 
2433 void
2434 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2435 {
2436 	LIBALIAS_LOCK(la);
2437 #ifndef NO_FW_PUNCH
2438 	la->fireWallBaseNum = base;
2439 	la->fireWallNumNums = num;
2440 #endif
2441 	LIBALIAS_UNLOCK(la);
2442 }
2443 
2444 void
2445 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2446 {
2447 	LIBALIAS_LOCK(la);
2448 	la->skinnyPort = port;
2449 	LIBALIAS_UNLOCK(la);
2450 }
2451 
2452 /*
2453  * Find the address to redirect incoming packets
2454  */
2455 struct in_addr
2456 FindSctpRedirectAddress(struct libalias *la,  struct sctp_nat_msg *sm)
2457 {
2458 	struct alias_link *lnk;
2459 	struct in_addr redir;
2460 
2461 	LIBALIAS_LOCK_ASSERT(la);
2462 	lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2463 	    sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2464 	if (lnk != NULL) {
2465 		/* port redirect */
2466 		return (lnk->src_addr);
2467 	} else {
2468 		redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2469 		if (redir.s_addr == la->aliasAddress.s_addr ||
2470 		    redir.s_addr == la->targetAddress.s_addr) {
2471 			/* No address found */
2472 			lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2473 			    NO_DEST_PORT, 0, LINK_SCTP, 1);
2474 			if (lnk != NULL)
2475 				/* redirect proto */
2476 				return (lnk->src_addr);
2477 		}
2478 		return (redir); /* address redirect */
2479 	}
2480 }
2481