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