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