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