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