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