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