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