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