mtw(4) remove misplaced DEBUG_FLAGS
[freebsd/src.git] / sys / netinet / libalias / alias_db.c
blobb09e41935d9319d89829f7c266988100929462a8
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * All rights reserved.
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.
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.
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
48 #include <sys/socket.h>
49 #include <netinet/tcp.h>
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
62 #include "alias_db.h"
64 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
65 int LibAliasTime;
67 /* Kernel module definition. */
68 #ifdef _KERNEL
69 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
71 MODULE_VERSION(libalias, 1);
73 static int
74 alias_mod_handler(module_t mod, int type, void *data)
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);
87 static moduledata_t alias_mod = {
88 "alias", alias_mod_handler, NULL
91 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
92 #endif
94 SPLAY_GENERATE(splay_out, alias_link, all.out, cmp_out);
95 SPLAY_GENERATE(splay_in, group_in, in, cmp_in);
96 SPLAY_GENERATE(splay_internal_endpoint, alias_link, all.internal_endpoint,
97 cmp_internal_endpoint);
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)
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
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);
123 static int
124 SeqDiff(u_long x, u_long y)
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.
130 return (ntohl(y) - ntohl(x));
133 #ifdef _KERNEL
134 static void
135 AliasLog(char *str, const char *format, ...)
137 va_list ap;
139 va_start(ap, format);
140 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
141 va_end(ap);
143 #else
144 static void
145 AliasLog(FILE *stream, const char *format, ...)
147 va_list ap;
149 va_start(ap, format);
150 vfprintf(stream, format, ap);
151 va_end(ap);
152 fflush(stream);
154 #endif
156 static void
157 ShowAliasStats(struct libalias *la)
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;
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
185 void SctpShowAliasStats(struct libalias *la)
187 ShowAliasStats(la);
190 /* get random port in network byte order */
191 static u_short
192 _RandomPort(struct libalias *la) {
193 u_short port;
195 port = la->aliasPortLower +
196 arc4random_uniform(la->aliasPortLength);
198 return ntohs(port);
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). */
206 static int
207 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
209 int i;
210 int max_trials;
211 u_short port;
213 LIBALIAS_LOCK_ASSERT(la);
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.
220 * The aliasing port is automatically selected by one of
221 * two methods below:
223 * When this parameter is GET_ALIAS_PORT, it indicates to get
224 * a randomly selected port number.
226 if (alias_port_param >= 0 && alias_port_param < 0x10000) {
227 lnk->alias_port = (u_short) alias_port_param;
228 return (0);
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);
238 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
240 if ((la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
241 lnk->link_type == LINK_UDP) {
242 /* Try reuse the same alias address:port for all destinations
243 * from the same internal address:port, as per RFC 4787.
245 struct alias_link *search_result = FindLinkByInternalEndpoint(
246 la, lnk->src_addr, lnk->src_port, lnk->link_type);
247 if (search_result != NULL) {
248 lnk->alias_port = search_result->alias_port;
249 return (0);
254 * When the PKT_ALIAS_SAME_PORTS option is chosen,
255 * the first try will be the actual source port. If
256 * this is already in use, the remainder of the
257 * trials will be random.
259 port = (la->packetAliasMode & PKT_ALIAS_SAME_PORTS)
260 ? lnk->src_port
261 : _RandomPort(la);
263 /* Port number search */
264 for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
265 struct group_in *grp;
266 struct alias_link *search_result;
268 grp = StartPointIn(la, lnk->alias_addr, port, lnk->link_type, 0);
269 if (grp == NULL)
270 break;
272 /* As per RFC 4787, UDP cannot share the same alias port among
273 * multiple internal endpoints
275 if ((la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
276 lnk->link_type == LINK_UDP)
277 continue;
279 LIST_FOREACH(search_result, &grp->full, all.in) {
280 if (lnk->dst_addr.s_addr ==
281 search_result->dst_addr.s_addr &&
282 lnk->dst_port == search_result->dst_port)
283 break; /* found match */
285 if (search_result == NULL)
286 break;
289 if (i >= max_trials) {
290 #ifdef LIBALIAS_DEBUG
291 fprintf(stderr, "PacketAlias/GetNewPort(): ");
292 fprintf(stderr, "could not find free port\n");
293 #endif
294 return (-1);
297 #ifndef NO_USE_SOCKETS
298 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) &&
299 (lnk->flags & LINK_PARTIALLY_SPECIFIED) &&
300 ((lnk->link_type == LINK_TCP) ||
301 (lnk->link_type == LINK_UDP))) {
302 if (!GetSocket(la, port, &lnk->sockfd, lnk->link_type)) {
303 return (-1);
306 #endif
307 lnk->alias_port = port;
309 return (0);
312 #ifndef NO_USE_SOCKETS
313 static u_short
314 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
316 int err;
317 int sock;
318 struct sockaddr_in sock_addr;
320 LIBALIAS_LOCK_ASSERT(la);
321 if (link_type == LINK_TCP)
322 sock = socket(AF_INET, SOCK_STREAM, 0);
323 else if (link_type == LINK_UDP)
324 sock = socket(AF_INET, SOCK_DGRAM, 0);
325 else {
326 #ifdef LIBALIAS_DEBUG
327 fprintf(stderr, "PacketAlias/GetSocket(): ");
328 fprintf(stderr, "incorrect link type\n");
329 #endif
330 return (0);
333 if (sock < 0) {
334 #ifdef LIBALIAS_DEBUG
335 fprintf(stderr, "PacketAlias/GetSocket(): ");
336 fprintf(stderr, "socket() error %d\n", *sockfd);
337 #endif
338 return (0);
340 sock_addr.sin_family = AF_INET;
341 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
342 sock_addr.sin_port = port_net;
344 err = bind(sock,
345 (struct sockaddr *)&sock_addr,
346 sizeof(sock_addr));
347 if (err == 0) {
348 la->sockCount++;
349 *sockfd = sock;
350 return (1);
351 } else {
352 close(sock);
353 return (0);
356 #endif
358 /* FindNewPortGroup() returns a base port number for an available
359 range of contiguous port numbers. Note that if a port number
360 is already in use, that does not mean that it cannot be used by
361 another link concurrently. This is because FindNewPortGroup()
362 looks for unused triplets: (dest addr, dest port, alias port). */
365 FindNewPortGroup(struct libalias *la,
366 struct in_addr dst_addr,
367 struct in_addr alias_addr,
368 u_short src_port,
369 u_short dst_port,
370 u_short port_count,
371 u_char proto,
372 u_char align)
374 int i, j;
375 int max_trials;
376 u_short port;
377 int link_type;
379 LIBALIAS_LOCK_ASSERT(la);
381 * Get link_type from protocol
384 switch (proto) {
385 case IPPROTO_UDP:
386 link_type = LINK_UDP;
387 break;
388 case IPPROTO_TCP:
389 link_type = LINK_TCP;
390 break;
391 default:
392 return (0);
393 break;
397 * The aliasing port is automatically selected by one of two
398 * methods below:
400 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
402 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
404 * When the ALIAS_SAME_PORTS option is chosen, the first
405 * try will be the actual source port. If this is already
406 * in use, the remainder of the trials will be random.
408 port = src_port;
410 } else {
411 port = _RandomPort(la);
414 /* Port number search */
415 for (i = 0; i < max_trials; i++, port = _RandomPort(la)) {
416 struct alias_link *search_result;
418 if (align)
419 port &= htons(0xfffe);
421 for (j = 0; j < port_count; j++) {
422 u_short port_j = ntohs(port) + j;
424 if ((search_result = FindLinkIn(la, dst_addr,
425 alias_addr, dst_port, htons(port_j),
426 link_type, 0)) != NULL)
427 break;
430 /* Found a good range, return base */
431 if (j == port_count)
432 return (port);
435 #ifdef LIBALIAS_DEBUG
436 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
437 fprintf(stderr, "could not find free port(s)\n");
438 #endif
440 return (0);
443 static void
444 CleanupAliasData(struct libalias *la, int deletePermanent)
446 struct alias_link *lnk, *lnk_tmp;
448 LIBALIAS_LOCK_ASSERT(la);
450 /* permanent entries may stay */
451 TAILQ_FOREACH_SAFE(lnk, &la->checkExpire, expire.list, lnk_tmp)
452 DeleteLink(&lnk, deletePermanent);
454 static void
455 CleanupLink(struct libalias *la, struct alias_link **lnk, int deletePermanent)
457 LIBALIAS_LOCK_ASSERT(la);
459 if (lnk == NULL || *lnk == NULL)
460 return;
462 if (LibAliasTime - (*lnk)->timestamp > (*lnk)->expire.time) {
463 DeleteLink(lnk, deletePermanent);
464 if ((*lnk) == NULL)
465 return;
468 /* move to end, swap may fail on a single entry list */
469 TAILQ_REMOVE(&la->checkExpire, (*lnk), expire.list);
470 TAILQ_INSERT_TAIL(&la->checkExpire, (*lnk), expire.list);
473 static struct alias_link *
474 UseLink(struct libalias *la, struct alias_link *lnk)
476 CleanupLink(la, &lnk, 0);
477 if (lnk != NULL)
478 lnk->timestamp = LibAliasTime;
479 return (lnk);
482 static void
483 DeleteLink(struct alias_link **plnk, int deletePermanent)
485 struct alias_link *lnk = *plnk;
486 struct libalias *la = lnk->la;
488 LIBALIAS_LOCK_ASSERT(la);
489 /* Don't do anything if the link is marked permanent */
490 if (!deletePermanent && (lnk->flags & LINK_PERMANENT))
491 return;
493 #ifndef NO_FW_PUNCH
494 /* Delete associated firewall hole, if any */
495 ClearFWHole(lnk);
496 #endif
498 switch (lnk->link_type) {
499 case LINK_PPTP:
500 LIST_REMOVE(lnk, pptp.list);
501 break;
502 default: {
503 struct group_in *grp;
505 /* Free memory allocated for LSNAT server pool */
506 if (lnk->server != NULL) {
507 struct server *head, *curr, *next;
509 head = curr = lnk->server;
510 do {
511 next = curr->next;
512 free(curr);
513 } while ((curr = next) != head);
514 } else {
515 /* Adjust output table pointers */
516 SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
519 /* Adjust input table pointers */
520 LIST_REMOVE(lnk, all.in);
522 /* Adjust "internal endpoint" table pointer */
523 SPLAY_REMOVE(splay_internal_endpoint,
524 &la->linkSplayInternalEndpoint, lnk);
526 /* Remove intermediate node, if empty */
527 grp = StartPointIn(la, lnk->alias_addr, lnk->alias_port, lnk->link_type, 0);
528 if (grp != NULL &&
529 LIST_EMPTY(&grp->full) &&
530 LIST_EMPTY(&grp->partial)) {
531 SPLAY_REMOVE(splay_in, &la->linkSplayIn, grp);
532 free(grp);
535 break;
538 /* remove from housekeeping */
539 TAILQ_REMOVE(&la->checkExpire, lnk, expire.list);
541 #ifndef NO_USE_SOCKETS
542 /* Close socket, if one has been allocated */
543 if (lnk->sockfd != -1) {
544 la->sockCount--;
545 close(lnk->sockfd);
547 #endif
548 /* Link-type dependent cleanup */
549 switch (lnk->link_type) {
550 case LINK_ICMP:
551 la->icmpLinkCount--;
552 break;
553 case LINK_UDP:
554 la->udpLinkCount--;
555 break;
556 case LINK_TCP:
557 la->tcpLinkCount--;
558 free(lnk->data.tcp);
559 break;
560 case LINK_PPTP:
561 la->pptpLinkCount--;
562 break;
563 case LINK_FRAGMENT_ID:
564 la->fragmentIdLinkCount--;
565 break;
566 case LINK_FRAGMENT_PTR:
567 la->fragmentPtrLinkCount--;
568 if (lnk->data.frag_ptr != NULL)
569 free(lnk->data.frag_ptr);
570 break;
571 case LINK_ADDR:
572 break;
573 default:
574 la->protoLinkCount--;
575 break;
578 /* Free memory */
579 free(lnk);
580 *plnk = NULL;
582 /* Write statistics, if logging enabled */
583 if (la->packetAliasMode & PKT_ALIAS_LOG) {
584 ShowAliasStats(la);
588 struct alias_link *
589 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
590 struct in_addr alias_addr, u_short src_port, u_short dst_port,
591 int alias_port_param, int link_type)
593 struct alias_link *lnk;
595 LIBALIAS_LOCK_ASSERT(la);
597 lnk = malloc(sizeof(struct alias_link));
598 if (lnk == NULL) {
599 #ifdef LIBALIAS_DEBUG
600 fprintf(stderr, "PacketAlias/AddLink(): ");
601 fprintf(stderr, "malloc() call failed.\n");
602 #endif
603 return (NULL);
605 /* Basic initialization */
606 lnk->la = la;
607 lnk->src_addr = src_addr;
608 lnk->dst_addr = dst_addr;
609 lnk->alias_addr = alias_addr;
610 lnk->proxy_addr.s_addr = INADDR_ANY;
611 lnk->src_port = src_port;
612 lnk->dst_port = dst_port;
613 lnk->proxy_port = 0;
614 lnk->server = NULL;
615 lnk->link_type = link_type;
616 #ifndef NO_USE_SOCKETS
617 lnk->sockfd = -1;
618 #endif
619 lnk->flags = 0;
620 lnk->pflags = 0;
621 lnk->timestamp = LibAliasTime;
623 /* Expiration time */
624 switch (link_type) {
625 case LINK_ICMP:
626 lnk->expire.time = ICMP_EXPIRE_TIME;
627 break;
628 case LINK_UDP:
629 lnk->expire.time = UDP_EXPIRE_TIME;
630 break;
631 case LINK_TCP:
632 lnk->expire.time = TCP_EXPIRE_INITIAL;
633 break;
634 case LINK_FRAGMENT_ID:
635 lnk->expire.time = FRAGMENT_ID_EXPIRE_TIME;
636 break;
637 case LINK_FRAGMENT_PTR:
638 lnk->expire.time = FRAGMENT_PTR_EXPIRE_TIME;
639 break;
640 default:
641 lnk->expire.time = PROTO_EXPIRE_TIME;
642 break;
645 /* Determine alias flags */
646 if (dst_addr.s_addr == INADDR_ANY)
647 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
648 if (dst_port == 0)
649 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
651 /* Determine alias port */
652 if (GetNewPort(la, lnk, alias_port_param) != 0) {
653 free(lnk);
654 return (NULL);
656 /* Link-type dependent initialization */
657 switch (link_type) {
658 case LINK_ICMP:
659 la->icmpLinkCount++;
660 break;
661 case LINK_UDP:
662 la->udpLinkCount++;
663 break;
664 case LINK_TCP: {
665 struct tcp_dat *aux_tcp;
666 int i;
668 aux_tcp = malloc(sizeof(struct tcp_dat));
669 if (aux_tcp == NULL) {
670 #ifdef LIBALIAS_DEBUG
671 fprintf(stderr, "PacketAlias/AddLink: ");
672 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
673 #endif
674 free(lnk);
675 return (NULL);
678 la->tcpLinkCount++;
679 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
680 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
681 aux_tcp->state.index = 0;
682 aux_tcp->state.ack_modified = 0;
683 for (i = 0; i < N_LINK_TCP_DATA; i++)
684 aux_tcp->ack[i].active = 0;
685 aux_tcp->fwhole = -1;
686 lnk->data.tcp = aux_tcp;
688 break;
689 case LINK_PPTP:
690 la->pptpLinkCount++;
691 break;
692 case LINK_FRAGMENT_ID:
693 la->fragmentIdLinkCount++;
694 break;
695 case LINK_FRAGMENT_PTR:
696 la->fragmentPtrLinkCount++;
697 break;
698 case LINK_ADDR:
699 break;
700 default:
701 la->protoLinkCount++;
702 break;
705 switch (link_type) {
706 case LINK_PPTP:
707 LIST_INSERT_HEAD(&la->pptpList, lnk, pptp.list);
708 break;
709 default: {
710 struct group_in *grp;
712 grp = StartPointIn(la, alias_addr, lnk->alias_port, link_type, 1);
713 if (grp == NULL) {
714 free(lnk);
715 return (NULL);
718 /* Set up pointers for output lookup table */
719 SPLAY_INSERT(splay_out, &la->linkSplayOut, lnk);
721 /* Set up pointers for input lookup table */
722 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
723 LIST_INSERT_HEAD(&grp->partial, lnk, all.in);
724 else
725 LIST_INSERT_HEAD(&grp->full, lnk, all.in);
727 /* Set up pointers for "internal endpoint" lookup table */
728 SPLAY_INSERT(splay_internal_endpoint,
729 &la->linkSplayInternalEndpoint, lnk);
731 break;
734 /* Include the element into the housekeeping list */
735 TAILQ_INSERT_TAIL(&la->checkExpire, lnk, expire.list);
737 if (la->packetAliasMode & PKT_ALIAS_LOG)
738 ShowAliasStats(la);
740 return (lnk);
744 * If alias_port_param is less than zero, alias port will be automatically
745 * chosen. If greater than zero, equal to alias port
747 static struct alias_link *
748 ReLink(struct alias_link *old_lnk,
749 struct in_addr src_addr,
750 struct in_addr dst_addr,
751 struct in_addr alias_addr,
752 u_short src_port,
753 u_short dst_port,
754 int alias_port_param,
755 int link_type,
756 int deletePermanent)
758 struct alias_link *new_lnk;
759 struct libalias *la = old_lnk->la;
761 LIBALIAS_LOCK_ASSERT(la);
762 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
763 src_port, dst_port, alias_port_param,
764 link_type);
765 #ifndef NO_FW_PUNCH
766 if (new_lnk != NULL &&
767 old_lnk->link_type == LINK_TCP &&
768 old_lnk->data.tcp->fwhole > 0) {
769 PunchFWHole(new_lnk);
771 #endif
772 DeleteLink(&old_lnk, deletePermanent);
773 return (new_lnk);
776 static struct alias_link *
777 _SearchLinkOut(struct libalias *la, struct in_addr src_addr,
778 struct in_addr dst_addr,
779 u_short src_port,
780 u_short dst_port,
781 int link_type) {
782 struct alias_link *lnk;
783 struct alias_link needle = {
784 .src_addr = src_addr,
785 .dst_addr = dst_addr,
786 .src_port = src_port,
787 .dst_port = dst_port,
788 .link_type = link_type
791 lnk = SPLAY_FIND(splay_out, &la->linkSplayOut, &needle);
792 return (UseLink(la, lnk));
795 static struct alias_link *
796 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
797 struct in_addr dst_addr,
798 u_short src_port,
799 u_short dst_port,
800 int link_type,
801 int replace_partial_links)
803 struct alias_link *lnk;
805 LIBALIAS_LOCK_ASSERT(la);
806 lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type);
807 if (lnk != NULL || !replace_partial_links)
808 return (lnk);
810 /* Search for partially specified links. */
811 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
812 lnk = _SearchLinkOut(la, src_addr, dst_addr, src_port, 0,
813 link_type);
814 if (lnk == NULL)
815 lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port,
816 dst_port, link_type);
818 if (lnk == NULL &&
819 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
820 lnk = _SearchLinkOut(la, src_addr, ANY_ADDR, src_port, 0,
821 link_type);
823 if (lnk != NULL) {
824 lnk = ReLink(lnk,
825 src_addr, dst_addr, lnk->alias_addr,
826 src_port, dst_port, lnk->alias_port,
827 link_type, 0);
829 return (lnk);
832 static struct alias_link *
833 FindLinkOut(struct libalias *la, struct in_addr src_addr,
834 struct in_addr dst_addr,
835 u_short src_port,
836 u_short dst_port,
837 int link_type,
838 int replace_partial_links)
840 struct alias_link *lnk;
842 LIBALIAS_LOCK_ASSERT(la);
843 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
844 link_type, replace_partial_links);
846 if (lnk == NULL) {
848 * The following allows permanent links to be specified as
849 * using the default source address (i.e. device interface
850 * address) without knowing in advance what that address
851 * is.
853 if (la->aliasAddress.s_addr != INADDR_ANY &&
854 src_addr.s_addr == la->aliasAddress.s_addr) {
855 lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port,
856 link_type, replace_partial_links);
859 return (lnk);
862 static struct alias_link *
863 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
864 struct in_addr alias_addr,
865 u_short dst_port,
866 u_short alias_port,
867 int link_type,
868 int replace_partial_links)
870 int flags_in;
871 struct group_in *grp;
872 struct alias_link *lnk;
873 struct alias_link *lnk_unknown_all;
874 struct alias_link *lnk_unknown_dst_addr;
875 struct alias_link *lnk_unknown_dst_port;
876 struct in_addr src_addr;
877 u_short src_port;
879 LIBALIAS_LOCK_ASSERT(la);
880 /* Initialize pointers */
881 lnk_unknown_all = NULL;
882 lnk_unknown_dst_addr = NULL;
883 lnk_unknown_dst_port = NULL;
885 /* If either the dest addr or port is unknown, the search
886 * loop will have to know about this. */
887 flags_in = 0;
888 if (dst_addr.s_addr == INADDR_ANY)
889 flags_in |= LINK_UNKNOWN_DEST_ADDR;
890 if (dst_port == 0)
891 flags_in |= LINK_UNKNOWN_DEST_PORT;
893 /* Search loop */
894 grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
895 if (grp == NULL)
896 return (NULL);
898 switch (flags_in) {
899 case 0:
900 LIST_FOREACH(lnk, &grp->full, all.in) {
901 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
902 lnk->dst_port == dst_port) {
903 struct alias_link *found;
905 found = UseLink(la, lnk);
906 if (found != NULL)
907 return (found);
908 /* link expired */
909 grp = StartPointIn(la, alias_addr, alias_port, link_type, 0);
910 if (grp == NULL)
911 return (NULL);
912 break;
915 break;
916 case LINK_UNKNOWN_DEST_PORT:
917 LIST_FOREACH(lnk, &grp->full, all.in) {
918 if(lnk->dst_addr.s_addr == dst_addr.s_addr) {
919 lnk_unknown_dst_port = lnk;
920 break;
923 break;
924 case LINK_UNKNOWN_DEST_ADDR:
925 LIST_FOREACH(lnk, &grp->full, all.in) {
926 if(lnk->dst_port == dst_port) {
927 lnk_unknown_dst_addr = lnk;
928 break;
931 break;
932 case LINK_PARTIALLY_SPECIFIED:
933 lnk_unknown_all = LIST_FIRST(&grp->full);
934 break;
937 if (lnk_unknown_dst_port == NULL) {
938 LIST_FOREACH(lnk, &grp->partial, all.in) {
939 int flags = (flags_in | lnk->flags) & LINK_PARTIALLY_SPECIFIED;
941 if (flags == LINK_PARTIALLY_SPECIFIED &&
942 lnk_unknown_all == NULL)
943 lnk_unknown_all = lnk;
944 if (flags == LINK_UNKNOWN_DEST_ADDR &&
945 lnk->dst_port == dst_port &&
946 lnk_unknown_dst_addr == NULL)
947 lnk_unknown_dst_addr = lnk;
948 if (flags == LINK_UNKNOWN_DEST_PORT &&
949 lnk->dst_addr.s_addr == dst_addr.s_addr) {
950 lnk_unknown_dst_port = lnk;
951 break;
956 lnk = (lnk_unknown_dst_port != NULL) ? lnk_unknown_dst_port
957 : (lnk_unknown_dst_addr != NULL) ? lnk_unknown_dst_addr
958 : lnk_unknown_all;
960 if (lnk == NULL || !replace_partial_links)
961 return (lnk);
963 if (lnk->server != NULL) { /* LSNAT link */
964 src_addr = lnk->server->addr;
965 src_port = lnk->server->port;
966 lnk->server = lnk->server->next;
967 } else {
968 src_addr = lnk->src_addr;
969 src_port = lnk->src_port;
972 if (link_type == LINK_SCTP) {
973 lnk->src_addr = src_addr;
974 lnk->src_port = src_port;
975 } else {
976 lnk = ReLink(lnk,
977 src_addr, dst_addr, alias_addr,
978 src_port, dst_port, alias_port,
979 link_type, 0);
981 return (lnk);
984 static struct alias_link *
985 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
986 struct in_addr alias_addr,
987 u_short dst_port,
988 u_short alias_port,
989 int link_type,
990 int replace_partial_links)
992 struct alias_link *lnk;
994 LIBALIAS_LOCK_ASSERT(la);
995 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
996 link_type, replace_partial_links);
998 if (lnk == NULL &&
999 (la->packetAliasMode & PKT_ALIAS_UDP_EIM) &&
1000 link_type == LINK_UDP &&
1001 !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1002 lnk = _FindLinkIn(la, ANY_ADDR, alias_addr, 0, alias_port,
1003 link_type, replace_partial_links);
1006 if (lnk == NULL) {
1008 * The following allows permanent links to be specified as
1009 * using the default aliasing address (i.e. device
1010 * interface address) without knowing in advance what that
1011 * address is.
1013 if (la->aliasAddress.s_addr != INADDR_ANY &&
1014 alias_addr.s_addr == la->aliasAddress.s_addr) {
1015 lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port,
1016 link_type, replace_partial_links);
1019 return (lnk);
1022 static struct alias_link *
1023 FindLinkByInternalEndpoint(struct libalias *la, struct in_addr src_addr,
1024 u_short src_port,
1025 int link_type)
1027 struct alias_link needle = {
1028 .src_addr = src_addr,
1029 .src_port = src_port,
1030 .link_type = link_type
1032 LIBALIAS_LOCK_ASSERT(la);
1033 return SPLAY_FIND(splay_internal_endpoint, &la->linkSplayInternalEndpoint, &needle);
1036 /* External routines for finding/adding links
1038 -- "external" means outside alias_db.c, but within alias*.c --
1040 FindIcmpIn(), FindIcmpOut()
1041 FindFragmentIn1(), FindFragmentIn2()
1042 AddFragmentPtrLink(), FindFragmentPtr()
1043 FindProtoIn(), FindProtoOut()
1044 FindUdpTcpIn(), FindUdpTcpOut()
1045 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1046 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1047 FindOriginalAddress(), FindAliasAddress()
1049 (prototypes in alias_local.h)
1052 struct alias_link *
1053 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1054 struct in_addr alias_addr,
1055 u_short id_alias,
1056 int create)
1058 struct alias_link *lnk;
1060 LIBALIAS_LOCK_ASSERT(la);
1061 lnk = FindLinkIn(la, dst_addr, alias_addr,
1062 NO_DEST_PORT, id_alias,
1063 LINK_ICMP, 0);
1064 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1065 struct in_addr target_addr;
1067 target_addr = FindOriginalAddress(la, alias_addr);
1068 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1069 id_alias, NO_DEST_PORT, id_alias,
1070 LINK_ICMP);
1072 return (lnk);
1075 struct alias_link *
1076 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1077 struct in_addr dst_addr,
1078 u_short id,
1079 int create)
1081 struct alias_link *lnk;
1083 LIBALIAS_LOCK_ASSERT(la);
1084 lnk = FindLinkOut(la, src_addr, dst_addr,
1085 id, NO_DEST_PORT,
1086 LINK_ICMP, 0);
1087 if (lnk == NULL && create) {
1088 struct in_addr alias_addr;
1090 alias_addr = FindAliasAddress(la, src_addr);
1091 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1092 id, NO_DEST_PORT, GET_ALIAS_ID,
1093 LINK_ICMP);
1095 return (lnk);
1098 struct alias_link *
1099 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1100 struct in_addr alias_addr,
1101 u_short ip_id)
1103 struct alias_link *lnk;
1105 LIBALIAS_LOCK_ASSERT(la);
1106 lnk = FindLinkIn(la, dst_addr, alias_addr,
1107 NO_DEST_PORT, ip_id,
1108 LINK_FRAGMENT_ID, 0);
1110 if (lnk == NULL) {
1111 lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr,
1112 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1113 LINK_FRAGMENT_ID);
1115 return (lnk);
1118 /* Doesn't add a link if one is not found. */
1119 struct alias_link *
1120 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,
1121 struct in_addr alias_addr, u_short ip_id)
1123 LIBALIAS_LOCK_ASSERT(la);
1124 return FindLinkIn(la, dst_addr, alias_addr,
1125 NO_DEST_PORT, ip_id,
1126 LINK_FRAGMENT_ID, 0);
1129 struct alias_link *
1130 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1131 u_short ip_id)
1133 LIBALIAS_LOCK_ASSERT(la);
1134 return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR,
1135 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1136 LINK_FRAGMENT_PTR);
1139 struct alias_link *
1140 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1141 u_short ip_id)
1143 LIBALIAS_LOCK_ASSERT(la);
1144 return FindLinkIn(la, dst_addr, ANY_ADDR,
1145 NO_DEST_PORT, ip_id,
1146 LINK_FRAGMENT_PTR, 0);
1149 struct alias_link *
1150 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1151 struct in_addr alias_addr,
1152 u_char proto)
1154 struct alias_link *lnk;
1156 LIBALIAS_LOCK_ASSERT(la);
1157 lnk = FindLinkIn(la, dst_addr, alias_addr,
1158 NO_DEST_PORT, 0,
1159 proto, 1);
1161 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1162 struct in_addr target_addr;
1164 target_addr = FindOriginalAddress(la, alias_addr);
1165 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1166 NO_SRC_PORT, NO_DEST_PORT, 0,
1167 proto);
1169 return (lnk);
1172 struct alias_link *
1173 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1174 struct in_addr dst_addr,
1175 u_char proto)
1177 struct alias_link *lnk;
1179 LIBALIAS_LOCK_ASSERT(la);
1180 lnk = FindLinkOut(la, src_addr, dst_addr,
1181 NO_SRC_PORT, NO_DEST_PORT,
1182 proto, 1);
1184 if (lnk == NULL) {
1185 struct in_addr alias_addr;
1187 alias_addr = FindAliasAddress(la, src_addr);
1188 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1189 NO_SRC_PORT, NO_DEST_PORT, 0,
1190 proto);
1192 return (lnk);
1195 struct alias_link *
1196 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1197 struct in_addr alias_addr,
1198 u_short dst_port,
1199 u_short alias_port,
1200 u_char proto,
1201 int create)
1203 int link_type;
1204 struct alias_link *lnk;
1206 LIBALIAS_LOCK_ASSERT(la);
1207 switch (proto) {
1208 case IPPROTO_UDP:
1209 link_type = LINK_UDP;
1210 break;
1211 case IPPROTO_TCP:
1212 link_type = LINK_TCP;
1213 break;
1214 default:
1215 return (NULL);
1216 break;
1219 lnk = FindLinkIn(la, dst_addr, alias_addr,
1220 dst_port, alias_port,
1221 link_type, create);
1223 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1224 struct in_addr target_addr;
1226 target_addr = FindOriginalAddress(la, alias_addr);
1227 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1228 alias_port, dst_port, alias_port,
1229 link_type);
1231 return (lnk);
1234 struct alias_link *
1235 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1236 struct in_addr dst_addr,
1237 u_short src_port,
1238 u_short dst_port,
1239 u_char proto,
1240 int create)
1242 int link_type;
1243 struct alias_link *lnk;
1245 LIBALIAS_LOCK_ASSERT(la);
1246 switch (proto) {
1247 case IPPROTO_UDP:
1248 link_type = LINK_UDP;
1249 break;
1250 case IPPROTO_TCP:
1251 link_type = LINK_TCP;
1252 break;
1253 default:
1254 return (NULL);
1255 break;
1258 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1260 if (lnk == NULL && create) {
1261 struct in_addr alias_addr;
1263 alias_addr = FindAliasAddress(la, src_addr);
1264 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1265 src_port, dst_port, GET_ALIAS_PORT,
1266 link_type);
1268 return (lnk);
1271 struct alias_link *
1272 AddPptp(struct libalias *la, struct in_addr src_addr,
1273 struct in_addr dst_addr,
1274 struct in_addr alias_addr,
1275 u_int16_t src_call_id)
1277 struct alias_link *lnk;
1279 LIBALIAS_LOCK_ASSERT(la);
1280 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1281 src_call_id, 0, GET_ALIAS_PORT,
1282 LINK_PPTP);
1284 return (lnk);
1287 struct alias_link *
1288 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1289 struct in_addr dst_addr,
1290 u_int16_t src_call_id)
1292 struct alias_link *lnk;
1294 LIBALIAS_LOCK_ASSERT(la);
1295 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1296 if (lnk->src_addr.s_addr == src_addr.s_addr &&
1297 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1298 lnk->src_port == src_call_id)
1299 break;
1301 return (UseLink(la, lnk));
1304 struct alias_link *
1305 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1306 struct in_addr dst_addr,
1307 u_int16_t dst_call_id)
1309 struct alias_link *lnk;
1311 LIBALIAS_LOCK_ASSERT(la);
1312 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1313 if (lnk->src_addr.s_addr == src_addr.s_addr &&
1314 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1315 lnk->dst_port == dst_call_id)
1316 break;
1318 return (UseLink(la, lnk));
1321 struct alias_link *
1322 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1323 struct in_addr alias_addr,
1324 u_int16_t dst_call_id)
1326 struct alias_link *lnk;
1328 LIBALIAS_LOCK_ASSERT(la);
1330 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1331 if (lnk->dst_port == dst_call_id &&
1332 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1333 lnk->alias_addr.s_addr == alias_addr.s_addr)
1334 break;
1336 return (UseLink(la, lnk));
1339 struct alias_link *
1340 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1341 struct in_addr alias_addr,
1342 u_int16_t alias_call_id)
1344 struct alias_link *lnk;
1346 LIBALIAS_LOCK_ASSERT(la);
1347 LIST_FOREACH(lnk, &la->pptpList, pptp.list)
1348 if (lnk->alias_port == alias_call_id &&
1349 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1350 lnk->alias_addr.s_addr == alias_addr.s_addr)
1351 break;
1353 return (lnk);
1356 struct alias_link *
1357 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1358 struct in_addr dst_addr,
1359 u_short src_port,
1360 u_short alias_port,
1361 u_char proto)
1363 int link_type;
1364 struct alias_link *lnk;
1366 LIBALIAS_LOCK_ASSERT(la);
1367 switch (proto) {
1368 case IPPROTO_UDP:
1369 link_type = LINK_UDP;
1370 break;
1371 case IPPROTO_TCP:
1372 link_type = LINK_TCP;
1373 break;
1374 default:
1375 return (NULL);
1376 break;
1379 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1381 if (lnk == NULL) {
1382 struct in_addr alias_addr;
1384 alias_addr = FindAliasAddress(la, src_addr);
1385 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1386 src_port, 0, alias_port,
1387 link_type);
1389 return (lnk);
1392 struct in_addr
1393 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1395 struct alias_link *lnk;
1397 LIBALIAS_LOCK_ASSERT(la);
1398 lnk = FindLinkIn(la, ANY_ADDR, alias_addr,
1399 0, 0, LINK_ADDR, 0);
1400 if (lnk == NULL) {
1401 if (la->targetAddress.s_addr == INADDR_ANY)
1402 return (alias_addr);
1403 else if (la->targetAddress.s_addr == INADDR_NONE)
1404 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1405 la->aliasAddress : alias_addr;
1406 else
1407 return (la->targetAddress);
1408 } else {
1409 if (lnk->server != NULL) { /* LSNAT link */
1410 struct in_addr src_addr;
1412 src_addr = lnk->server->addr;
1413 lnk->server = lnk->server->next;
1414 return (src_addr);
1415 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1416 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1417 la->aliasAddress : alias_addr;
1418 else
1419 return (lnk->src_addr);
1423 struct in_addr
1424 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1426 struct alias_link *lnk;
1428 LIBALIAS_LOCK_ASSERT(la);
1429 lnk = FindLinkOut(la, original_addr, ANY_ADDR,
1430 0, 0, LINK_ADDR, 0);
1431 if (lnk == NULL) {
1432 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1433 la->aliasAddress : original_addr;
1434 } else {
1435 if (lnk->alias_addr.s_addr == INADDR_ANY)
1436 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1437 la->aliasAddress : original_addr;
1438 else
1439 return (lnk->alias_addr);
1443 /* External routines for getting or changing link data
1444 (external to alias_db.c, but internal to alias*.c)
1446 SetFragmentData(), GetFragmentData()
1447 SetFragmentPtr(), GetFragmentPtr()
1448 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1449 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1450 GetOriginalPort(), GetAliasPort()
1451 SetAckModified(), GetAckModified()
1452 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1453 SetProtocolFlags(), GetProtocolFlags()
1454 SetDestCallId()
1457 void
1458 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1460 lnk->data.frag_addr = src_addr;
1463 void
1464 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1466 *src_addr = lnk->data.frag_addr;
1469 void
1470 SetFragmentPtr(struct alias_link *lnk, void *fptr)
1472 lnk->data.frag_ptr = fptr;
1475 void
1476 GetFragmentPtr(struct alias_link *lnk, void **fptr)
1478 *fptr = lnk->data.frag_ptr;
1481 void
1482 SetStateIn(struct alias_link *lnk, int state)
1484 /* TCP input state */
1485 switch (state) {
1486 case ALIAS_TCP_STATE_DISCONNECTED:
1487 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1488 lnk->expire.time = TCP_EXPIRE_DEAD;
1489 else
1490 lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1491 break;
1492 case ALIAS_TCP_STATE_CONNECTED:
1493 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1494 lnk->expire.time = TCP_EXPIRE_CONNECTED;
1495 break;
1496 default:
1497 #ifdef _KERNEL
1498 panic("libalias:SetStateIn() unknown state");
1499 #else
1500 abort();
1501 #endif
1503 lnk->data.tcp->state.in = state;
1506 void
1507 SetStateOut(struct alias_link *lnk, int state)
1509 /* TCP output state */
1510 switch (state) {
1511 case ALIAS_TCP_STATE_DISCONNECTED:
1512 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1513 lnk->expire.time = TCP_EXPIRE_DEAD;
1514 else
1515 lnk->expire.time = TCP_EXPIRE_SINGLEDEAD;
1516 break;
1517 case ALIAS_TCP_STATE_CONNECTED:
1518 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1519 lnk->expire.time = TCP_EXPIRE_CONNECTED;
1520 break;
1521 default:
1522 #ifdef _KERNEL
1523 panic("libalias:SetStateOut() unknown state");
1524 #else
1525 abort();
1526 #endif
1528 lnk->data.tcp->state.out = state;
1532 GetStateIn(struct alias_link *lnk)
1534 /* TCP input state */
1535 return (lnk->data.tcp->state.in);
1539 GetStateOut(struct alias_link *lnk)
1541 /* TCP output state */
1542 return (lnk->data.tcp->state.out);
1545 struct in_addr
1546 GetOriginalAddress(struct alias_link *lnk)
1548 if (lnk->src_addr.s_addr == INADDR_ANY)
1549 return (lnk->la->aliasAddress);
1550 else
1551 return (lnk->src_addr);
1554 struct in_addr
1555 GetDestAddress(struct alias_link *lnk)
1557 return (lnk->dst_addr);
1560 struct in_addr
1561 GetAliasAddress(struct alias_link *lnk)
1563 if (lnk->alias_addr.s_addr == INADDR_ANY)
1564 return (lnk->la->aliasAddress);
1565 else
1566 return (lnk->alias_addr);
1569 struct in_addr
1570 GetDefaultAliasAddress(struct libalias *la)
1572 LIBALIAS_LOCK_ASSERT(la);
1573 return (la->aliasAddress);
1576 void
1577 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1579 LIBALIAS_LOCK_ASSERT(la);
1580 la->aliasAddress = alias_addr;
1583 u_short
1584 GetOriginalPort(struct alias_link *lnk)
1586 return (lnk->src_port);
1589 u_short
1590 GetAliasPort(struct alias_link *lnk)
1592 return (lnk->alias_port);
1595 #ifndef NO_FW_PUNCH
1596 static u_short
1597 GetDestPort(struct alias_link *lnk)
1599 return (lnk->dst_port);
1602 #endif
1604 /* Indicate that ACK numbers have been modified in a TCP connection */
1605 void
1606 SetAckModified(struct alias_link *lnk)
1608 lnk->data.tcp->state.ack_modified = 1;
1611 struct in_addr
1612 GetProxyAddress(struct alias_link *lnk)
1614 return (lnk->proxy_addr);
1617 void
1618 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1620 lnk->proxy_addr = addr;
1623 u_short
1624 GetProxyPort(struct alias_link *lnk)
1626 return (lnk->proxy_port);
1629 void
1630 SetProxyPort(struct alias_link *lnk, u_short port)
1632 lnk->proxy_port = port;
1635 /* See if ACK numbers have been modified */
1637 GetAckModified(struct alias_link *lnk)
1639 return (lnk->data.tcp->state.ack_modified);
1643 * Find out how much the ACK number has been altered for an
1644 * incoming TCP packet. To do this, a circular list of ACK
1645 * numbers where the TCP packet size was altered is searched.
1647 // XXX ip free
1649 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1651 int i, j;
1652 int delta, ack_diff_min;
1654 delta = 0;
1655 ack_diff_min = -1;
1656 i = lnk->data.tcp->state.index;
1657 for (j = 0; j < N_LINK_TCP_DATA; j++) {
1658 struct ack_data_record x;
1660 if (i == 0)
1661 i = N_LINK_TCP_DATA;
1662 i--;
1663 x = lnk->data.tcp->ack[i];
1664 if (x.active == 1) {
1665 int ack_diff;
1667 ack_diff = SeqDiff(x.ack_new, ack);
1668 if (ack_diff >= 0) {
1669 if (ack_diff_min >= 0) {
1670 if (ack_diff < ack_diff_min) {
1671 delta = x.delta;
1672 ack_diff_min = ack_diff;
1674 } else {
1675 delta = x.delta;
1676 ack_diff_min = ack_diff;
1681 return (delta);
1685 * Find out how much the sequence number has been altered for an
1686 * outgoing TCP packet. To do this, a circular list of ACK numbers
1687 * where the TCP packet size was altered is searched.
1689 // XXX ip free
1691 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
1693 int i, j;
1694 int delta, seq_diff_min;
1696 delta = 0;
1697 seq_diff_min = -1;
1698 i = lnk->data.tcp->state.index;
1699 for (j = 0; j < N_LINK_TCP_DATA; j++) {
1700 struct ack_data_record x;
1702 if (i == 0)
1703 i = N_LINK_TCP_DATA;
1704 i--;
1705 x = lnk->data.tcp->ack[i];
1706 if (x.active == 1) {
1707 int seq_diff;
1709 seq_diff = SeqDiff(x.ack_old, seq);
1710 if (seq_diff >= 0) {
1711 if (seq_diff_min >= 0) {
1712 if (seq_diff < seq_diff_min) {
1713 delta = x.delta;
1714 seq_diff_min = seq_diff;
1716 } else {
1717 delta = x.delta;
1718 seq_diff_min = seq_diff;
1723 return (delta);
1727 * When a TCP packet has been altered in length, save this
1728 * information in a circular list. If enough packets have been
1729 * altered, then this list will begin to overwrite itself.
1731 // XXX ip free
1732 void
1733 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
1734 u_long th_seq, u_int th_off)
1736 struct ack_data_record x;
1737 int hlen, tlen, dlen;
1738 int i;
1740 hlen = (ip_hl + th_off) << 2;
1741 tlen = ntohs(ip_len);
1742 dlen = tlen - hlen;
1744 x.ack_old = htonl(ntohl(th_seq) + dlen);
1745 x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
1746 x.delta = delta;
1747 x.active = 1;
1749 i = lnk->data.tcp->state.index;
1750 lnk->data.tcp->ack[i] = x;
1752 i++;
1753 if (i == N_LINK_TCP_DATA)
1754 lnk->data.tcp->state.index = 0;
1755 else
1756 lnk->data.tcp->state.index = i;
1759 void
1760 SetExpire(struct alias_link *lnk, int expire)
1762 if (expire == 0) {
1763 lnk->flags &= ~LINK_PERMANENT;
1764 DeleteLink(&lnk, 0);
1765 } else if (expire == -1) {
1766 lnk->flags |= LINK_PERMANENT;
1767 } else if (expire > 0) {
1768 lnk->expire.time = expire;
1769 } else {
1770 #ifdef LIBALIAS_DEBUG
1771 fprintf(stderr, "PacketAlias/SetExpire(): ");
1772 fprintf(stderr, "error in expire parameter\n");
1773 #endif
1777 void
1778 SetProtocolFlags(struct alias_link *lnk, int pflags)
1780 lnk->pflags = pflags;
1784 GetProtocolFlags(struct alias_link *lnk)
1786 return (lnk->pflags);
1789 void
1790 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
1792 LIBALIAS_LOCK_ASSERT(lnk->la);
1793 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
1794 lnk->src_port, cid, lnk->alias_port, lnk->link_type, 1);
1797 /* Miscellaneous Functions
1799 HouseKeeping()
1800 InitPacketAliasLog()
1801 UninitPacketAliasLog()
1805 Whenever an outgoing or incoming packet is handled, HouseKeeping()
1806 is called to find and remove timed-out aliasing links. Logic exists
1807 to sweep through the entire table and linked list structure
1808 every 60 seconds.
1810 (prototype in alias_local.h)
1813 void
1814 HouseKeeping(struct libalias *la)
1816 static unsigned int packets = 0;
1817 static unsigned int packet_limit = 1000;
1819 LIBALIAS_LOCK_ASSERT(la);
1820 packets++;
1823 * User space time/gettimeofday/... is very expensive.
1824 * Kernel space cache trashing is unnecessary.
1826 * Save system time (seconds) in global variable LibAliasTime
1827 * for use by other functions. This is done so as not to
1828 * unnecessarily waste timeline by making system calls.
1830 * Reduce the amount of house keeping work substantially by
1831 * sampling over the packets.
1833 if (packet_limit <= 1 || packets % packet_limit == 0) {
1834 time_t now;
1836 #ifdef _KERNEL
1837 now = time_uptime;
1838 #else
1839 now = time(NULL);
1840 #endif
1841 if (now != LibAliasTime) {
1842 /* retry three times a second */
1843 packet_limit = packets / 3;
1844 packets = 0;
1845 LibAliasTime = now;
1849 /* Do a cleanup for the first packets of the new second only */
1850 if (packets < (la->udpLinkCount + la->tcpLinkCount)) {
1851 struct alias_link * lnk = TAILQ_FIRST(&la->checkExpire);
1853 CleanupLink(la, &lnk, 0);
1857 /* Init the log file and enable logging */
1858 static int
1859 InitPacketAliasLog(struct libalias *la)
1861 LIBALIAS_LOCK_ASSERT(la);
1862 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
1863 #ifdef _KERNEL
1864 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
1866 #else
1867 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
1868 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1869 #endif
1870 else
1871 return (ENOMEM); /* log initialization failed */
1872 la->packetAliasMode |= PKT_ALIAS_LOG;
1875 return (1);
1878 /* Close the log-file and disable logging. */
1879 static void
1880 UninitPacketAliasLog(struct libalias *la)
1882 LIBALIAS_LOCK_ASSERT(la);
1883 if (la->logDesc) {
1884 #ifdef _KERNEL
1885 free(la->logDesc);
1886 #else
1887 fclose(la->logDesc);
1888 #endif
1889 la->logDesc = NULL;
1891 la->packetAliasMode &= ~PKT_ALIAS_LOG;
1894 /* Outside world interfaces
1896 -- "outside world" means other than alias*.c routines --
1898 PacketAliasRedirectPort()
1899 PacketAliasAddServer()
1900 PacketAliasRedirectProto()
1901 PacketAliasRedirectAddr()
1902 PacketAliasRedirectDynamic()
1903 PacketAliasRedirectDelete()
1904 PacketAliasSetAddress()
1905 PacketAliasInit()
1906 PacketAliasUninit()
1907 PacketAliasSetMode()
1909 (prototypes in alias.h)
1912 /* Redirection from a specific public addr:port to a
1913 private addr:port */
1914 struct alias_link *
1915 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
1916 struct in_addr dst_addr, u_short dst_port,
1917 struct in_addr alias_addr, u_short alias_port,
1918 u_char proto)
1920 int link_type;
1921 struct alias_link *lnk;
1923 LIBALIAS_LOCK(la);
1924 switch (proto) {
1925 case IPPROTO_UDP:
1926 link_type = LINK_UDP;
1927 break;
1928 case IPPROTO_TCP:
1929 link_type = LINK_TCP;
1930 break;
1931 case IPPROTO_SCTP:
1932 link_type = LINK_SCTP;
1933 break;
1934 default:
1935 #ifdef LIBALIAS_DEBUG
1936 fprintf(stderr, "PacketAliasRedirectPort(): ");
1937 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
1938 #endif
1939 lnk = NULL;
1940 goto getout;
1943 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1944 src_port, dst_port, alias_port,
1945 link_type);
1947 if (lnk != NULL) {
1948 lnk->flags |= LINK_PERMANENT;
1950 #ifdef LIBALIAS_DEBUG
1951 else {
1952 fprintf(stderr, "PacketAliasRedirectPort(): "
1953 "call to AddLink() failed\n");
1955 #endif
1957 getout:
1958 LIBALIAS_UNLOCK(la);
1959 return (lnk);
1962 /* Add server to the pool of servers */
1964 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
1966 struct server *server;
1967 int res;
1969 LIBALIAS_LOCK(la);
1970 (void)la;
1972 switch (lnk->link_type) {
1973 case LINK_PPTP:
1974 server = NULL;
1975 break;
1976 default:
1977 server = malloc(sizeof(struct server));
1978 break;
1981 if (server != NULL) {
1982 struct server *head;
1984 server->addr = addr;
1985 server->port = port;
1987 head = lnk->server;
1988 if (head == NULL) {
1989 server->next = server;
1990 /* not usable for outgoing connections */
1991 SPLAY_REMOVE(splay_out, &la->linkSplayOut, lnk);
1992 } else {
1993 struct server *s;
1995 for (s = head; s->next != head; s = s->next)
1997 s->next = server;
1998 server->next = head;
2000 lnk->server = server;
2001 res = 0;
2002 } else
2003 res = -1;
2005 LIBALIAS_UNLOCK(la);
2006 return (res);
2009 /* Redirect packets of a given IP protocol from a specific
2010 public address to a private address */
2011 struct alias_link *
2012 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2013 struct in_addr dst_addr,
2014 struct in_addr alias_addr,
2015 u_char proto)
2017 struct alias_link *lnk;
2019 LIBALIAS_LOCK(la);
2020 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2021 NO_SRC_PORT, NO_DEST_PORT, 0,
2022 proto);
2024 if (lnk != NULL) {
2025 lnk->flags |= LINK_PERMANENT;
2027 #ifdef LIBALIAS_DEBUG
2028 else {
2029 fprintf(stderr, "PacketAliasRedirectProto(): "
2030 "call to AddLink() failed\n");
2032 #endif
2034 LIBALIAS_UNLOCK(la);
2035 return (lnk);
2038 /* Static address translation */
2039 struct alias_link *
2040 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2041 struct in_addr alias_addr)
2043 struct alias_link *lnk;
2045 LIBALIAS_LOCK(la);
2046 lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr,
2047 0, 0, 0,
2048 LINK_ADDR);
2050 if (lnk != NULL) {
2051 lnk->flags |= LINK_PERMANENT;
2053 #ifdef LIBALIAS_DEBUG
2054 else {
2055 fprintf(stderr, "PacketAliasRedirectAddr(): "
2056 "call to AddLink() failed\n");
2058 #endif
2060 LIBALIAS_UNLOCK(la);
2061 return (lnk);
2064 /* Mark the aliasing link dynamic */
2066 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2068 int res;
2070 LIBALIAS_LOCK(la);
2071 (void)la;
2073 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2074 res = -1;
2075 else {
2076 lnk->flags &= ~LINK_PERMANENT;
2077 res = 0;
2079 LIBALIAS_UNLOCK(la);
2080 return (res);
2083 /* This is a dangerous function to put in the API,
2084 because an invalid pointer can crash the program. */
2085 void
2086 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2088 LIBALIAS_LOCK(la);
2089 (void)la;
2090 DeleteLink(&lnk, 1);
2091 LIBALIAS_UNLOCK(la);
2094 void
2095 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2097 LIBALIAS_LOCK(la);
2098 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2099 && la->aliasAddress.s_addr != addr.s_addr)
2100 CleanupAliasData(la, 0);
2102 la->aliasAddress = addr;
2103 LIBALIAS_UNLOCK(la);
2106 void
2107 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
2108 u_short port_high)
2110 LIBALIAS_LOCK(la);
2111 if (port_low) {
2112 la->aliasPortLower = port_low;
2113 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
2114 la->aliasPortLength = port_high - port_low + 1;
2115 } else {
2116 /* Set default values */
2117 la->aliasPortLower = 0x8000;
2118 la->aliasPortLength = 0x8000;
2120 LIBALIAS_UNLOCK(la);
2123 void
2124 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2126 LIBALIAS_LOCK(la);
2127 la->targetAddress = target_addr;
2128 LIBALIAS_UNLOCK(la);
2131 static void
2132 finishoff(void)
2134 while (!LIST_EMPTY(&instancehead))
2135 LibAliasUninit(LIST_FIRST(&instancehead));
2138 struct libalias *
2139 LibAliasInit(struct libalias *la)
2141 if (la == NULL) {
2142 #ifdef _KERNEL
2143 #undef malloc /* XXX: ugly */
2144 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2145 #else
2146 la = calloc(sizeof *la, 1);
2147 if (la == NULL)
2148 return (la);
2149 #endif
2151 #ifndef _KERNEL
2152 /* kernel cleans up on module unload */
2153 if (LIST_EMPTY(&instancehead))
2154 atexit(finishoff);
2155 #endif
2156 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2158 #ifdef _KERNEL
2159 LibAliasTime = time_uptime;
2160 #else
2161 LibAliasTime = time(NULL);
2162 #endif
2164 SPLAY_INIT(&la->linkSplayIn);
2165 SPLAY_INIT(&la->linkSplayOut);
2166 SPLAY_INIT(&la->linkSplayInternalEndpoint);
2167 LIST_INIT(&la->pptpList);
2168 TAILQ_INIT(&la->checkExpire);
2169 #ifdef _KERNEL
2170 AliasSctpInit(la);
2171 #endif
2172 LIBALIAS_LOCK_INIT(la);
2173 LIBALIAS_LOCK(la);
2174 } else {
2175 LIBALIAS_LOCK(la);
2176 CleanupAliasData(la, 1);
2177 #ifdef _KERNEL
2178 AliasSctpTerm(la);
2179 AliasSctpInit(la);
2180 #endif
2183 la->aliasAddress.s_addr = INADDR_ANY;
2184 la->targetAddress.s_addr = INADDR_ANY;
2185 la->aliasPortLower = 0x8000;
2186 la->aliasPortLength = 0x8000;
2188 la->icmpLinkCount = 0;
2189 la->udpLinkCount = 0;
2190 la->tcpLinkCount = 0;
2191 la->sctpLinkCount = 0;
2192 la->pptpLinkCount = 0;
2193 la->protoLinkCount = 0;
2194 la->fragmentIdLinkCount = 0;
2195 la->fragmentPtrLinkCount = 0;
2196 la->sockCount = 0;
2198 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2199 #ifndef NO_USE_SOCKETS
2200 | PKT_ALIAS_USE_SOCKETS
2201 #endif
2202 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2203 #ifndef NO_FW_PUNCH
2204 la->fireWallFD = -1;
2205 #endif
2206 #ifndef _KERNEL
2207 LibAliasRefreshModules();
2208 #endif
2209 LIBALIAS_UNLOCK(la);
2210 return (la);
2213 void
2214 LibAliasUninit(struct libalias *la)
2216 LIBALIAS_LOCK(la);
2217 #ifdef _KERNEL
2218 AliasSctpTerm(la);
2219 #endif
2220 CleanupAliasData(la, 1);
2221 UninitPacketAliasLog(la);
2222 #ifndef NO_FW_PUNCH
2223 UninitPunchFW(la);
2224 #endif
2225 LIST_REMOVE(la, instancelist);
2226 LIBALIAS_UNLOCK(la);
2227 LIBALIAS_LOCK_DESTROY(la);
2228 free(la);
2231 /* Change mode for some operations */
2232 unsigned int
2233 LibAliasSetMode(
2234 struct libalias *la,
2235 unsigned int flags, /* Which state to bring flags to */
2236 unsigned int mask /* Mask of which flags to affect (use 0 to
2237 * do a probe for flag values) */
2240 int res = -1;
2242 LIBALIAS_LOCK(la);
2243 if (flags & mask & PKT_ALIAS_LOG) {
2244 /* Enable logging */
2245 if (InitPacketAliasLog(la) == ENOMEM)
2246 goto getout;
2247 } else if (~flags & mask & PKT_ALIAS_LOG)
2248 /* _Disable_ logging */
2249 UninitPacketAliasLog(la);
2251 #ifndef NO_FW_PUNCH
2252 if (flags & mask & PKT_ALIAS_PUNCH_FW)
2253 /* Start punching holes in the firewall? */
2254 InitPunchFW(la);
2255 else if (~flags & mask & PKT_ALIAS_PUNCH_FW)
2256 /* Stop punching holes in the firewall? */
2257 UninitPunchFW(la);
2258 #endif
2260 /* Other flags can be set/cleared without special action */
2261 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2262 res = la->packetAliasMode;
2263 getout:
2264 LIBALIAS_UNLOCK(la);
2265 return (res);
2268 #ifndef NO_FW_PUNCH
2270 /*****************
2271 Code to support firewall punching. This shouldn't really be in this
2272 file, but making variables global is evil too.
2273 ****************/
2275 /* Firewall include files */
2276 #include <net/if.h>
2277 #include <netinet/ip_fw.h>
2278 #include <string.h>
2279 #include <err.h>
2282 * helper function, updates the pointer to cmd with the length
2283 * of the current command, and also cleans up the first word of
2284 * the new command in case it has been clobbered before.
2286 static ipfw_insn *
2287 next_cmd(ipfw_insn * cmd)
2289 cmd += F_LEN(cmd);
2290 bzero(cmd, sizeof(*cmd));
2291 return (cmd);
2295 * A function to fill simple commands of size 1.
2296 * Existing flags are preserved.
2298 static ipfw_insn *
2299 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2300 int flags, u_int16_t arg)
2302 cmd->opcode = opcode;
2303 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2304 cmd->arg1 = arg;
2305 return next_cmd(cmd);
2308 static ipfw_insn *
2309 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2311 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2313 cmd->addr.s_addr = addr;
2314 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2317 static ipfw_insn *
2318 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2320 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2322 cmd->ports[0] = cmd->ports[1] = port;
2323 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2326 static int
2327 fill_rule(void *buf, int bufsize, int rulenum,
2328 enum ipfw_opcodes action, int proto,
2329 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2331 struct ip_fw *rule = (struct ip_fw *)buf;
2332 ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2334 bzero(buf, bufsize);
2335 rule->rulenum = rulenum;
2337 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2338 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2339 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2340 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2341 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2343 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2344 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2346 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2348 return ((char *)cmd - (char *)buf);
2351 static void
2352 InitPunchFW(struct libalias *la)
2354 la->fireWallField = malloc(la->fireWallNumNums);
2355 if (la->fireWallField) {
2356 memset(la->fireWallField, 0, la->fireWallNumNums);
2357 if (la->fireWallFD < 0) {
2358 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2360 ClearAllFWHoles(la);
2361 la->fireWallActiveNum = la->fireWallBaseNum;
2365 static void
2366 UninitPunchFW(struct libalias *la)
2368 ClearAllFWHoles(la);
2369 if (la->fireWallFD >= 0)
2370 close(la->fireWallFD);
2371 la->fireWallFD = -1;
2372 if (la->fireWallField)
2373 free(la->fireWallField);
2374 la->fireWallField = NULL;
2375 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2378 /* Make a certain link go through the firewall */
2379 void
2380 PunchFWHole(struct alias_link *lnk)
2382 struct libalias *la;
2383 int r; /* Result code */
2384 struct ip_fw rule; /* On-the-fly built rule */
2385 int fwhole; /* Where to punch hole */
2387 la = lnk->la;
2389 /* Don't do anything unless we are asked to */
2390 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2391 la->fireWallFD < 0 ||
2392 lnk->link_type != LINK_TCP)
2393 return;
2395 memset(&rule, 0, sizeof rule);
2397 /** Build rule **/
2399 /* Find empty slot */
2400 for (fwhole = la->fireWallActiveNum;
2401 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2402 fw_tstfield(la, la->fireWallField, fwhole);
2403 fwhole++);
2404 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2405 for (fwhole = la->fireWallBaseNum;
2406 fwhole < la->fireWallActiveNum &&
2407 fw_tstfield(la, la->fireWallField, fwhole);
2408 fwhole++);
2409 if (fwhole == la->fireWallActiveNum) {
2410 /* No rule point empty - we can't punch more holes. */
2411 la->fireWallActiveNum = la->fireWallBaseNum;
2412 #ifdef LIBALIAS_DEBUG
2413 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2414 #endif
2415 return;
2418 /* Start next search at next position */
2419 la->fireWallActiveNum = fwhole + 1;
2422 * generate two rules of the form
2424 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2425 * accept tcp from DAddr DPort to OAddr OPort
2427 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2428 u_int32_t rulebuf[255];
2429 int i;
2431 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2432 O_ACCEPT, IPPROTO_TCP,
2433 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2434 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2435 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2436 if (r)
2437 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2439 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2440 O_ACCEPT, IPPROTO_TCP,
2441 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2442 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2443 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2444 if (r)
2445 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2448 /* Indicate hole applied */
2449 lnk->data.tcp->fwhole = fwhole;
2450 fw_setfield(la, la->fireWallField, fwhole);
2453 /* Remove a hole in a firewall associated with a particular alias
2454 lnk. Calling this too often is harmless. */
2455 static void
2456 ClearFWHole(struct alias_link *lnk)
2458 struct libalias *la;
2460 la = lnk->la;
2461 if (lnk->link_type == LINK_TCP) {
2462 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall hole? */
2463 struct ip_fw rule;
2465 if (fwhole < 0)
2466 return;
2468 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2469 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2470 &fwhole, sizeof fwhole));
2471 fw_clrfield(la, la->fireWallField, fwhole);
2472 lnk->data.tcp->fwhole = -1;
2476 /* Clear out the entire range dedicated to firewall holes. */
2477 static void
2478 ClearAllFWHoles(struct libalias *la)
2480 struct ip_fw rule; /* On-the-fly built rule */
2481 int i;
2483 if (la->fireWallFD < 0)
2484 return;
2486 memset(&rule, 0, sizeof rule);
2487 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2488 int r = i;
2490 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2492 /* XXX: third arg correct here ? /phk */
2493 memset(la->fireWallField, 0, la->fireWallNumNums);
2496 #endif /* !NO_FW_PUNCH */
2498 void
2499 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2501 LIBALIAS_LOCK(la);
2502 #ifndef NO_FW_PUNCH
2503 la->fireWallBaseNum = base;
2504 la->fireWallNumNums = num;
2505 #endif
2506 LIBALIAS_UNLOCK(la);
2509 void
2510 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2512 LIBALIAS_LOCK(la);
2513 la->skinnyPort = port;
2514 LIBALIAS_UNLOCK(la);
2518 * Find the address to redirect incoming packets
2520 struct in_addr
2521 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm)
2523 struct alias_link *lnk;
2524 struct in_addr redir;
2526 LIBALIAS_LOCK_ASSERT(la);
2527 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2528 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2529 if (lnk != NULL) {
2530 /* port redirect */
2531 return (lnk->src_addr);
2532 } else {
2533 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2534 if (redir.s_addr == la->aliasAddress.s_addr ||
2535 redir.s_addr == la->targetAddress.s_addr) {
2536 /* No address found */
2537 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2538 NO_DEST_PORT, 0, LINK_SCTP, 1);
2539 if (lnk != NULL)
2540 /* redirect proto */
2541 return (lnk->src_addr);
2543 return (redir); /* address redirect */