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