1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Charles Mott <[email protected]>
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 	default:
617 		lnk->expire.time = PROTO_EXPIRE_TIME;
618 		break;
619 	}
620 
621 	/* Determine alias flags */
622 	if (dst_addr.s_addr == INADDR_ANY)
623 		lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
624 	if (dst_port == 0)
625 		lnk->flags |= LINK_UNKNOWN_DEST_PORT;
626 
627 	/* Determine alias port */
628 	if (GetNewPort(la, lnk, alias_port_param) != 0) {
629 		free(lnk);
630 		return (NULL);
631 	}
632 	/* Link-type dependent initialization */
633 	switch (link_type) {
634 	case LINK_ICMP:
635 		la->icmpLinkCount++;
636 		break;
637 	case LINK_UDP:
638 		la->udpLinkCount++;
639 		break;
640 	case LINK_TCP: {
641 		struct tcp_dat *aux_tcp;
642 		int i;
643 
644 		aux_tcp = malloc(sizeof(struct tcp_dat));
645 		if (aux_tcp == NULL) {
646 #ifdef LIBALIAS_DEBUG
647 			fprintf(stderr, "PacketAlias/AddLink: ");
648 			fprintf(stderr, " cannot allocate auxiliary TCP data\n");
649 #endif
650 			free(lnk);
651 			return (NULL);
652 		}
653 
654 		la->tcpLinkCount++;
655 		aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
656 		aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
657 		aux_tcp->state.index = 0;
658 		aux_tcp->state.ack_modified = 0;
659 		for (i = 0; i < N_LINK_TCP_DATA; i++)
660 			aux_tcp->ack[i].active = 0;
661 		aux_tcp->fwhole = -1;
662 		lnk->data.tcp = aux_tcp;
663 	}
664 		break;
665 	case LINK_PPTP:
666 		la->pptpLinkCount++;
667 		break;
668 	case LINK_FRAGMENT_ID:
669 		la->fragmentIdLinkCount++;
670 		break;
671 	case LINK_FRAGMENT_PTR:
672 		la->fragmentPtrLinkCount++;
673 		break;
674 	case LINK_ADDR:
675 		break;
676 	default:
677 		la->protoLinkCount++;
678 		break;
679 	}
680 
681 	switch (link_type) {
682 	case LINK_PPTP:
683 		LIST_INSERT_HEAD(&la->pptpList, lnk, pptp.list);
684 		break;
685 	default: {
686 		struct group_in *grp;
687 
688 		grp = StartPointIn(la, alias_addr, lnk->alias_port, link_type, 1);
689 		if (grp == NULL) {
690 			free(lnk);
691 			return (NULL);
692 		}
693 
694 		/* Set up pointers for output lookup table */
695 		SPLAY_INSERT(splay_out, &la->linkSplayOut, lnk);
696 
697 		/* Set up pointers for input lookup table */
698 		if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
699 			LIST_INSERT_HEAD(&grp->partial, lnk, all.in);
700 		else
701 			LIST_INSERT_HEAD(&grp->full, lnk, all.in);
702 	}
703 		break;
704 	}
705 
706 	/* Include the element into the housekeeping list */
707 	TAILQ_INSERT_TAIL(&la->checkExpire, lnk, expire.list);
708 
709 	if (la->packetAliasMode & PKT_ALIAS_LOG)
710 		ShowAliasStats(la);
711 
712 	return (lnk);
713 }
714 
715 /*
716  * If alias_port_param is less than zero, alias port will be automatically
717  * chosen. If greater than zero, equal to alias port
718  */
719 static struct alias_link *
720 ReLink(struct alias_link *old_lnk,
721     struct in_addr src_addr,
722     struct in_addr dst_addr,
723     struct in_addr alias_addr,
724     u_short src_port,
725     u_short dst_port,
726     int alias_port_param,
727     int link_type,
728     int deletePermanent)
729 {
730 	struct alias_link *new_lnk;
731 	struct libalias *la = old_lnk->la;
732 
733 	LIBALIAS_LOCK_ASSERT(la);
734 	new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
735 	    src_port, dst_port, alias_port_param,
736 	    link_type);
737 #ifndef NO_FW_PUNCH
738 	if (new_lnk != NULL &&
739 	    old_lnk->link_type == LINK_TCP &&
740 	    old_lnk->data.tcp->fwhole > 0) {
741 		PunchFWHole(new_lnk);
742 	}
743 #endif
744 	DeleteLink(&old_lnk, deletePermanent);
745 	return (new_lnk);
746 }
747 
748 static struct alias_link *
749 _SearchLinkOut(struct libalias *la, struct in_addr src_addr,
750     struct in_addr dst_addr,
751     u_short src_port,
752     u_short dst_port,
753     int link_type) {
754 	struct alias_link *lnk;
755 	struct alias_link needle = {
756 		.src_addr = src_addr,
757 		.dst_addr = dst_addr,
758 		.src_port = src_port,
759 		.dst_port = dst_port,
760 		.link_type = link_type
761 	};
762 
763 	lnk = SPLAY_FIND(splay_out, &la->linkSplayOut, &needle);
764 	return (UseLink(la, lnk));
765 }
766 
767 static struct alias_link *
768 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
769     struct in_addr dst_addr,
770     u_short src_port,
771     u_short dst_port,
772     int link_type,
773     int replace_partial_links)
774 {
775 	struct alias_link *lnk;
776 
777 	LIBALIAS_LOCK_ASSERT(la);
778 	lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type);
779 	if (lnk != NULL || !replace_partial_links)
780 		return (lnk);
781 
782 	/* Search for partially specified links. */
783 	if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
784 		lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, 0,
785 		    link_type);
786 		if (lnk == NULL)
787 			lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port,
788 			    dst_port, link_type);
789 	}
790 	if (lnk == NULL &&
791 	    (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
792 		lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, 0,
793 		    link_type);
794 	}
795 	if (lnk != NULL) {
796 		lnk = ReLink(lnk,
797 		    src_addr, dst_addr, lnk->alias_addr,
798 		    src_port, dst_port, lnk->alias_port,
799 		    link_type, 0);
800 	}
801 	return (lnk);
802 }
803 
804 static struct alias_link *
805 FindLinkOut(struct libalias *la, struct in_addr src_addr,
806     struct in_addr dst_addr,
807     u_short src_port,
808     u_short dst_port,
809     int link_type,
810     int replace_partial_links)
811 {
812 	struct alias_link *lnk;
813 
814 	LIBALIAS_LOCK_ASSERT(la);
815 	lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
816 	    link_type, replace_partial_links);
817 
818 	if (lnk == NULL) {
819 		/*
820 		 * The following allows permanent links to be specified as
821 		 * using the default source address (i.e. device interface
822 		 * address) without knowing in advance what that address
823 		 * is.
824 		 */
825 		if (la->aliasAddress.s_addr != INADDR_ANY &&
826 		    src_addr.s_addr == la->aliasAddress.s_addr) {
827 			lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port,
828 			    link_type, replace_partial_links);
829 		}
830 	}
831 	return (lnk);
832 }
833 
834 static struct alias_link *
835 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
836     struct in_addr alias_addr,
837     u_short dst_port,
838     u_short alias_port,
839     int link_type,
840     int replace_partial_links)
841 {
842 	int flags_in;
843 	struct group_in *grp;
844 	struct alias_link *lnk;
845 	struct alias_link *lnk_unknown_all;
846 	struct alias_link *lnk_unknown_dst_addr;
847 	struct alias_link *lnk_unknown_dst_port;
848 	struct in_addr src_addr;
849 	u_short src_port;
850 
851 	LIBALIAS_LOCK_ASSERT(la);
852 	/* Initialize pointers */
853 	lnk_unknown_all = NULL;
854 	lnk_unknown_dst_addr = NULL;
855 	lnk_unknown_dst_port = NULL;
856 
857 	/* If either the dest addr or port is unknown, the search
858 	 * loop will have to know about this. */
859 	flags_in = 0;
860 	if (dst_addr.s_addr == INADDR_ANY)
861 		flags_in |= LINK_UNKNOWN_DEST_ADDR;
862 	if (dst_port == 0)
863 		flags_in |= LINK_UNKNOWN_DEST_PORT;
864 
865 	/* Search loop */
866 	grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
867 	if (grp == NULL)
868 		return (NULL);
869 
870 	switch (flags_in) {
871 	case 0:
872 		LIST_FOREACH(lnk, &grp->full, all.in) {
873 			if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
874 			    lnk->dst_port == dst_port)
875 				return (UseLink(la, lnk));
876 		}
877 		break;
878 	case LINK_UNKNOWN_DEST_PORT:
879 		LIST_FOREACH(lnk, &grp->full, all.in) {
880 			if(lnk->dst_addr.s_addr == dst_addr.s_addr) {
881 				lnk_unknown_dst_port = lnk;
882 				break;
883 			}
884 		}
885 		break;
886 	case LINK_UNKNOWN_DEST_ADDR:
887 		LIST_FOREACH(lnk, &grp->full, all.in) {
888 			if(lnk->dst_port == dst_port) {
889 				lnk_unknown_dst_addr = lnk;
890 				break;
891 			}
892 		}
893 		break;
894 	case LINK_PARTIALLY_SPECIFIED:
895 		lnk_unknown_all = LIST_FIRST(&grp->full);
896 		break;
897 	}
898 
899 	if (lnk_unknown_dst_port == NULL) {
900 		LIST_FOREACH(lnk, &grp->partial, all.in) {
901 			int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED;
902 
903 			if (flags == LINK_PARTIALLY_SPECIFIED &&
904 			    lnk_unknown_all == NULL)
905 				lnk_unknown_all = lnk;
906 			if (flags == LINK_UNKNOWN_DEST_ADDR &&
907 			    lnk->dst_port == dst_port &&
908 			    lnk_unknown_dst_addr == NULL)
909 				lnk_unknown_dst_addr = lnk;
910 			if (flags == LINK_UNKNOWN_DEST_PORT &&
911 			    lnk->dst_addr.s_addr == dst_addr.s_addr) {
912 				lnk_unknown_dst_port = lnk;
913 				break;
914 			}
915 		}
916 	}
917 
918 	lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port
919 	    : (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr
920 	    : lnk_unknown_all;
921 
922 	if (lnk == NULL || !replace_partial_links)
923 		return (lnk);
924 
925 	if (lnk->server != NULL) {	/* LSNAT link */
926 		src_addr = lnk->server->addr;
927 		src_port = lnk->server->port;
928 		lnk->server = lnk->server->next;
929 	} else {
930 		src_addr = lnk->src_addr;
931 		src_port = lnk->src_port;
932 	}
933 
934 	if (link_type == LINK_SCTP) {
935 		lnk->src_addr = src_addr;
936 		lnk->src_port = src_port;
937 	} else {
938 		lnk = ReLink(lnk,
939 		    src_addr, dst_addr, alias_addr,
940 		    src_port, dst_port, alias_port,
941 		    link_type, 0);
942 	}
943 	return (lnk);
944 }
945 
946 static struct alias_link *
947 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
948     struct in_addr alias_addr,
949     u_short dst_port,
950     u_short alias_port,
951     int link_type,
952     int replace_partial_links)
953 {
954 	struct alias_link *lnk;
955 
956 	LIBALIAS_LOCK_ASSERT(la);
957 	lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
958 	    link_type, replace_partial_links);
959 
960 	if (lnk == NULL) {
961 		/*
962 		 * The following allows permanent links to be specified as
963 		 * using the default aliasing address (i.e. device
964 		 * interface address) without knowing in advance what that
965 		 * address is.
966 		 */
967 		if (la->aliasAddress.s_addr != INADDR_ANY &&
968 		    alias_addr.s_addr == la->aliasAddress.s_addr) {
969 			lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port,
970 			    link_type, replace_partial_links);
971 		}
972 	}
973 	return (lnk);
974 }
975 
976 /* External routines for finding/adding links
977 
978 -- "external" means outside alias_db.c, but within alias*.c --
979 
980     FindIcmpIn(), FindIcmpOut()
981     FindFragmentIn1(), FindFragmentIn2()
982     AddFragmentPtrLink(), FindFragmentPtr()
983     FindProtoIn(), FindProtoOut()
984     FindUdpTcpIn(), FindUdpTcpOut()
985     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
986     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
987     FindOriginalAddress(), FindAliasAddress()
988 
989 (prototypes in alias_local.h)
990 */
991 
992 struct alias_link *
993 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
994     struct in_addr alias_addr,
995     u_short id_alias,
996     int create)
997 {
998 	struct alias_link *lnk;
999 
1000 	LIBALIAS_LOCK_ASSERT(la);
1001 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1002 	    NO_DEST_PORT, id_alias,
1003 	    LINK_ICMP, 0);
1004 	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1005 		struct in_addr target_addr;
1006 
1007 		target_addr = FindOriginalAddress(la, alias_addr);
1008 		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1009 		    id_alias, NO_DEST_PORT, id_alias,
1010 		    LINK_ICMP);
1011 	}
1012 	return (lnk);
1013 }
1014 
1015 struct alias_link *
1016 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1017     struct in_addr dst_addr,
1018     u_short id,
1019     int create)
1020 {
1021 	struct alias_link *lnk;
1022 
1023 	LIBALIAS_LOCK_ASSERT(la);
1024 	lnk = FindLinkOut(la, src_addr, dst_addr,
1025 	    id, NO_DEST_PORT,
1026 	    LINK_ICMP, 0);
1027 	if (lnk == NULL && create) {
1028 		struct in_addr alias_addr;
1029 
1030 		alias_addr = FindAliasAddress(la, src_addr);
1031 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1032 		    id, NO_DEST_PORT, GET_ALIAS_ID,
1033 		    LINK_ICMP);
1034 	}
1035 	return (lnk);
1036 }
1037 
1038 struct alias_link *
1039 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1040     struct in_addr alias_addr,
1041     u_short ip_id)
1042 {
1043 	struct alias_link *lnk;
1044 
1045 	LIBALIAS_LOCK_ASSERT(la);
1046 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1047 	    NO_DEST_PORT, ip_id,
1048 	    LINK_FRAGMENT_ID, 0);
1049 
1050 	if (lnk == NULL) {
1051 		lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr,
1052 		    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1053 		    LINK_FRAGMENT_ID);
1054 	}
1055 	return (lnk);
1056 }
1057 
1058 /* Doesn't add a link if one is not found. */
1059 struct alias_link *
1060 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,
1061     struct in_addr alias_addr, u_short ip_id)
1062 {
1063 	LIBALIAS_LOCK_ASSERT(la);
1064 	return FindLinkIn(la, dst_addr, alias_addr,
1065 	    NO_DEST_PORT, ip_id,
1066 	    LINK_FRAGMENT_ID, 0);
1067 }
1068 
1069 struct alias_link *
1070 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1071     u_short ip_id)
1072 {
1073 	LIBALIAS_LOCK_ASSERT(la);
1074 	return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR,
1075 	    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1076 	    LINK_FRAGMENT_PTR);
1077 }
1078 
1079 struct alias_link *
1080 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1081     u_short ip_id)
1082 {
1083 	LIBALIAS_LOCK_ASSERT(la);
1084 	return FindLinkIn(la, dst_addr, ANY_ADDR,
1085 	    NO_DEST_PORT, ip_id,
1086 	    LINK_FRAGMENT_PTR, 0);
1087 }
1088 
1089 struct alias_link *
1090 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1091     struct in_addr alias_addr,
1092     u_char proto)
1093 {
1094 	struct alias_link *lnk;
1095 
1096 	LIBALIAS_LOCK_ASSERT(la);
1097 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1098 	    NO_DEST_PORT, 0,
1099 	    proto, 1);
1100 
1101 	if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1102 		struct in_addr target_addr;
1103 
1104 		target_addr = FindOriginalAddress(la, alias_addr);
1105 		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1106 		    NO_SRC_PORT, NO_DEST_PORT, 0,
1107 		    proto);
1108 	}
1109 	return (lnk);
1110 }
1111 
1112 struct alias_link *
1113 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1114     struct in_addr dst_addr,
1115     u_char proto)
1116 {
1117 	struct alias_link *lnk;
1118 
1119 	LIBALIAS_LOCK_ASSERT(la);
1120 	lnk = FindLinkOut(la, src_addr, dst_addr,
1121 	    NO_SRC_PORT, NO_DEST_PORT,
1122 	    proto, 1);
1123 
1124 	if (lnk == NULL) {
1125 		struct in_addr alias_addr;
1126 
1127 		alias_addr = FindAliasAddress(la, src_addr);
1128 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1129 		    NO_SRC_PORT, NO_DEST_PORT, 0,
1130 		    proto);
1131 	}
1132 	return (lnk);
1133 }
1134 
1135 struct alias_link *
1136 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1137     struct in_addr alias_addr,
1138     u_short dst_port,
1139     u_short alias_port,
1140     u_char proto,
1141     int create)
1142 {
1143 	int link_type;
1144 	struct alias_link *lnk;
1145 
1146 	LIBALIAS_LOCK_ASSERT(la);
1147 	switch (proto) {
1148 	case IPPROTO_UDP:
1149 		link_type = LINK_UDP;
1150 		break;
1151 	case IPPROTO_TCP:
1152 		link_type = LINK_TCP;
1153 		break;
1154 	default:
1155 		return (NULL);
1156 		break;
1157 	}
1158 
1159 	lnk = FindLinkIn(la, dst_addr, alias_addr,
1160 	    dst_port, alias_port,
1161 	    link_type, create);
1162 
1163 	if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1164 		struct in_addr target_addr;
1165 
1166 		target_addr = FindOriginalAddress(la, alias_addr);
1167 		lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1168 		    alias_port, dst_port, alias_port,
1169 		    link_type);
1170 	}
1171 	return (lnk);
1172 }
1173 
1174 struct alias_link *
1175 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1176     struct in_addr dst_addr,
1177     u_short src_port,
1178     u_short dst_port,
1179     u_char proto,
1180     int create)
1181 {
1182 	int link_type;
1183 	struct alias_link *lnk;
1184 
1185 	LIBALIAS_LOCK_ASSERT(la);
1186 	switch (proto) {
1187 	case IPPROTO_UDP:
1188 		link_type = LINK_UDP;
1189 		break;
1190 	case IPPROTO_TCP:
1191 		link_type = LINK_TCP;
1192 		break;
1193 	default:
1194 		return (NULL);
1195 		break;
1196 	}
1197 
1198 	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1199 
1200 	if (lnk == NULL && create) {
1201 		struct in_addr alias_addr;
1202 
1203 		alias_addr = FindAliasAddress(la, src_addr);
1204 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1205 		    src_port, dst_port, GET_ALIAS_PORT,
1206 		    link_type);
1207 	}
1208 	return (lnk);
1209 }
1210 
1211 struct alias_link *
1212 AddPptp(struct libalias *la, struct in_addr src_addr,
1213     struct in_addr dst_addr,
1214     struct in_addr alias_addr,
1215     u_int16_t src_call_id)
1216 {
1217 	struct alias_link *lnk;
1218 
1219 	LIBALIAS_LOCK_ASSERT(la);
1220 	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1221 	    src_call_id, 0, GET_ALIAS_PORT,
1222 	    LINK_PPTP);
1223 
1224 	return (lnk);
1225 }
1226 
1227 struct alias_link *
1228 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1229     struct in_addr dst_addr,
1230     u_int16_t src_call_id)
1231 {
1232 	struct alias_link *lnk;
1233 
1234 	LIBALIAS_LOCK_ASSERT(la);
1235 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1236 		if (lnk->src_addr.s_addr == src_addr.s_addr &&
1237 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1238 		    lnk->src_port == src_call_id)
1239 			break;
1240 
1241 	return (UseLink(la, lnk));
1242 }
1243 
1244 struct alias_link *
1245 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1246     struct in_addr dst_addr,
1247     u_int16_t dst_call_id)
1248 {
1249 	struct alias_link *lnk;
1250 
1251 	LIBALIAS_LOCK_ASSERT(la);
1252 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1253 		if (lnk->src_addr.s_addr == src_addr.s_addr &&
1254 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1255 		    lnk->dst_port == dst_call_id)
1256 			break;
1257 
1258 	return (UseLink(la, lnk));
1259 }
1260 
1261 struct alias_link *
1262 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1263     struct in_addr alias_addr,
1264     u_int16_t dst_call_id)
1265 {
1266 	struct alias_link *lnk;
1267 
1268 	LIBALIAS_LOCK_ASSERT(la);
1269 
1270 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1271 		if (lnk->dst_port == dst_call_id &&
1272 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1273 		    lnk->alias_addr.s_addr == alias_addr.s_addr)
1274 			break;
1275 
1276 	return (UseLink(la, lnk));
1277 }
1278 
1279 struct alias_link *
1280 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1281     struct in_addr alias_addr,
1282     u_int16_t alias_call_id)
1283 {
1284 	struct alias_link *lnk;
1285 
1286 	LIBALIAS_LOCK_ASSERT(la);
1287 	LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1288 		if (lnk->alias_port == alias_call_id &&
1289 		    lnk->dst_addr.s_addr == dst_addr.s_addr &&
1290 		    lnk->alias_addr.s_addr == alias_addr.s_addr)
1291 			break;
1292 
1293 	return (lnk);
1294 }
1295 
1296 struct alias_link *
1297 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1298     struct in_addr dst_addr,
1299     u_short src_port,
1300     u_short alias_port,
1301     u_char proto)
1302 {
1303 	int link_type;
1304 	struct alias_link *lnk;
1305 
1306 	LIBALIAS_LOCK_ASSERT(la);
1307 	switch (proto) {
1308 	case IPPROTO_UDP:
1309 		link_type = LINK_UDP;
1310 		break;
1311 	case IPPROTO_TCP:
1312 		link_type = LINK_TCP;
1313 		break;
1314 	default:
1315 		return (NULL);
1316 		break;
1317 	}
1318 
1319 	lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1320 
1321 	if (lnk == NULL) {
1322 		struct in_addr alias_addr;
1323 
1324 		alias_addr = FindAliasAddress(la, src_addr);
1325 		lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1326 		    src_port, 0, alias_port,
1327 		    link_type);
1328 	}
1329 	return (lnk);
1330 }
1331 
1332 struct in_addr
1333 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1334 {
1335 	struct alias_link *lnk;
1336 
1337 	LIBALIAS_LOCK_ASSERT(la);
1338 	lnk = FindLinkIn(la, ANY_ADDR, alias_addr,
1339 	    0, 0, LINK_ADDR, 0);
1340 	if (lnk == NULL) {
1341 		if (la->targetAddress.s_addr == INADDR_ANY)
1342 			return (alias_addr);
1343 		else if (la->targetAddress.s_addr == INADDR_NONE)
1344 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1345 			    la->aliasAddress : alias_addr;
1346 		else
1347 			return (la->targetAddress);
1348 	} else {
1349 		if (lnk->server != NULL) {	/* LSNAT link */
1350 			struct in_addr src_addr;
1351 
1352 			src_addr = lnk->server->addr;
1353 			lnk->server = lnk->server->next;
1354 			return (src_addr);
1355 		} else if (lnk->src_addr.s_addr == INADDR_ANY)
1356 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1357 			    la->aliasAddress : alias_addr;
1358 		else
1359 			return (lnk->src_addr);
1360 	}
1361 }
1362 
1363 struct in_addr
1364 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1365 {
1366 	struct alias_link *lnk;
1367 
1368 	LIBALIAS_LOCK_ASSERT(la);
1369 	lnk = FindLinkOut(la, original_addr, ANY_ADDR,
1370 	    0, 0, LINK_ADDR, 0);
1371 	if (lnk == NULL) {
1372 		return (la->aliasAddress.s_addr != INADDR_ANY) ?
1373 		    la->aliasAddress : original_addr;
1374 	} else {
1375 		if (lnk->alias_addr.s_addr == INADDR_ANY)
1376 			return (la->aliasAddress.s_addr != INADDR_ANY) ?
1377 			    la->aliasAddress : original_addr;
1378 		else
1379 			return (lnk->alias_addr);
1380 	}
1381 }
1382 
1383 /* External routines for getting or changing link data
1384    (external to alias_db.c, but internal to alias*.c)
1385 
1386     SetFragmentData(), GetFragmentData()
1387     SetFragmentPtr(), GetFragmentPtr()
1388     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1389     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1390     GetOriginalPort(), GetAliasPort()
1391     SetAckModified(), GetAckModified()
1392     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1393     SetProtocolFlags(), GetProtocolFlags()
1394     SetDestCallId()
1395 */
1396 
1397 void
1398 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1399 {
1400 	lnk->data.frag_addr = src_addr;
1401 }
1402 
1403 void
1404 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1405 {
1406 	*src_addr = lnk->data.frag_addr;
1407 }
1408 
1409 void
1410 SetFragmentPtr(struct alias_link *lnk, void *fptr)
1411 {
1412 	lnk->data.frag_ptr = fptr;
1413 }
1414 
1415 void
1416 GetFragmentPtr(struct alias_link *lnk, void **fptr)
1417 {
1418 	*fptr = lnk->data.frag_ptr;
1419 }
1420 
1421 void
1422 SetStateIn(struct alias_link *lnk, int state)
1423 {
1424 	/* TCP input state */
1425 	switch (state) {
1426 		case ALIAS_TCP_STATE_DISCONNECTED:
1427 		if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1428 			lnk->expire.time = TCP_EXPIRE_DEAD;
1429 		else
1430 			lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1431 		break;
1432 	case ALIAS_TCP_STATE_CONNECTED:
1433 		if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1434 			lnk->expire.time = TCP_EXPIRE_CONNECTED;
1435 		break;
1436 	default:
1437 #ifdef _KERNEL
1438 		panic("libalias:SetStateIn() unknown state");
1439 #else
1440 		abort();
1441 #endif
1442 	}
1443 	lnk->data.tcp->state.in = state;
1444 }
1445 
1446 void
1447 SetStateOut(struct alias_link *lnk, int state)
1448 {
1449 	/* TCP output state */
1450 	switch (state) {
1451 		case ALIAS_TCP_STATE_DISCONNECTED:
1452 		if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1453 			lnk->expire.time = TCP_EXPIRE_DEAD;
1454 		else
1455 			lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1456 		break;
1457 	case ALIAS_TCP_STATE_CONNECTED:
1458 		if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1459 			lnk->expire.time = TCP_EXPIRE_CONNECTED;
1460 		break;
1461 	default:
1462 #ifdef _KERNEL
1463 		panic("libalias:SetStateOut() unknown state");
1464 #else
1465 		abort();
1466 #endif
1467 	}
1468 	lnk->data.tcp->state.out = state;
1469 }
1470 
1471 int
1472 GetStateIn(struct alias_link *lnk)
1473 {
1474 	/* TCP input state */
1475 	return (lnk->data.tcp->state.in);
1476 }
1477 
1478 int
1479 GetStateOut(struct alias_link *lnk)
1480 {
1481 	/* TCP output state */
1482 	return (lnk->data.tcp->state.out);
1483 }
1484 
1485 struct in_addr
1486 GetOriginalAddress(struct alias_link *lnk)
1487 {
1488 	if (lnk->src_addr.s_addr == INADDR_ANY)
1489 		return (lnk->la->aliasAddress);
1490 	else
1491 		return (lnk->src_addr);
1492 }
1493 
1494 struct in_addr
1495 GetDestAddress(struct alias_link *lnk)
1496 {
1497 	return (lnk->dst_addr);
1498 }
1499 
1500 struct in_addr
1501 GetAliasAddress(struct alias_link *lnk)
1502 {
1503 	if (lnk->alias_addr.s_addr == INADDR_ANY)
1504 		return (lnk->la->aliasAddress);
1505 	else
1506 		return (lnk->alias_addr);
1507 }
1508 
1509 struct in_addr
1510 GetDefaultAliasAddress(struct libalias *la)
1511 {
1512 	LIBALIAS_LOCK_ASSERT(la);
1513 	return (la->aliasAddress);
1514 }
1515 
1516 void
1517 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1518 {
1519 	LIBALIAS_LOCK_ASSERT(la);
1520 	la->aliasAddress = alias_addr;
1521 }
1522 
1523 u_short
1524 GetOriginalPort(struct alias_link *lnk)
1525 {
1526 	return (lnk->src_port);
1527 }
1528 
1529 u_short
1530 GetAliasPort(struct alias_link *lnk)
1531 {
1532 	return (lnk->alias_port);
1533 }
1534 
1535 #ifndef NO_FW_PUNCH
1536 static u_short
1537 GetDestPort(struct alias_link *lnk)
1538 {
1539 	return (lnk->dst_port);
1540 }
1541 
1542 #endif
1543 
1544 /* Indicate that ACK numbers have been modified in a TCP connection */
1545 void
1546 SetAckModified(struct alias_link *lnk)
1547 {
1548 	lnk->data.tcp->state.ack_modified = 1;
1549 }
1550 
1551 struct in_addr
1552 GetProxyAddress(struct alias_link *lnk)
1553 {
1554 	return (lnk->proxy_addr);
1555 }
1556 
1557 void
1558 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1559 {
1560 	lnk->proxy_addr = addr;
1561 }
1562 
1563 u_short
1564 GetProxyPort(struct alias_link *lnk)
1565 {
1566 	return (lnk->proxy_port);
1567 }
1568 
1569 void
1570 SetProxyPort(struct alias_link *lnk, u_short port)
1571 {
1572 	lnk->proxy_port = port;
1573 }
1574 
1575 /* See if ACK numbers have been modified */
1576 int
1577 GetAckModified(struct alias_link *lnk)
1578 {
1579 	return (lnk->data.tcp->state.ack_modified);
1580 }
1581 
1582 /*
1583  * Find out how much the ACK number has been altered for an
1584  * incoming TCP packet.  To do this, a circular list of ACK
1585  * numbers where the TCP packet size was altered is searched.
1586  */
1587 // XXX ip free
1588 int
1589 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1590 {
1591 	int i, j;
1592 	int delta, ack_diff_min;
1593 
1594 	delta = 0;
1595 	ack_diff_min = -1;
1596 	i = lnk->data.tcp->state.index;
1597 	for (j = 0; j < N_LINK_TCP_DATA; j++) {
1598 		struct ack_data_record x;
1599 
1600 		if (i == 0)
1601 			i = N_LINK_TCP_DATA;
1602 		i--;
1603 		x = lnk->data.tcp->ack[i];
1604 		if (x.active == 1) {
1605 			int ack_diff;
1606 
1607 			ack_diff = SeqDiff(x.ack_new, ack);
1608 			if (ack_diff >= 0) {
1609 				if (ack_diff_min >= 0) {
1610 					if (ack_diff < ack_diff_min) {
1611 						delta = x.delta;
1612 						ack_diff_min = ack_diff;
1613 					}
1614 				} else {
1615 					delta = x.delta;
1616 					ack_diff_min = ack_diff;
1617 				}
1618 			}
1619 		}
1620 	}
1621 	return (delta);
1622 }
1623 
1624 /*
1625  * Find out how much the sequence number has been altered for an
1626  * outgoing TCP packet.  To do this, a circular list of ACK numbers
1627  * where the TCP packet size was altered is searched.
1628  */
1629 // XXX ip free
1630 int
1631 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
1632 {
1633 	int i, j;
1634 	int delta, seq_diff_min;
1635 
1636 	delta = 0;
1637 	seq_diff_min = -1;
1638 	i = lnk->data.tcp->state.index;
1639 	for (j = 0; j < N_LINK_TCP_DATA; j++) {
1640 		struct ack_data_record x;
1641 
1642 		if (i == 0)
1643 			i = N_LINK_TCP_DATA;
1644 		i--;
1645 		x = lnk->data.tcp->ack[i];
1646 		if (x.active == 1) {
1647 			int seq_diff;
1648 
1649 			seq_diff = SeqDiff(x.ack_old, seq);
1650 			if (seq_diff >= 0) {
1651 				if (seq_diff_min >= 0) {
1652 					if (seq_diff < seq_diff_min) {
1653 						delta = x.delta;
1654 						seq_diff_min = seq_diff;
1655 					}
1656 				} else {
1657 					delta = x.delta;
1658 					seq_diff_min = seq_diff;
1659 				}
1660 			}
1661 		}
1662 	}
1663 	return (delta);
1664 }
1665 
1666 /*
1667  * When a TCP packet has been altered in length, save this
1668  * information in a circular list.  If enough packets have been
1669  * altered, then this list will begin to overwrite itself.
1670  */
1671 // XXX ip free
1672 void
1673 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
1674     u_long th_seq, u_int th_off)
1675 {
1676 	struct ack_data_record x;
1677 	int hlen, tlen, dlen;
1678 	int i;
1679 
1680 	hlen = (ip_hl + th_off) << 2;
1681 	tlen = ntohs(ip_len);
1682 	dlen = tlen - hlen;
1683 
1684 	x.ack_old = htonl(ntohl(th_seq) + dlen);
1685 	x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
1686 	x.delta = delta;
1687 	x.active = 1;
1688 
1689 	i = lnk->data.tcp->state.index;
1690 	lnk->data.tcp->ack[i] = x;
1691 
1692 	i++;
1693 	if (i == N_LINK_TCP_DATA)
1694 		lnk->data.tcp->state.index = 0;
1695 	else
1696 		lnk->data.tcp->state.index = i;
1697 }
1698 
1699 void
1700 SetExpire(struct alias_link *lnk, int expire)
1701 {
1702 	if (expire == 0) {
1703 		lnk->flags &= ~LINK_PERMANENT;
1704 		DeleteLink(&lnk, 0);
1705 	} else if (expire == -1) {
1706 		lnk->flags |= LINK_PERMANENT;
1707 	} else if (expire > 0) {
1708 		lnk->expire.time = expire;
1709 	} else {
1710 #ifdef LIBALIAS_DEBUG
1711 		fprintf(stderr, "PacketAlias/SetExpire(): ");
1712 		fprintf(stderr, "error in expire parameter\n");
1713 #endif
1714 	}
1715 }
1716 
1717 void
1718 SetProtocolFlags(struct alias_link *lnk, int pflags)
1719 {
1720 	lnk->pflags = pflags;
1721 }
1722 
1723 int
1724 GetProtocolFlags(struct alias_link *lnk)
1725 {
1726 	return (lnk->pflags);
1727 }
1728 
1729 void
1730 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
1731 {
1732 	LIBALIAS_LOCK_ASSERT(lnk->la);
1733 	ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
1734 	    lnk->src_port, cid, lnk->alias_port, lnk->link_type, 1);
1735 }
1736 
1737 /* Miscellaneous Functions
1738 
1739     HouseKeeping()
1740     InitPacketAliasLog()
1741     UninitPacketAliasLog()
1742 */
1743 
1744 /*
1745     Whenever an outgoing or incoming packet is handled, HouseKeeping()
1746     is called to find and remove timed-out aliasing links.  Logic exists
1747     to sweep through the entire table and linked list structure
1748     every 60 seconds.
1749 
1750     (prototype in alias_local.h)
1751 */
1752 
1753 void
1754 HouseKeeping(struct libalias *la)
1755 {
1756 	static unsigned int packets = 0;
1757 	static unsigned int packet_limit = 1000;
1758 
1759 	LIBALIAS_LOCK_ASSERT(la);
1760 	packets++;
1761 
1762 	/*
1763 	 * User space time/gettimeofday/... is very expensive.
1764 	 * Kernel space cache trashing is unnecessary.
1765 	 *
1766 	 * Save system time (seconds) in global variable LibAliasTime
1767 	 * for use by other functions. This is done so as not to
1768 	 * unnecessarily waste timeline by making system calls.
1769 	 *
1770 	 * Reduce the amount of house keeping work substantially by
1771 	 * sampling over the packets.
1772 	 */
1773 	if (packets % packet_limit == 0) {
1774 		time_t now;
1775 
1776 #ifdef _KERNEL
1777 		now = time_uptime;
1778 #else
1779 		now = time(NULL);
1780 #endif
1781 		if (now != LibAliasTime) {
1782 			/* retry three times a second */
1783 			packet_limit = packets / 3;
1784 			packets = 0;
1785 			LibAliasTime = now;
1786 		}
1787 
1788 	}
1789 	/* Do a cleanup for the first packets of the new second only */
1790 	if (packets < (la->udpLinkCount + la->tcpLinkCount)) {
1791 		struct alias_link * lnk = TAILQ_FIRST(&la->checkExpire);
1792 
1793 		CleanupLink(la, &lnk, 0);
1794 	}
1795 }
1796 
1797 /* Init the log file and enable logging */
1798 static int
1799 InitPacketAliasLog(struct libalias *la)
1800 {
1801 	LIBALIAS_LOCK_ASSERT(la);
1802 	if (~la->packetAliasMode & PKT_ALIAS_LOG) {
1803 #ifdef _KERNEL
1804 		if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
1805 			;
1806 #else
1807 		if ((la->logDesc = fopen("/var/log/alias.log", "w")))
1808 			fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1809 #endif
1810 		else
1811 			return (ENOMEM); /* log initialization failed */
1812 		la->packetAliasMode |= PKT_ALIAS_LOG;
1813 	}
1814 
1815 	return (1);
1816 }
1817 
1818 /* Close the log-file and disable logging. */
1819 static void
1820 UninitPacketAliasLog(struct libalias *la)
1821 {
1822 	LIBALIAS_LOCK_ASSERT(la);
1823 	if (la->logDesc) {
1824 #ifdef _KERNEL
1825 		free(la->logDesc);
1826 #else
1827 		fclose(la->logDesc);
1828 #endif
1829 		la->logDesc = NULL;
1830 	}
1831 	la->packetAliasMode &= ~PKT_ALIAS_LOG;
1832 }
1833 
1834 /* Outside world interfaces
1835 
1836 -- "outside world" means other than alias*.c routines --
1837 
1838     PacketAliasRedirectPort()
1839     PacketAliasAddServer()
1840     PacketAliasRedirectProto()
1841     PacketAliasRedirectAddr()
1842     PacketAliasRedirectDynamic()
1843     PacketAliasRedirectDelete()
1844     PacketAliasSetAddress()
1845     PacketAliasInit()
1846     PacketAliasUninit()
1847     PacketAliasSetMode()
1848 
1849 (prototypes in alias.h)
1850 */
1851 
1852 /* Redirection from a specific public addr:port to a
1853    private addr:port */
1854 struct alias_link *
1855 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
1856     struct in_addr dst_addr, u_short dst_port,
1857     struct in_addr alias_addr, u_short alias_port,
1858     u_char proto)
1859 {
1860 	int link_type;
1861 	struct alias_link *lnk;
1862 
1863 	LIBALIAS_LOCK(la);
1864 	switch (proto) {
1865 	case IPPROTO_UDP:
1866 		link_type = LINK_UDP;
1867 		break;
1868 	case IPPROTO_TCP:
1869 		link_type = LINK_TCP;
1870 		break;
1871 	case IPPROTO_SCTP:
1872 		link_type = LINK_SCTP;
1873 		break;
1874 	default:
1875 #ifdef LIBALIAS_DEBUG
1876 		fprintf(stderr, "PacketAliasRedirectPort(): ");
1877 		fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
1878 #endif
1879 		lnk = NULL;
1880 		goto getout;
1881 	}
1882 
1883 	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1884 	    src_port, dst_port, alias_port,
1885 	    link_type);
1886 
1887 	if (lnk != NULL) {
1888 		lnk->flags |= LINK_PERMANENT;
1889 	}
1890 #ifdef LIBALIAS_DEBUG
1891 	else {
1892 		fprintf(stderr, "PacketAliasRedirectPort(): "
1893 		    "call to AddLink() failed\n");
1894 	}
1895 #endif
1896 
1897 getout:
1898 	LIBALIAS_UNLOCK(la);
1899 	return (lnk);
1900 }
1901 
1902 /* Add server to the pool of servers */
1903 int
1904 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
1905 {
1906 	struct server *server;
1907 	int res;
1908 
1909 	LIBALIAS_LOCK(la);
1910 	(void)la;
1911 
1912 	switch (lnk->link_type) {
1913 	case LINK_PPTP:
1914 		server = NULL;
1915 		break;
1916 	default:
1917 		server = malloc(sizeof(struct server));
1918 		break;
1919 	}
1920 
1921 	if (server != NULL) {
1922 		struct server *head;
1923 
1924 		server->addr = addr;
1925 		server->port = port;
1926 
1927 		head = lnk->server;
1928 		if (head == NULL) {
1929 			server->next = server;
1930 			/* not usable for outgoing connections */
1931 			SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
1932 		} else {
1933 			struct server *s;
1934 
1935 			for (s = head; s->next != head; s = s->next)
1936 				;
1937 			s->next = server;
1938 			server->next = head;
1939 		}
1940 		lnk->server = server;
1941 		res = 0;
1942 	} else
1943 		res = -1;
1944 
1945 	LIBALIAS_UNLOCK(la);
1946 	return (res);
1947 }
1948 
1949 /* Redirect packets of a given IP protocol from a specific
1950    public address to a private address */
1951 struct alias_link *
1952 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
1953     struct in_addr dst_addr,
1954     struct in_addr alias_addr,
1955     u_char proto)
1956 {
1957 	struct alias_link *lnk;
1958 
1959 	LIBALIAS_LOCK(la);
1960 	lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1961 	    NO_SRC_PORT, NO_DEST_PORT, 0,
1962 	    proto);
1963 
1964 	if (lnk != NULL) {
1965 		lnk->flags |= LINK_PERMANENT;
1966 	}
1967 #ifdef LIBALIAS_DEBUG
1968 	else {
1969 		fprintf(stderr, "PacketAliasRedirectProto(): "
1970 		    "call to AddLink() failed\n");
1971 	}
1972 #endif
1973 
1974 	LIBALIAS_UNLOCK(la);
1975 	return (lnk);
1976 }
1977 
1978 /* Static address translation */
1979 struct alias_link *
1980 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
1981     struct in_addr alias_addr)
1982 {
1983 	struct alias_link *lnk;
1984 
1985 	LIBALIAS_LOCK(la);
1986 	lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr,
1987 	    0, 0, 0,
1988 	    LINK_ADDR);
1989 
1990 	if (lnk != NULL) {
1991 		lnk->flags |= LINK_PERMANENT;
1992 	}
1993 #ifdef LIBALIAS_DEBUG
1994 	else {
1995 		fprintf(stderr, "PacketAliasRedirectAddr(): "
1996 		    "call to AddLink() failed\n");
1997 	}
1998 #endif
1999 
2000 	LIBALIAS_UNLOCK(la);
2001 	return (lnk);
2002 }
2003 
2004 /* Mark the aliasing link dynamic */
2005 int
2006 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2007 {
2008 	int res;
2009 
2010 	LIBALIAS_LOCK(la);
2011 	(void)la;
2012 
2013 	if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2014 		res = -1;
2015 	else {
2016 		lnk->flags &= ~LINK_PERMANENT;
2017 		res = 0;
2018 	}
2019 	LIBALIAS_UNLOCK(la);
2020 	return (res);
2021 }
2022 
2023 /* This is a dangerous function to put in the API,
2024    because an invalid pointer can crash the program. */
2025 void
2026 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2027 {
2028 	LIBALIAS_LOCK(la);
2029 	(void)la;
2030 	DeleteLink(&lnk, 1);
2031 	LIBALIAS_UNLOCK(la);
2032 }
2033 
2034 void
2035 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2036 {
2037 	LIBALIAS_LOCK(la);
2038 	if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2039 	    && la->aliasAddress.s_addr != addr.s_addr)
2040 		CleanupAliasData(la, 0);
2041 
2042 	la->aliasAddress = addr;
2043 	LIBALIAS_UNLOCK(la);
2044 }
2045 
2046 void
2047 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
2048     u_short port_high)
2049 {
2050 	LIBALIAS_LOCK(la);
2051 	la->aliasPortLower = port_low;
2052 	/* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
2053 	la->aliasPortLength = port_high - port_low + 1;
2054 	LIBALIAS_UNLOCK(la);
2055 }
2056 
2057 void
2058 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2059 {
2060 	LIBALIAS_LOCK(la);
2061 	la->targetAddress = target_addr;
2062 	LIBALIAS_UNLOCK(la);
2063 }
2064 
2065 static void
2066 finishoff(void)
2067 {
2068 	while (!LIST_EMPTY(&instancehead))
2069 		LibAliasUninit(LIST_FIRST(&instancehead));
2070 }
2071 
2072 struct libalias *
2073 LibAliasInit(struct libalias *la)
2074 {
2075 	if (la == NULL) {
2076 #ifdef _KERNEL
2077 #undef malloc	/* XXX: ugly */
2078 		la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2079 #else
2080 		la = calloc(sizeof *la, 1);
2081 		if (la == NULL)
2082 			return (la);
2083 #endif
2084 
2085 #ifndef _KERNEL
2086 		/* kernel cleans up on module unload */
2087 		if (LIST_EMPTY(&instancehead))
2088 			atexit(finishoff);
2089 #endif
2090 		LIST_INSERT_HEAD(&instancehead, la, instancelist);
2091 
2092 #ifdef _KERNEL
2093 		LibAliasTime = time_uptime;
2094 #else
2095 		LibAliasTime = time(NULL);
2096 #endif
2097 
2098 		SPLAY_INIT(&la->linkSplayIn);
2099 		SPLAY_INIT(&la->linkSplayOut);
2100 		LIST_INIT(&la->pptpList);
2101 		TAILQ_INIT(&la->checkExpire);
2102 #ifdef _KERNEL
2103 		AliasSctpInit(la);
2104 #endif
2105 		LIBALIAS_LOCK_INIT(la);
2106 		LIBALIAS_LOCK(la);
2107 	} else {
2108 		LIBALIAS_LOCK(la);
2109 		CleanupAliasData(la, 1);
2110 #ifdef _KERNEL
2111 		AliasSctpTerm(la);
2112 		AliasSctpInit(la);
2113 #endif
2114 	}
2115 
2116 	la->aliasAddress.s_addr = INADDR_ANY;
2117 	la->targetAddress.s_addr = INADDR_ANY;
2118 	la->aliasPortLower = 0x8000;
2119 	la->aliasPortLength = 0x8000;
2120 
2121 	la->icmpLinkCount = 0;
2122 	la->udpLinkCount = 0;
2123 	la->tcpLinkCount = 0;
2124 	la->sctpLinkCount = 0;
2125 	la->pptpLinkCount = 0;
2126 	la->protoLinkCount = 0;
2127 	la->fragmentIdLinkCount = 0;
2128 	la->fragmentPtrLinkCount = 0;
2129 	la->sockCount = 0;
2130 
2131 	la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2132 #ifndef NO_USE_SOCKETS
2133 	    | PKT_ALIAS_USE_SOCKETS
2134 #endif
2135 	    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2136 #ifndef NO_FW_PUNCH
2137 	la->fireWallFD = -1;
2138 #endif
2139 #ifndef _KERNEL
2140 	LibAliasRefreshModules();
2141 #endif
2142 	LIBALIAS_UNLOCK(la);
2143 	return (la);
2144 }
2145 
2146 void
2147 LibAliasUninit(struct libalias *la)
2148 {
2149 	LIBALIAS_LOCK(la);
2150 #ifdef _KERNEL
2151 	AliasSctpTerm(la);
2152 #endif
2153 	CleanupAliasData(la, 1);
2154 	UninitPacketAliasLog(la);
2155 #ifndef NO_FW_PUNCH
2156 	UninitPunchFW(la);
2157 #endif
2158 	LIST_REMOVE(la, instancelist);
2159 	LIBALIAS_UNLOCK(la);
2160 	LIBALIAS_LOCK_DESTROY(la);
2161 	free(la);
2162 }
2163 
2164 /* Change mode for some operations */
2165 unsigned int
2166 LibAliasSetMode(
2167     struct libalias *la,
2168     unsigned int flags,		/* Which state to bring flags to */
2169     unsigned int mask		/* Mask of which flags to affect (use 0 to
2170 				 * do a probe for flag values) */
2171 )
2172 {
2173 	int res = -1;
2174 
2175 	LIBALIAS_LOCK(la);
2176 	if (flags & mask & PKT_ALIAS_LOG) {
2177 		/* Enable logging */
2178 		if (InitPacketAliasLog(la) == ENOMEM)
2179 			goto getout;
2180 	} else if (~flags & mask & PKT_ALIAS_LOG)
2181 		/* _Disable_ logging */
2182 		UninitPacketAliasLog(la);
2183 
2184 #ifndef NO_FW_PUNCH
2185 	if (flags & mask & PKT_ALIAS_PUNCH_FW)
2186 		/* Start punching holes in the firewall? */
2187 		InitPunchFW(la);
2188 	else if (~flags & mask & PKT_ALIAS_PUNCH_FW)
2189 		/* Stop punching holes in the firewall? */
2190 		UninitPunchFW(la);
2191 #endif
2192 
2193 	/* Other flags can be set/cleared without special action */
2194 	la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2195 	res = la->packetAliasMode;
2196 getout:
2197 	LIBALIAS_UNLOCK(la);
2198 	return (res);
2199 }
2200 
2201 #ifndef NO_FW_PUNCH
2202 
2203 /*****************
2204   Code to support firewall punching.  This shouldn't really be in this
2205   file, but making variables global is evil too.
2206   ****************/
2207 
2208 /* Firewall include files */
2209 #include <net/if.h>
2210 #include <netinet/ip_fw.h>
2211 #include <string.h>
2212 #include <err.h>
2213 
2214 /*
2215  * helper function, updates the pointer to cmd with the length
2216  * of the current command, and also cleans up the first word of
2217  * the new command in case it has been clobbered before.
2218  */
2219 static ipfw_insn *
2220 next_cmd(ipfw_insn * cmd)
2221 {
2222 	cmd += F_LEN(cmd);
2223 	bzero(cmd, sizeof(*cmd));
2224 	return (cmd);
2225 }
2226 
2227 /*
2228  * A function to fill simple commands of size 1.
2229  * Existing flags are preserved.
2230  */
2231 static ipfw_insn *
2232 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2233     int flags, u_int16_t arg)
2234 {
2235 	cmd->opcode = opcode;
2236 	cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2237 	cmd->arg1 = arg;
2238 	return next_cmd(cmd);
2239 }
2240 
2241 static ipfw_insn *
2242 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2243 {
2244 	ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2245 
2246 	cmd->addr.s_addr = addr;
2247 	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2248 }
2249 
2250 static ipfw_insn *
2251 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2252 {
2253 	ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2254 
2255 	cmd->ports[0] = cmd->ports[1] = port;
2256 	return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2257 }
2258 
2259 static int
2260 fill_rule(void *buf, int bufsize, int rulenum,
2261     enum ipfw_opcodes action, int proto,
2262     struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2263 {
2264 	struct ip_fw *rule = (struct ip_fw *)buf;
2265 	ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2266 
2267 	bzero(buf, bufsize);
2268 	rule->rulenum = rulenum;
2269 
2270 	cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2271 	cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2272 	cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2273 	cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2274 	cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2275 
2276 	rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2277 	cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2278 
2279 	rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2280 
2281 	return ((char *)cmd - (char *)buf);
2282 }
2283 
2284 static void
2285 InitPunchFW(struct libalias *la)
2286 {
2287 	la->fireWallField = malloc(la->fireWallNumNums);
2288 	if (la->fireWallField) {
2289 		memset(la->fireWallField, 0, la->fireWallNumNums);
2290 		if (la->fireWallFD < 0) {
2291 			la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2292 		}
2293 		ClearAllFWHoles(la);
2294 		la->fireWallActiveNum = la->fireWallBaseNum;
2295 	}
2296 }
2297 
2298 static void
2299 UninitPunchFW(struct libalias *la)
2300 {
2301 	ClearAllFWHoles(la);
2302 	if (la->fireWallFD >= 0)
2303 		close(la->fireWallFD);
2304 	la->fireWallFD = -1;
2305 	if (la->fireWallField)
2306 		free(la->fireWallField);
2307 	la->fireWallField = NULL;
2308 	la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2309 }
2310 
2311 /* Make a certain link go through the firewall */
2312 void
2313 PunchFWHole(struct alias_link *lnk)
2314 {
2315 	struct libalias *la;
2316 	int r;			/* Result code */
2317 	struct ip_fw rule;	/* On-the-fly built rule */
2318 	int fwhole;		/* Where to punch hole */
2319 
2320 	la = lnk->la;
2321 
2322 	/* Don't do anything unless we are asked to */
2323 	if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2324 	    la->fireWallFD < 0 ||
2325 	    lnk->link_type != LINK_TCP)
2326 		return;
2327 
2328 	memset(&rule, 0, sizeof rule);
2329 
2330 	/** Build rule **/
2331 
2332 	/* Find empty slot */
2333 	for (fwhole = la->fireWallActiveNum;
2334 	    fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2335 	    fw_tstfield(la, la->fireWallField, fwhole);
2336 	    fwhole++);
2337 	if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2338 		for (fwhole = la->fireWallBaseNum;
2339 		    fwhole < la->fireWallActiveNum &&
2340 		    fw_tstfield(la, la->fireWallField, fwhole);
2341 		    fwhole++);
2342 		if (fwhole == la->fireWallActiveNum) {
2343 			/* No rule point empty - we can't punch more holes. */
2344 			la->fireWallActiveNum = la->fireWallBaseNum;
2345 #ifdef LIBALIAS_DEBUG
2346 			fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2347 #endif
2348 			return;
2349 		}
2350 	}
2351 	/* Start next search at next position */
2352 	la->fireWallActiveNum = fwhole + 1;
2353 
2354 	/*
2355 	 * generate two rules of the form
2356 	 *
2357 	 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2358 	 * accept tcp from DAddr DPort to OAddr OPort
2359 	 */
2360 	if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2361 		u_int32_t rulebuf[255];
2362 		int i;
2363 
2364 		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2365 		    O_ACCEPT, IPPROTO_TCP,
2366 		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2367 		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2368 		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2369 		if (r)
2370 			err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2371 
2372 		i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2373 		    O_ACCEPT, IPPROTO_TCP,
2374 		    GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2375 		    GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2376 		r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2377 		if (r)
2378 			err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2379 	}
2380 
2381 	/* Indicate hole applied */
2382 	lnk->data.tcp->fwhole = fwhole;
2383 	fw_setfield(la, la->fireWallField, fwhole);
2384 }
2385 
2386 /* Remove a hole in a firewall associated with a particular alias
2387    lnk.  Calling this too often is harmless. */
2388 static void
2389 ClearFWHole(struct alias_link *lnk)
2390 {
2391 	struct libalias *la;
2392 
2393 	la = lnk->la;
2394 	if (lnk->link_type == LINK_TCP) {
2395 		int fwhole = lnk->data.tcp->fwhole;  /* Where is the firewall hole? */
2396 		struct ip_fw rule;
2397 
2398 		if (fwhole < 0)
2399 			return;
2400 
2401 		memset(&rule, 0, sizeof rule);	/* useless for ipfw2 */
2402 		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2403 		    &fwhole, sizeof fwhole));
2404 		fw_clrfield(la, la->fireWallField, fwhole);
2405 		lnk->data.tcp->fwhole = -1;
2406 	}
2407 }
2408 
2409 /* Clear out the entire range dedicated to firewall holes. */
2410 static void
2411 ClearAllFWHoles(struct libalias *la)
2412 {
2413 	struct ip_fw rule;	/* On-the-fly built rule */
2414 	int i;
2415 
2416 	if (la->fireWallFD < 0)
2417 		return;
2418 
2419 	memset(&rule, 0, sizeof rule);
2420 	for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2421 		int r = i;
2422 
2423 		while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2424 	}
2425 	/* XXX: third arg correct here ? /phk */
2426 	memset(la->fireWallField, 0, la->fireWallNumNums);
2427 }
2428 
2429 #endif /* !NO_FW_PUNCH */
2430 
2431 void
2432 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2433 {
2434 	LIBALIAS_LOCK(la);
2435 #ifndef NO_FW_PUNCH
2436 	la->fireWallBaseNum = base;
2437 	la->fireWallNumNums = num;
2438 #endif
2439 	LIBALIAS_UNLOCK(la);
2440 }
2441 
2442 void
2443 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2444 {
2445 	LIBALIAS_LOCK(la);
2446 	la->skinnyPort = port;
2447 	LIBALIAS_UNLOCK(la);
2448 }
2449 
2450 /*
2451  * Find the address to redirect incoming packets
2452  */
2453 struct in_addr
2454 FindSctpRedirectAddress(struct libalias *la,  struct sctp_nat_msg *sm)
2455 {
2456 	struct alias_link *lnk;
2457 	struct in_addr redir;
2458 
2459 	LIBALIAS_LOCK_ASSERT(la);
2460 	lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2461 	    sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2462 	if (lnk != NULL) {
2463 		/* port redirect */
2464 		return (lnk->src_addr);
2465 	} else {
2466 		redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2467 		if (redir.s_addr == la->aliasAddress.s_addr ||
2468 		    redir.s_addr == la->targetAddress.s_addr) {
2469 			/* No address found */
2470 			lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2471 			    NO_DEST_PORT, 0, LINK_SCTP, 1);
2472 			if (lnk != NULL)
2473 				/* redirect proto */
2474 				return (lnk->src_addr);
2475 		}
2476 		return (redir); /* address redirect */
2477 	}
2478 }
2479