2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
29 #include <sys/cdefs.h>
31 #include <machine/stdarg.h>
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
36 #include <sys/module.h>
37 #include <sys/rwlock.h>
38 #include <sys/syslog.h>
43 #include <sys/errno.h>
48 #include <sys/socket.h>
49 #include <netinet/tcp.h>
52 #include <netinet/libalias/alias.h>
53 #include <netinet/libalias/alias_local.h>
54 #include <netinet/libalias/alias_mod.h>
58 #include "alias_local.h"
59 #include "alias_mod.h"
64 static LIST_HEAD(, libalias
) instancehead
= LIST_HEAD_INITIALIZER(instancehead
);
67 /* Kernel module definition. */
69 MALLOC_DEFINE(M_ALIAS
, "libalias", "packet aliasing");
71 MODULE_VERSION(libalias
, 1);
74 alias_mod_handler(module_t mod
, int type
, void *data
)
87 static moduledata_t alias_mod
= {
88 "alias", alias_mod_handler
, NULL
91 DECLARE_MODULE(alias
, alias_mod
, SI_SUB_DRIVERS
, SI_ORDER_SECOND
);
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
,
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
)
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
);
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
));
135 AliasLog(char *str
, const char *format
, ...)
139 va_start(ap
, format
);
140 vsnprintf(str
, LIBALIAS_BUF_SIZE
, format
, ap
);
145 AliasLog(FILE *stream
, const char *format
, ...)
149 va_start(ap
, format
);
150 vfprintf(stream
, format
, ap
);
157 ShowAliasStats(struct libalias
*la
)
159 LIBALIAS_LOCK_ASSERT(la
);
160 /* Used for debugging */
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",
173 la
->sctpLinkCount
>>1, /* sctp counts half associations */
176 la
->fragmentIdLinkCount
,
177 la
->fragmentPtrLinkCount
,
180 AliasLog(la
->logDesc
, " (sock=%u)\n", la
->sockCount
);
185 void SctpShowAliasStats(struct libalias
*la
)
190 /* get random port in network byte order */
192 _RandomPort(struct libalias
*la
) {
195 port
= la
->aliasPortLower
+
196 arc4random_uniform(la
->aliasPortLength
);
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). */
207 GetNewPort(struct libalias
*la
, struct alias_link
*lnk
, int alias_port_param
)
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
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
;
230 if (alias_port_param
!= GET_ALIAS_PORT
) {
231 #ifdef LIBALIAS_DEBUG
232 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
233 fprintf(stderr
, "input parameter error\n");
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
;
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
)
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);
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
)
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
)
289 if (i
>= max_trials
) {
290 #ifdef LIBALIAS_DEBUG
291 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
292 fprintf(stderr
, "could not find free port\n");
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
)) {
307 lnk
->alias_port
= port
;
312 #ifndef NO_USE_SOCKETS
314 GetSocket(struct libalias
*la
, u_short port_net
, int *sockfd
, int link_type
)
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);
326 #ifdef LIBALIAS_DEBUG
327 fprintf(stderr
, "PacketAlias/GetSocket(): ");
328 fprintf(stderr
, "incorrect link type\n");
334 #ifdef LIBALIAS_DEBUG
335 fprintf(stderr
, "PacketAlias/GetSocket(): ");
336 fprintf(stderr
, "socket() error %d\n", *sockfd
);
340 sock_addr
.sin_family
= AF_INET
;
341 sock_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
342 sock_addr
.sin_port
= port_net
;
345 (struct sockaddr
*)&sock_addr
,
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
,
379 LIBALIAS_LOCK_ASSERT(la
);
381 * Get link_type from protocol
386 link_type
= LINK_UDP
;
389 link_type
= LINK_TCP
;
397 * The aliasing port is automatically selected by one of two
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.
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
;
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
)
430 /* Found a good range, return base */
435 #ifdef LIBALIAS_DEBUG
436 fprintf(stderr
, "PacketAlias/FindNewPortGroup(): ");
437 fprintf(stderr
, "could not find free port(s)\n");
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
);
455 CleanupLink(struct libalias
*la
, struct alias_link
**lnk
, int deletePermanent
)
457 LIBALIAS_LOCK_ASSERT(la
);
459 if (lnk
== NULL
|| *lnk
== NULL
)
462 if (LibAliasTime
- (*lnk
)->timestamp
> (*lnk
)->expire
.time
) {
463 DeleteLink(lnk
, deletePermanent
);
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);
478 lnk
->timestamp
= LibAliasTime
;
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
))
494 /* Delete associated firewall hole, if any */
498 switch (lnk
->link_type
) {
500 LIST_REMOVE(lnk
, pptp
.list
);
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
;
513 } while ((curr
= next
) != head
);
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);
529 LIST_EMPTY(&grp
->full
) &&
530 LIST_EMPTY(&grp
->partial
)) {
531 SPLAY_REMOVE(splay_in
, &la
->linkSplayIn
, grp
);
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) {
548 /* Link-type dependent cleanup */
549 switch (lnk
->link_type
) {
563 case LINK_FRAGMENT_ID
:
564 la
->fragmentIdLinkCount
--;
566 case LINK_FRAGMENT_PTR
:
567 la
->fragmentPtrLinkCount
--;
568 if (lnk
->data
.frag_ptr
!= NULL
)
569 free(lnk
->data
.frag_ptr
);
574 la
->protoLinkCount
--;
582 /* Write statistics, if logging enabled */
583 if (la
->packetAliasMode
& PKT_ALIAS_LOG
) {
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
));
599 #ifdef LIBALIAS_DEBUG
600 fprintf(stderr
, "PacketAlias/AddLink(): ");
601 fprintf(stderr
, "malloc() call failed.\n");
605 /* Basic initialization */
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
;
615 lnk
->link_type
= link_type
;
616 #ifndef NO_USE_SOCKETS
621 lnk
->timestamp
= LibAliasTime
;
623 /* Expiration time */
626 lnk
->expire
.time
= ICMP_EXPIRE_TIME
;
629 lnk
->expire
.time
= UDP_EXPIRE_TIME
;
632 lnk
->expire
.time
= TCP_EXPIRE_INITIAL
;
634 case LINK_FRAGMENT_ID
:
635 lnk
->expire
.time
= FRAGMENT_ID_EXPIRE_TIME
;
637 case LINK_FRAGMENT_PTR
:
638 lnk
->expire
.time
= FRAGMENT_PTR_EXPIRE_TIME
;
641 lnk
->expire
.time
= PROTO_EXPIRE_TIME
;
645 /* Determine alias flags */
646 if (dst_addr
.s_addr
== INADDR_ANY
)
647 lnk
->flags
|= LINK_UNKNOWN_DEST_ADDR
;
649 lnk
->flags
|= LINK_UNKNOWN_DEST_PORT
;
651 /* Determine alias port */
652 if (GetNewPort(la
, lnk
, alias_port_param
) != 0) {
656 /* Link-type dependent initialization */
665 struct tcp_dat
*aux_tcp
;
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");
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
;
692 case LINK_FRAGMENT_ID
:
693 la
->fragmentIdLinkCount
++;
695 case LINK_FRAGMENT_PTR
:
696 la
->fragmentPtrLinkCount
++;
701 la
->protoLinkCount
++;
707 LIST_INSERT_HEAD(&la
->pptpList
, lnk
, pptp
.list
);
710 struct group_in
*grp
;
712 grp
= StartPointIn(la
, alias_addr
, lnk
->alias_port
, link_type
, 1);
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
);
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
);
734 /* Include the element into the housekeeping list */
735 TAILQ_INSERT_TAIL(&la
->checkExpire
, lnk
, expire
.list
);
737 if (la
->packetAliasMode
& PKT_ALIAS_LOG
)
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
,
754 int alias_port_param
,
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
,
766 if (new_lnk
!= NULL
&&
767 old_lnk
->link_type
== LINK_TCP
&&
768 old_lnk
->data
.tcp
->fwhole
> 0) {
769 PunchFWHole(new_lnk
);
772 DeleteLink(&old_lnk
, deletePermanent
);
776 static struct alias_link
*
777 _SearchLinkOut(struct libalias
*la
, struct in_addr src_addr
,
778 struct in_addr dst_addr
,
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
,
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
)
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,
815 lnk
= _SearchLinkOut(la
, src_addr
, ANY_ADDR
, src_port
,
816 dst_port
, link_type
);
819 (dst_port
!= 0 || dst_addr
.s_addr
!= INADDR_ANY
)) {
820 lnk
= _SearchLinkOut(la
, src_addr
, ANY_ADDR
, src_port
, 0,
825 src_addr
, dst_addr
, lnk
->alias_addr
,
826 src_port
, dst_port
, lnk
->alias_port
,
832 static struct alias_link
*
833 FindLinkOut(struct libalias
*la
, struct in_addr src_addr
,
834 struct in_addr dst_addr
,
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
);
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
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
);
862 static struct alias_link
*
863 _FindLinkIn(struct libalias
*la
, struct in_addr dst_addr
,
864 struct in_addr alias_addr
,
868 int replace_partial_links
)
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
;
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. */
888 if (dst_addr
.s_addr
== INADDR_ANY
)
889 flags_in
|= LINK_UNKNOWN_DEST_ADDR
;
891 flags_in
|= LINK_UNKNOWN_DEST_PORT
;
894 grp
= StartPointIn(la
, alias_addr
, alias_port
, link_type
, 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
);
909 grp
= StartPointIn(la
, alias_addr
, alias_port
, link_type
, 0);
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
;
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
;
932 case LINK_PARTIALLY_SPECIFIED
:
933 lnk_unknown_all
= LIST_FIRST(&grp
->full
);
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
;
956 lnk
= (lnk_unknown_dst_port
!= NULL
) ? lnk_unknown_dst_port
957 : (lnk_unknown_dst_addr
!= NULL
) ? lnk_unknown_dst_addr
960 if (lnk
== NULL
|| !replace_partial_links
)
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
;
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
;
977 src_addr
, dst_addr
, alias_addr
,
978 src_port
, dst_port
, alias_port
,
984 static struct alias_link
*
985 FindLinkIn(struct libalias
*la
, struct in_addr dst_addr
,
986 struct in_addr alias_addr
,
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
);
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
);
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
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
);
1022 static struct alias_link
*
1023 FindLinkByInternalEndpoint(struct libalias
*la
, struct in_addr src_addr
,
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)
1053 FindIcmpIn(struct libalias
*la
, struct in_addr dst_addr
,
1054 struct in_addr alias_addr
,
1058 struct alias_link
*lnk
;
1060 LIBALIAS_LOCK_ASSERT(la
);
1061 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
1062 NO_DEST_PORT
, id_alias
,
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
,
1076 FindIcmpOut(struct libalias
*la
, struct in_addr src_addr
,
1077 struct in_addr dst_addr
,
1081 struct alias_link
*lnk
;
1083 LIBALIAS_LOCK_ASSERT(la
);
1084 lnk
= FindLinkOut(la
, src_addr
, dst_addr
,
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
,
1099 FindFragmentIn1(struct libalias
*la
, struct in_addr dst_addr
,
1100 struct in_addr alias_addr
,
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);
1111 lnk
= AddLink(la
, ANY_ADDR
, dst_addr
, alias_addr
,
1112 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1118 /* Doesn't add a link if one is not found. */
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);
1130 AddFragmentPtrLink(struct libalias
*la
, struct in_addr dst_addr
,
1133 LIBALIAS_LOCK_ASSERT(la
);
1134 return AddLink(la
, ANY_ADDR
, dst_addr
, ANY_ADDR
,
1135 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1140 FindFragmentPtr(struct libalias
*la
, struct in_addr dst_addr
,
1143 LIBALIAS_LOCK_ASSERT(la
);
1144 return FindLinkIn(la
, dst_addr
, ANY_ADDR
,
1145 NO_DEST_PORT
, ip_id
,
1146 LINK_FRAGMENT_PTR
, 0);
1150 FindProtoIn(struct libalias
*la
, struct in_addr dst_addr
,
1151 struct in_addr alias_addr
,
1154 struct alias_link
*lnk
;
1156 LIBALIAS_LOCK_ASSERT(la
);
1157 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
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,
1173 FindProtoOut(struct libalias
*la
, struct in_addr src_addr
,
1174 struct in_addr dst_addr
,
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
,
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,
1196 FindUdpTcpIn(struct libalias
*la
, struct in_addr dst_addr
,
1197 struct in_addr alias_addr
,
1204 struct alias_link
*lnk
;
1206 LIBALIAS_LOCK_ASSERT(la
);
1209 link_type
= LINK_UDP
;
1212 link_type
= LINK_TCP
;
1219 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
1220 dst_port
, alias_port
,
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
,
1235 FindUdpTcpOut(struct libalias
*la
, struct in_addr src_addr
,
1236 struct in_addr dst_addr
,
1243 struct alias_link
*lnk
;
1245 LIBALIAS_LOCK_ASSERT(la
);
1248 link_type
= LINK_UDP
;
1251 link_type
= LINK_TCP
;
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
,
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
,
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
)
1301 return (UseLink(la
, lnk
));
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
)
1318 return (UseLink(la
, lnk
));
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
)
1336 return (UseLink(la
, lnk
));
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
)
1357 FindRtspOut(struct libalias
*la
, struct in_addr src_addr
,
1358 struct in_addr dst_addr
,
1364 struct alias_link
*lnk
;
1366 LIBALIAS_LOCK_ASSERT(la
);
1369 link_type
= LINK_UDP
;
1372 link_type
= LINK_TCP
;
1379 lnk
= FindLinkOut(la
, src_addr
, dst_addr
, src_port
, 0, link_type
, 1);
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
,
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);
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
;
1407 return (la
->targetAddress
);
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
;
1415 } else if (lnk
->src_addr
.s_addr
== INADDR_ANY
)
1416 return (la
->aliasAddress
.s_addr
!= INADDR_ANY
) ?
1417 la
->aliasAddress
: alias_addr
;
1419 return (lnk
->src_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);
1432 return (la
->aliasAddress
.s_addr
!= INADDR_ANY
) ?
1433 la
->aliasAddress
: original_addr
;
1435 if (lnk
->alias_addr
.s_addr
== INADDR_ANY
)
1436 return (la
->aliasAddress
.s_addr
!= INADDR_ANY
) ?
1437 la
->aliasAddress
: original_addr
;
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()
1458 SetFragmentAddr(struct alias_link
*lnk
, struct in_addr src_addr
)
1460 lnk
->data
.frag_addr
= src_addr
;
1464 GetFragmentAddr(struct alias_link
*lnk
, struct in_addr
*src_addr
)
1466 *src_addr
= lnk
->data
.frag_addr
;
1470 SetFragmentPtr(struct alias_link
*lnk
, void *fptr
)
1472 lnk
->data
.frag_ptr
= fptr
;
1476 GetFragmentPtr(struct alias_link
*lnk
, void **fptr
)
1478 *fptr
= lnk
->data
.frag_ptr
;
1482 SetStateIn(struct alias_link
*lnk
, int state
)
1484 /* TCP input 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
;
1490 lnk
->expire
.time
= TCP_EXPIRE_SINGLEDEAD
;
1492 case ALIAS_TCP_STATE_CONNECTED
:
1493 if (lnk
->data
.tcp
->state
.out
== ALIAS_TCP_STATE_CONNECTED
)
1494 lnk
->expire
.time
= TCP_EXPIRE_CONNECTED
;
1498 panic("libalias:SetStateIn() unknown state");
1503 lnk
->data
.tcp
->state
.in
= state
;
1507 SetStateOut(struct alias_link
*lnk
, int state
)
1509 /* TCP output 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
;
1515 lnk
->expire
.time
= TCP_EXPIRE_SINGLEDEAD
;
1517 case ALIAS_TCP_STATE_CONNECTED
:
1518 if (lnk
->data
.tcp
->state
.in
== ALIAS_TCP_STATE_CONNECTED
)
1519 lnk
->expire
.time
= TCP_EXPIRE_CONNECTED
;
1523 panic("libalias:SetStateOut() unknown state");
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
);
1546 GetOriginalAddress(struct alias_link
*lnk
)
1548 if (lnk
->src_addr
.s_addr
== INADDR_ANY
)
1549 return (lnk
->la
->aliasAddress
);
1551 return (lnk
->src_addr
);
1555 GetDestAddress(struct alias_link
*lnk
)
1557 return (lnk
->dst_addr
);
1561 GetAliasAddress(struct alias_link
*lnk
)
1563 if (lnk
->alias_addr
.s_addr
== INADDR_ANY
)
1564 return (lnk
->la
->aliasAddress
);
1566 return (lnk
->alias_addr
);
1570 GetDefaultAliasAddress(struct libalias
*la
)
1572 LIBALIAS_LOCK_ASSERT(la
);
1573 return (la
->aliasAddress
);
1577 SetDefaultAliasAddress(struct libalias
*la
, struct in_addr alias_addr
)
1579 LIBALIAS_LOCK_ASSERT(la
);
1580 la
->aliasAddress
= alias_addr
;
1584 GetOriginalPort(struct alias_link
*lnk
)
1586 return (lnk
->src_port
);
1590 GetAliasPort(struct alias_link
*lnk
)
1592 return (lnk
->alias_port
);
1597 GetDestPort(struct alias_link
*lnk
)
1599 return (lnk
->dst_port
);
1604 /* Indicate that ACK numbers have been modified in a TCP connection */
1606 SetAckModified(struct alias_link
*lnk
)
1608 lnk
->data
.tcp
->state
.ack_modified
= 1;
1612 GetProxyAddress(struct alias_link
*lnk
)
1614 return (lnk
->proxy_addr
);
1618 SetProxyAddress(struct alias_link
*lnk
, struct in_addr addr
)
1620 lnk
->proxy_addr
= addr
;
1624 GetProxyPort(struct alias_link
*lnk
)
1626 return (lnk
->proxy_port
);
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.
1649 GetDeltaAckIn(u_long ack
, struct alias_link
*lnk
)
1652 int delta
, ack_diff_min
;
1656 i
= lnk
->data
.tcp
->state
.index
;
1657 for (j
= 0; j
< N_LINK_TCP_DATA
; j
++) {
1658 struct ack_data_record x
;
1661 i
= N_LINK_TCP_DATA
;
1663 x
= lnk
->data
.tcp
->ack
[i
];
1664 if (x
.active
== 1) {
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
) {
1672 ack_diff_min
= ack_diff
;
1676 ack_diff_min
= ack_diff
;
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.
1691 GetDeltaSeqOut(u_long seq
, struct alias_link
*lnk
)
1694 int delta
, seq_diff_min
;
1698 i
= lnk
->data
.tcp
->state
.index
;
1699 for (j
= 0; j
< N_LINK_TCP_DATA
; j
++) {
1700 struct ack_data_record x
;
1703 i
= N_LINK_TCP_DATA
;
1705 x
= lnk
->data
.tcp
->ack
[i
];
1706 if (x
.active
== 1) {
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
) {
1714 seq_diff_min
= seq_diff
;
1718 seq_diff_min
= seq_diff
;
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.
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
;
1740 hlen
= (ip_hl
+ th_off
) << 2;
1741 tlen
= ntohs(ip_len
);
1744 x
.ack_old
= htonl(ntohl(th_seq
) + dlen
);
1745 x
.ack_new
= htonl(ntohl(th_seq
) + dlen
+ delta
);
1749 i
= lnk
->data
.tcp
->state
.index
;
1750 lnk
->data
.tcp
->ack
[i
] = x
;
1753 if (i
== N_LINK_TCP_DATA
)
1754 lnk
->data
.tcp
->state
.index
= 0;
1756 lnk
->data
.tcp
->state
.index
= i
;
1760 SetExpire(struct alias_link
*lnk
, int expire
)
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
;
1770 #ifdef LIBALIAS_DEBUG
1771 fprintf(stderr
, "PacketAlias/SetExpire(): ");
1772 fprintf(stderr
, "error in expire parameter\n");
1778 SetProtocolFlags(struct alias_link
*lnk
, int pflags
)
1780 lnk
->pflags
= pflags
;
1784 GetProtocolFlags(struct alias_link
*lnk
)
1786 return (lnk
->pflags
);
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
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
1810 (prototype in alias_local.h)
1814 HouseKeeping(struct libalias
*la
)
1816 static unsigned int packets
= 0;
1817 static unsigned int packet_limit
= 1000;
1819 LIBALIAS_LOCK_ASSERT(la
);
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) {
1841 if (now
!= LibAliasTime
) {
1842 /* retry three times a second */
1843 packet_limit
= packets
/ 3;
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 */
1859 InitPacketAliasLog(struct libalias
*la
)
1861 LIBALIAS_LOCK_ASSERT(la
);
1862 if (~la
->packetAliasMode
& PKT_ALIAS_LOG
) {
1864 if ((la
->logDesc
= malloc(LIBALIAS_BUF_SIZE
)))
1867 if ((la
->logDesc
= fopen("/var/log/alias.log", "w")))
1868 fprintf(la
->logDesc
, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1871 return (ENOMEM
); /* log initialization failed */
1872 la
->packetAliasMode
|= PKT_ALIAS_LOG
;
1878 /* Close the log-file and disable logging. */
1880 UninitPacketAliasLog(struct libalias
*la
)
1882 LIBALIAS_LOCK_ASSERT(la
);
1887 fclose(la
->logDesc
);
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()
1907 PacketAliasSetMode()
1909 (prototypes in alias.h)
1912 /* Redirection from a specific public addr:port to a
1913 private addr:port */
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
,
1921 struct alias_link
*lnk
;
1926 link_type
= LINK_UDP
;
1929 link_type
= LINK_TCP
;
1932 link_type
= LINK_SCTP
;
1935 #ifdef LIBALIAS_DEBUG
1936 fprintf(stderr
, "PacketAliasRedirectPort(): ");
1937 fprintf(stderr
, "only SCTP, TCP and UDP protocols allowed\n");
1943 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
1944 src_port
, dst_port
, alias_port
,
1948 lnk
->flags
|= LINK_PERMANENT
;
1950 #ifdef LIBALIAS_DEBUG
1952 fprintf(stderr
, "PacketAliasRedirectPort(): "
1953 "call to AddLink() failed\n");
1958 LIBALIAS_UNLOCK(la
);
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
;
1972 switch (lnk
->link_type
) {
1977 server
= malloc(sizeof(struct server
));
1981 if (server
!= NULL
) {
1982 struct server
*head
;
1984 server
->addr
= addr
;
1985 server
->port
= port
;
1989 server
->next
= server
;
1990 /* not usable for outgoing connections */
1991 SPLAY_REMOVE(splay_out
, &la
->linkSplayOut
, lnk
);
1995 for (s
= head
; s
->next
!= head
; s
= s
->next
)
1998 server
->next
= head
;
2000 lnk
->server
= server
;
2005 LIBALIAS_UNLOCK(la
);
2009 /* Redirect packets of a given IP protocol from a specific
2010 public address to a private address */
2012 LibAliasRedirectProto(struct libalias
*la
, struct in_addr src_addr
,
2013 struct in_addr dst_addr
,
2014 struct in_addr alias_addr
,
2017 struct alias_link
*lnk
;
2020 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
2021 NO_SRC_PORT
, NO_DEST_PORT
, 0,
2025 lnk
->flags
|= LINK_PERMANENT
;
2027 #ifdef LIBALIAS_DEBUG
2029 fprintf(stderr
, "PacketAliasRedirectProto(): "
2030 "call to AddLink() failed\n");
2034 LIBALIAS_UNLOCK(la
);
2038 /* Static address translation */
2040 LibAliasRedirectAddr(struct libalias
*la
, struct in_addr src_addr
,
2041 struct in_addr alias_addr
)
2043 struct alias_link
*lnk
;
2046 lnk
= AddLink(la
, src_addr
, ANY_ADDR
, alias_addr
,
2051 lnk
->flags
|= LINK_PERMANENT
;
2053 #ifdef LIBALIAS_DEBUG
2055 fprintf(stderr
, "PacketAliasRedirectAddr(): "
2056 "call to AddLink() failed\n");
2060 LIBALIAS_UNLOCK(la
);
2064 /* Mark the aliasing link dynamic */
2066 LibAliasRedirectDynamic(struct libalias
*la
, struct alias_link
*lnk
)
2073 if (lnk
->flags
& LINK_PARTIALLY_SPECIFIED
)
2076 lnk
->flags
&= ~LINK_PERMANENT
;
2079 LIBALIAS_UNLOCK(la
);
2083 /* This is a dangerous function to put in the API,
2084 because an invalid pointer can crash the program. */
2086 LibAliasRedirectDelete(struct libalias
*la
, struct alias_link
*lnk
)
2090 DeleteLink(&lnk
, 1);
2091 LIBALIAS_UNLOCK(la
);
2095 LibAliasSetAddress(struct libalias
*la
, struct in_addr addr
)
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
);
2107 LibAliasSetAliasPortRange(struct libalias
*la
, u_short 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;
2116 /* Set default values */
2117 la
->aliasPortLower
= 0x8000;
2118 la
->aliasPortLength
= 0x8000;
2120 LIBALIAS_UNLOCK(la
);
2124 LibAliasSetTarget(struct libalias
*la
, struct in_addr target_addr
)
2127 la
->targetAddress
= target_addr
;
2128 LIBALIAS_UNLOCK(la
);
2134 while (!LIST_EMPTY(&instancehead
))
2135 LibAliasUninit(LIST_FIRST(&instancehead
));
2139 LibAliasInit(struct libalias
*la
)
2143 #undef malloc /* XXX: ugly */
2144 la
= malloc(sizeof *la
, M_ALIAS
, M_WAITOK
| M_ZERO
);
2146 la
= calloc(sizeof *la
, 1);
2152 /* kernel cleans up on module unload */
2153 if (LIST_EMPTY(&instancehead
))
2156 LIST_INSERT_HEAD(&instancehead
, la
, instancelist
);
2159 LibAliasTime
= time_uptime
;
2161 LibAliasTime
= time(NULL
);
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
);
2172 LIBALIAS_LOCK_INIT(la
);
2176 CleanupAliasData(la
, 1);
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;
2198 la
->packetAliasMode
= PKT_ALIAS_SAME_PORTS
2199 #ifndef NO_USE_SOCKETS
2200 | PKT_ALIAS_USE_SOCKETS
2202 | PKT_ALIAS_RESET_ON_ADDR_CHANGE
;
2204 la
->fireWallFD
= -1;
2207 LibAliasRefreshModules();
2209 LIBALIAS_UNLOCK(la
);
2214 LibAliasUninit(struct libalias
*la
)
2220 CleanupAliasData(la
, 1);
2221 UninitPacketAliasLog(la
);
2225 LIST_REMOVE(la
, instancelist
);
2226 LIBALIAS_UNLOCK(la
);
2227 LIBALIAS_LOCK_DESTROY(la
);
2231 /* Change mode for some operations */
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) */
2243 if (flags
& mask
& PKT_ALIAS_LOG
) {
2244 /* Enable logging */
2245 if (InitPacketAliasLog(la
) == ENOMEM
)
2247 } else if (~flags
& mask
& PKT_ALIAS_LOG
)
2248 /* _Disable_ logging */
2249 UninitPacketAliasLog(la
);
2252 if (flags
& mask
& PKT_ALIAS_PUNCH_FW
)
2253 /* Start punching holes in the firewall? */
2255 else if (~flags
& mask
& PKT_ALIAS_PUNCH_FW
)
2256 /* Stop punching holes in the firewall? */
2260 /* Other flags can be set/cleared without special action */
2261 la
->packetAliasMode
= (flags
& mask
) | (la
->packetAliasMode
& ~mask
);
2262 res
= la
->packetAliasMode
;
2264 LIBALIAS_UNLOCK(la
);
2271 Code to support firewall punching. This shouldn't really be in this
2272 file, but making variables global is evil too.
2275 /* Firewall include files */
2277 #include <netinet/ip_fw.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.
2287 next_cmd(ipfw_insn
* cmd
)
2290 bzero(cmd
, sizeof(*cmd
));
2295 * A function to fill simple commands of size 1.
2296 * Existing flags are preserved.
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
);
2305 return next_cmd(cmd
);
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);
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);
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
);
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
;
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 */
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 */
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
)
2395 memset(&rule
, 0, sizeof rule
);
2399 /* Find empty slot */
2400 for (fwhole
= la
->fireWallActiveNum
;
2401 fwhole
< la
->fireWallBaseNum
+ la
->fireWallNumNums
&&
2402 fw_tstfield(la
, la
->fireWallField
, fwhole
);
2404 if (fwhole
== la
->fireWallBaseNum
+ la
->fireWallNumNums
) {
2405 for (fwhole
= la
->fireWallBaseNum
;
2406 fwhole
< la
->fireWallActiveNum
&&
2407 fw_tstfield(la
, la
->fireWallField
, 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");
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];
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
);
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
);
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. */
2456 ClearFWHole(struct alias_link
*lnk
)
2458 struct libalias
*la
;
2461 if (lnk
->link_type
== LINK_TCP
) {
2462 int fwhole
= lnk
->data
.tcp
->fwhole
; /* Where is the firewall hole? */
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. */
2478 ClearAllFWHoles(struct libalias
*la
)
2480 struct ip_fw rule
; /* On-the-fly built rule */
2483 if (la
->fireWallFD
< 0)
2486 memset(&rule
, 0, sizeof rule
);
2487 for (i
= la
->fireWallBaseNum
; i
< la
->fireWallBaseNum
+ la
->fireWallNumNums
; 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 */
2499 LibAliasSetFWBase(struct libalias
*la
, unsigned int base
, unsigned int num
)
2503 la
->fireWallBaseNum
= base
;
2504 la
->fireWallNumNums
= num
;
2506 LIBALIAS_UNLOCK(la
);
2510 LibAliasSetSkinnyPort(struct libalias
*la
, unsigned int port
)
2513 la
->skinnyPort
= port
;
2514 LIBALIAS_UNLOCK(la
);
2518 * Find the address to redirect incoming packets
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);
2531 return (lnk
->src_addr
);
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);
2540 /* redirect proto */
2541 return (lnk
->src_addr
);
2543 return (redir
); /* address redirect */