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