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