2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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>
30 __FBSDID("$FreeBSD$");
33 Alias_db.c encapsulates all data structures used for storing
34 packet aliasing data. Other parts of the aliasing software
35 access data through functions provided in this file.
37 Data storage is based on the notion of a "link", which is
38 established for ICMP echo/reply packets, UDP datagrams and
39 TCP stream connections. A link stores the original source
40 and destination addresses. For UDP and TCP, it also stores
41 source and destination port numbers, as well as an alias
42 port number. Links are also used to store information about
45 There is a facility for sweeping through and deleting old
46 links as new packets are sent through. A simple timeout is
47 used for ICMP and UDP links. TCP links are left alone unless
48 there is an incomplete connection, in which case the link
49 can be deleted after a certain amount of time.
51 Initial version: August, 1996 (cjm)
53 Version 1.4: September 16, 1996 (cjm)
54 Facility for handling incoming links added.
56 Version 1.6: September 18, 1996 (cjm)
57 ICMP data handling simplified.
59 Version 1.7: January 9, 1997 (cjm)
60 Fragment handling simplified.
61 Saves pointers for unresolved fragments.
62 Permits links for unspecified remote ports
63 or unspecified remote addresses.
64 Fixed bug which did not properly zero port
65 table entries after a link was deleted.
66 Cleaned up some obsolete comments.
68 Version 1.8: January 14, 1997 (cjm)
69 Fixed data type error in StartPoint().
70 (This error did not exist prior to v1.7
71 and was discovered and fixed by Ari Suutari)
73 Version 1.9: February 1, 1997
74 Optionally, connections initiated from packet aliasing host
75 machine will will not have their port number aliased unless it
76 conflicts with an aliasing port already being used. (cjm)
78 All options earlier being #ifdef'ed are now available through
79 a new interface, SetPacketAliasMode(). This allows run time
80 control (which is now available in PPP+pktAlias through the
81 'alias' keyword). (ee)
83 Added ability to create an alias port without
84 either destination address or port specified.
85 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
87 Removed K&R style function headers
88 and general cleanup. (ee)
90 Added packetAliasMode to replace compiler #defines's (ee)
92 Allocates sockets for partially specified
93 ports if ALIAS_USE_SOCKETS defined. (cjm)
95 Version 2.0: March, 1997
96 SetAliasAddress() will now clean up alias links
97 if the aliasing address is changed. (cjm)
99 PacketAliasPermanentLink() function added to support permanent
100 links. (J. Fortes suggested the need for this.)
103 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
105 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
108 These permanent links allow for incoming connections to
109 machines on the local network. They can be given with a
110 user-chosen amount of specificity, with increasing specificity
111 meaning more security. (cjm)
113 Quite a bit of rework to the basic engine. The portTable[]
114 array, which kept track of which ports were in use was replaced
115 by a table/linked list structure. (cjm)
117 SetExpire() function added. (cjm)
119 DeleteLink() no longer frees memory association with a pointer
120 to a fragment (this bug was first recognized by E. Eklund in
123 Version 2.1: May, 1997 (cjm)
124 Packet aliasing engine reworked so that it can handle
125 multiple external addresses rather than just a single
128 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
129 added to the API. The first function is a more generalized
130 version of PacketAliasPermanentLink(). The second function
131 implements static network address translation.
133 Version 3.2: July, 2000 (salander and satoh)
134 Added FindNewPortGroup to get contiguous range of port values.
136 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
137 link but not actually add one.
139 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
140 except that the alias port (from FindNewPortGroup) is provided
143 See HISTORY file for additional revisions.
147 #include <machine/stdarg.h>
148 #include <sys/param.h>
149 #include <sys/kernel.h>
150 #include <sys/systm.h>
151 #include <sys/lock.h>
152 #include <sys/module.h>
153 #include <sys/rwlock.h>
154 #include <sys/syslog.h>
159 #include <sys/errno.h>
160 #include <sys/time.h>
164 #include <sys/socket.h>
165 #include <netinet/tcp.h>
168 #include <netinet/libalias/alias.h>
169 #include <netinet/libalias/alias_local.h>
170 #include <netinet/libalias/alias_mod.h>
174 #include "alias_local.h"
175 #include "alias_mod.h"
178 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
181 Constants (note: constants are also defined
182 near relevant functions or structs)
185 /* Parameters used for cleanup of expired links */
186 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
187 #define ALIAS_CLEANUP_INTERVAL_SECS 64
188 #define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
190 /* Timeouts (in seconds) for different link types */
191 #define ICMP_EXPIRE_TIME 60
192 #define UDP_EXPIRE_TIME 60
193 #define PROTO_EXPIRE_TIME 60
194 #define FRAGMENT_ID_EXPIRE_TIME 10
195 #define FRAGMENT_PTR_EXPIRE_TIME 30
197 /* TCP link expire time for different cases */
198 /* When the link has been used and closed - minimal grace time to
199 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
200 #ifndef TCP_EXPIRE_DEAD
201 #define TCP_EXPIRE_DEAD 10
204 /* When the link has been used and closed on one side - the other side
205 is allowed to still send data */
206 #ifndef TCP_EXPIRE_SINGLEDEAD
207 #define TCP_EXPIRE_SINGLEDEAD 90
210 /* When the link isn't yet up */
211 #ifndef TCP_EXPIRE_INITIAL
212 #define TCP_EXPIRE_INITIAL 300
215 /* When the link is up */
216 #ifndef TCP_EXPIRE_CONNECTED
217 #define TCP_EXPIRE_CONNECTED 86400
220 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
221 These constants can be anything except zero, which indicates an
222 unknown port number. */
224 #define NO_DEST_PORT 1
225 #define NO_SRC_PORT 1
229 The fundamental data structure used in this program is
230 "struct alias_link". Whenever a TCP connection is made,
231 a UDP datagram is sent out, or an ICMP echo request is made,
232 a link record is made (if it has not already been created).
233 The link record is identified by the source address/port
234 and the destination address/port. In the case of an ICMP
235 echo request, the source port is treated as being equivalent
236 with the 16-bit ID number of the ICMP packet.
238 The link record also can store some auxiliary data. For
239 TCP connections that have had sequence and acknowledgment
240 modifications, data space is available to track these changes.
241 A state field is used to keep track in changes to the TCP
242 connection state. ID numbers of fragments can also be
243 stored in the auxiliary space. Pointers to unresolved
244 fragments can also be stored.
246 The link records support two independent chainings. Lookup
247 tables for input and out tables hold the initial pointers
248 the link chains. On input, the lookup table indexes on alias
249 port and link type. On output, the lookup table indexes on
250 source address, destination address, source port, destination
254 struct ack_data_record { /* used to save changes to ACK/sequence
262 struct tcp_state { /* Information about TCP connection */
263 int in; /* State for outside -> inside */
264 int out; /* State for inside -> outside */
265 int index; /* Index to ACK data array */
266 int ack_modified; /* Indicates whether ACK and
267 * sequence numbers */
271 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
272 * saved for a modified TCP stream */
274 struct tcp_state state;
275 struct ack_data_record ack[N_LINK_TCP_DATA];
276 int fwhole; /* Which firewall record is used for this
280 struct server { /* LSNAT server pool (circular list) */
286 struct alias_link { /* Main data structure */
288 struct in_addr src_addr; /* Address and port information */
289 struct in_addr dst_addr;
290 struct in_addr alias_addr;
291 struct in_addr proxy_addr;
296 struct server *server;
298 int link_type; /* Type of link: TCP, UDP, ICMP,
301 /* values for link_type */
302 #define LINK_ICMP IPPROTO_ICMP
303 #define LINK_UDP IPPROTO_UDP
304 #define LINK_TCP IPPROTO_TCP
305 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
306 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
307 #define LINK_ADDR (IPPROTO_MAX + 3)
308 #define LINK_PPTP (IPPROTO_MAX + 4)
310 int flags; /* indicates special characteristics */
311 int pflags; /* protocol-specific flags */
314 #define LINK_UNKNOWN_DEST_PORT 0x01
315 #define LINK_UNKNOWN_DEST_ADDR 0x02
316 #define LINK_PERMANENT 0x04
317 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
318 #define LINK_UNFIREWALLED 0x08
320 int timestamp; /* Time link was last accessed */
321 int expire_time; /* Expire time for link */
322 #ifndef NO_USE_SOCKETS
323 int sockfd; /* socket descriptor */
325 LIST_ENTRY (alias_link) list_out; /* Linked list of
327 LIST_ENTRY (alias_link) list_in; /* input and output
330 union { /* Auxiliary data */
332 struct in_addr frag_addr;
337 /* Clean up procedure. */
338 static void finishoff(void);
340 /* Kernel module definition. */
342 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
344 MODULE_VERSION(libalias, 1);
347 alias_mod_handler(module_t mod, int type, void *data)
361 static moduledata_t alias_mod = {
362 "alias", alias_mod_handler, NULL
365 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
368 /* Internal utility routines (used only in alias_db.c)
370 Lookup table starting points:
371 StartPointIn() -- link table initial search point for
373 StartPointOut() -- link table initial search point for
377 SeqDiff() -- difference between two TCP sequences
378 ShowAliasStats() -- send alias statistics to a monitor file
381 /* Local prototypes */
382 static u_int StartPointIn(struct in_addr, u_short, int);
385 StartPointOut(struct in_addr, struct in_addr,
386 u_short, u_short, int);
388 static int SeqDiff(u_long, u_long);
391 /* Firewall control */
392 static void InitPunchFW(struct libalias *);
393 static void UninitPunchFW(struct libalias *);
394 static void ClearFWHole(struct alias_link *);
398 /* Log file control */
399 static void ShowAliasStats(struct libalias *);
400 static int InitPacketAliasLog(struct libalias *);
401 static void UninitPacketAliasLog(struct libalias *);
403 void SctpShowAliasStats(struct libalias *la);
406 StartPointIn(struct in_addr alias_addr,
412 n = alias_addr.s_addr;
413 if (link_type != LINK_PPTP)
416 return (n % LINK_TABLE_IN_SIZE);
420 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
421 u_short src_port, u_short dst_port, int link_type)
426 n += dst_addr.s_addr;
427 if (link_type != LINK_PPTP) {
433 return (n % LINK_TABLE_OUT_SIZE);
437 SeqDiff(u_long x, u_long y)
439 /* Return the difference between two TCP sequence numbers */
442 This function is encapsulated in case there are any unusual
443 arithmetic conditions that need to be considered.
446 return (ntohl(y) - ntohl(x));
452 AliasLog(char *str, const char *format, ...)
456 va_start(ap, format);
457 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
462 AliasLog(FILE *stream, const char *format, ...)
466 va_start(ap, format);
467 vfprintf(stream, format, ap);
474 ShowAliasStats(struct libalias *la)
477 LIBALIAS_LOCK_ASSERT(la);
478 /* Used for debugging */
480 int tot = la->icmpLinkCount + la->udpLinkCount +
481 (la->sctpLinkCount>>1) + /* sctp counts half associations */
482 la->tcpLinkCount + la->pptpLinkCount +
483 la->protoLinkCount + la->fragmentIdLinkCount +
484 la->fragmentPtrLinkCount;
486 AliasLog(la->logDesc,
487 "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
491 la->sctpLinkCount>>1, /* sctp counts half associations */
494 la->fragmentIdLinkCount,
495 la->fragmentPtrLinkCount, tot);
497 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
502 void SctpShowAliasStats(struct libalias *la)
508 /* Internal routines for finding, deleting and adding links
511 GetNewPort() -- find and reserve new alias port number
512 GetSocket() -- try to allocate a socket for a given port
514 Link creation and deletion:
515 CleanupAliasData() - remove all link chains from lookup table
516 IncrementalCleanup() - look for stale links in a single chain
517 DeleteLink() - remove link
519 ReLink() - change link
522 FindLinkOut() - find link for outgoing packets
523 FindLinkIn() - find link for incoming packets
526 FindNewPortGroup() - find an available group of ports
529 /* Local prototypes */
530 static int GetNewPort(struct libalias *, struct alias_link *, int);
531 #ifndef NO_USE_SOCKETS
532 static u_short GetSocket(struct libalias *, u_short, int *, int);
534 static void CleanupAliasData(struct libalias *);
536 static void IncrementalCleanup(struct libalias *);
538 static void DeleteLink(struct alias_link *);
540 static struct alias_link *
541 ReLink(struct alias_link *,
542 struct in_addr, struct in_addr, struct in_addr,
543 u_short, u_short, int, int);
545 static struct alias_link *
546 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
548 static struct alias_link *
549 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
551 #define ALIAS_PORT_BASE 0x08000
552 #define ALIAS_PORT_MASK 0x07fff
553 #define ALIAS_PORT_MASK_EVEN 0x07ffe
554 #define GET_NEW_PORT_MAX_ATTEMPTS 20
556 #define FIND_EVEN_ALIAS_BASE 1
558 /* GetNewPort() allocates port numbers. Note that if a port number
559 is already in use, that does not mean that it cannot be used by
560 another link concurrently. This is because GetNewPort() looks for
561 unused triplets: (dest addr, dest port, alias port). */
564 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
571 LIBALIAS_LOCK_ASSERT(la);
573 Description of alias_port_param for GetNewPort(). When
574 this parameter is zero or positive, it precisely specifies
575 the port number. GetNewPort() will return this number
576 without check that it is in use.
578 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
579 selected port number.
582 if (alias_port_param == GET_ALIAS_PORT) {
584 * The aliasing port is automatically selected by one of
587 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
589 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
591 * When the PKT_ALIAS_SAME_PORTS option is chosen,
592 * the first try will be the actual source port. If
593 * this is already in use, the remainder of the
594 * trials will be random.
596 port_net = lnk->src_port;
597 port_sys = ntohs(port_net);
598 } else if (la->aliasPortLower) {
599 /* First trial is a random port in the aliasing range. */
600 port_sys = la->aliasPortLower +
601 (arc4random() % la->aliasPortLength);
602 port_net = htons(port_sys);
604 /* First trial and all subsequent are random. */
605 port_sys = arc4random() & ALIAS_PORT_MASK;
606 port_sys += ALIAS_PORT_BASE;
607 port_net = htons(port_sys);
609 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
610 lnk->alias_port = (u_short) alias_port_param;
613 #ifdef LIBALIAS_DEBUG
614 fprintf(stderr, "PacketAlias/GetNewPort(): ");
615 fprintf(stderr, "input parameter error\n");
620 /* Port number search */
621 for (i = 0; i < max_trials; i++) {
623 struct alias_link *search_result;
625 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
626 lnk->dst_port, port_net,
629 if (search_result == NULL)
631 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
632 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
638 #ifndef NO_USE_SOCKETS
639 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
640 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
641 && ((lnk->link_type == LINK_TCP) ||
642 (lnk->link_type == LINK_UDP))) {
643 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
644 lnk->alias_port = port_net;
649 lnk->alias_port = port_net;
651 #ifndef NO_USE_SOCKETS
655 if (la->aliasPortLower) {
656 port_sys = la->aliasPortLower +
657 (arc4random() % la->aliasPortLength);
658 port_net = htons(port_sys);
660 port_sys = arc4random() & ALIAS_PORT_MASK;
661 port_sys += ALIAS_PORT_BASE;
662 port_net = htons(port_sys);
666 #ifdef LIBALIAS_DEBUG
667 fprintf(stderr, "PacketAlias/GetNewPort(): ");
668 fprintf(stderr, "could not find free port\n");
674 #ifndef NO_USE_SOCKETS
676 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
680 struct sockaddr_in sock_addr;
682 LIBALIAS_LOCK_ASSERT(la);
683 if (link_type == LINK_TCP)
684 sock = socket(AF_INET, SOCK_STREAM, 0);
685 else if (link_type == LINK_UDP)
686 sock = socket(AF_INET, SOCK_DGRAM, 0);
688 #ifdef LIBALIAS_DEBUG
689 fprintf(stderr, "PacketAlias/GetSocket(): ");
690 fprintf(stderr, "incorrect link type\n");
696 #ifdef LIBALIAS_DEBUG
697 fprintf(stderr, "PacketAlias/GetSocket(): ");
698 fprintf(stderr, "socket() error %d\n", *sockfd);
702 sock_addr.sin_family = AF_INET;
703 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
704 sock_addr.sin_port = port_net;
707 (struct sockaddr *)&sock_addr,
720 /* FindNewPortGroup() returns a base port number for an available
721 range of contiguous port numbers. Note that if a port number
722 is already in use, that does not mean that it cannot be used by
723 another link concurrently. This is because FindNewPortGroup()
724 looks for unused triplets: (dest addr, dest port, alias port). */
727 FindNewPortGroup(struct libalias *la,
728 struct in_addr dst_addr,
729 struct in_addr alias_addr,
741 LIBALIAS_LOCK_ASSERT(la);
743 * Get link_type from protocol
748 link_type = LINK_UDP;
751 link_type = LINK_TCP;
759 * The aliasing port is automatically selected by one of two
762 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
764 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
766 * When the ALIAS_SAME_PORTS option is chosen, the first
767 * try will be the actual source port. If this is already
768 * in use, the remainder of the trials will be random.
770 port_sys = ntohs(src_port);
773 /* First trial and all subsequent are random. */
774 if (align == FIND_EVEN_ALIAS_BASE)
775 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
777 port_sys = arc4random() & ALIAS_PORT_MASK;
779 port_sys += ALIAS_PORT_BASE;
782 /* Port number search */
783 for (i = 0; i < max_trials; i++) {
784 struct alias_link *search_result;
786 for (j = 0; j < port_count; j++)
787 if ((search_result = FindLinkIn(la, dst_addr,
788 alias_addr, dst_port, htons(port_sys + j),
789 link_type, 0)) != NULL)
792 /* Found a good range, return base */
794 return (htons(port_sys));
796 /* Find a new base to try */
797 if (align == FIND_EVEN_ALIAS_BASE)
798 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
800 port_sys = arc4random() & ALIAS_PORT_MASK;
802 port_sys += ALIAS_PORT_BASE;
805 #ifdef LIBALIAS_DEBUG
806 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
807 fprintf(stderr, "could not find free port(s)\n");
814 CleanupAliasData(struct libalias *la)
816 struct alias_link *lnk;
819 LIBALIAS_LOCK_ASSERT(la);
820 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
821 lnk = LIST_FIRST(&la->linkTableOut[i]);
822 while (lnk != NULL) {
823 struct alias_link *link_next = LIST_NEXT(lnk, list_out);
829 la->cleanupIndex = 0;
833 IncrementalCleanup(struct libalias *la)
835 struct alias_link *lnk, *lnk_tmp;
837 LIBALIAS_LOCK_ASSERT(la);
838 LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
840 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
844 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
845 la->cleanupIndex = 0;
849 DeleteLink(struct alias_link *lnk)
851 struct libalias *la = lnk->la;
853 LIBALIAS_LOCK_ASSERT(la);
854 /* Don't do anything if the link is marked permanent */
855 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
859 /* Delete associated firewall hole, if any */
863 /* Free memory allocated for LSNAT server pool */
864 if (lnk->server != NULL) {
865 struct server *head, *curr, *next;
867 head = curr = lnk->server;
871 } while ((curr = next) != head);
873 /* Adjust output table pointers */
874 LIST_REMOVE(lnk, list_out);
876 /* Adjust input table pointers */
877 LIST_REMOVE(lnk, list_in);
878 #ifndef NO_USE_SOCKETS
879 /* Close socket, if one has been allocated */
880 if (lnk->sockfd != -1) {
885 /* Link-type dependent cleanup */
886 switch (lnk->link_type) {
900 case LINK_FRAGMENT_ID:
901 la->fragmentIdLinkCount--;
903 case LINK_FRAGMENT_PTR:
904 la->fragmentPtrLinkCount--;
905 if (lnk->data.frag_ptr != NULL)
906 free(lnk->data.frag_ptr);
911 la->protoLinkCount--;
918 /* Write statistics, if logging enabled */
919 if (la->packetAliasMode & PKT_ALIAS_LOG) {
925 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
926 struct in_addr alias_addr, u_short src_port, u_short dst_port,
927 int alias_port_param, int link_type)
930 struct alias_link *lnk;
932 LIBALIAS_LOCK_ASSERT(la);
933 lnk = malloc(sizeof(struct alias_link));
935 /* Basic initialization */
937 lnk->src_addr = src_addr;
938 lnk->dst_addr = dst_addr;
939 lnk->alias_addr = alias_addr;
940 lnk->proxy_addr.s_addr = INADDR_ANY;
941 lnk->src_port = src_port;
942 lnk->dst_port = dst_port;
945 lnk->link_type = link_type;
946 #ifndef NO_USE_SOCKETS
951 lnk->timestamp = la->timeStamp;
953 /* Expiration time */
956 lnk->expire_time = ICMP_EXPIRE_TIME;
959 lnk->expire_time = UDP_EXPIRE_TIME;
962 lnk->expire_time = TCP_EXPIRE_INITIAL;
965 lnk->flags |= LINK_PERMANENT; /* no timeout. */
967 case LINK_FRAGMENT_ID:
968 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
970 case LINK_FRAGMENT_PTR:
971 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
976 lnk->expire_time = PROTO_EXPIRE_TIME;
980 /* Determine alias flags */
981 if (dst_addr.s_addr == INADDR_ANY)
982 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
984 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
986 /* Determine alias port */
987 if (GetNewPort(la, lnk, alias_port_param) != 0) {
991 /* Link-type dependent initialization */
993 struct tcp_dat *aux_tcp;
1002 aux_tcp = malloc(sizeof(struct tcp_dat));
1003 if (aux_tcp != NULL) {
1007 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1008 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1009 aux_tcp->state.index = 0;
1010 aux_tcp->state.ack_modified = 0;
1011 for (i = 0; i < N_LINK_TCP_DATA; i++)
1012 aux_tcp->ack[i].active = 0;
1013 aux_tcp->fwhole = -1;
1014 lnk->data.tcp = aux_tcp;
1016 #ifdef LIBALIAS_DEBUG
1017 fprintf(stderr, "PacketAlias/AddLink: ");
1018 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1025 la->pptpLinkCount++;
1027 case LINK_FRAGMENT_ID:
1028 la->fragmentIdLinkCount++;
1030 case LINK_FRAGMENT_PTR:
1031 la->fragmentPtrLinkCount++;
1036 la->protoLinkCount++;
1040 /* Set up pointers for output lookup table */
1041 start_point = StartPointOut(src_addr, dst_addr,
1042 src_port, dst_port, link_type);
1043 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1045 /* Set up pointers for input lookup table */
1046 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1047 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1049 #ifdef LIBALIAS_DEBUG
1050 fprintf(stderr, "PacketAlias/AddLink(): ");
1051 fprintf(stderr, "malloc() call failed.\n");
1054 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1060 static struct alias_link *
1061 ReLink(struct alias_link *old_lnk,
1062 struct in_addr src_addr,
1063 struct in_addr dst_addr,
1064 struct in_addr alias_addr,
1067 int alias_port_param, /* if less than zero, alias */
1069 { /* port will be automatically *//* chosen.
1070 * If greater than */
1071 struct alias_link *new_lnk; /* zero, equal to alias port */
1072 struct libalias *la = old_lnk->la;
1074 LIBALIAS_LOCK_ASSERT(la);
1075 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1076 src_port, dst_port, alias_port_param,
1079 if (new_lnk != NULL &&
1080 old_lnk->link_type == LINK_TCP &&
1081 old_lnk->data.tcp->fwhole > 0) {
1082 PunchFWHole(new_lnk);
1085 DeleteLink(old_lnk);
1089 static struct alias_link *
1090 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1091 struct in_addr dst_addr,
1095 int replace_partial_links)
1098 struct alias_link *lnk;
1100 LIBALIAS_LOCK_ASSERT(la);
1101 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1102 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1103 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1104 lnk->src_addr.s_addr == src_addr.s_addr &&
1105 lnk->src_port == src_port &&
1106 lnk->dst_port == dst_port &&
1107 lnk->link_type == link_type &&
1108 lnk->server == NULL) {
1109 lnk->timestamp = la->timeStamp;
1114 /* Search for partially specified links. */
1115 if (lnk == NULL && replace_partial_links) {
1116 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1117 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1120 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1121 dst_port, link_type, 0);
1124 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1125 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1130 src_addr, dst_addr, lnk->alias_addr,
1131 src_port, dst_port, lnk->alias_port,
1138 static struct alias_link *
1139 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1140 struct in_addr dst_addr,
1144 int replace_partial_links)
1146 struct alias_link *lnk;
1148 LIBALIAS_LOCK_ASSERT(la);
1149 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1150 link_type, replace_partial_links);
1154 * The following allows permanent links to be specified as
1155 * using the default source address (i.e. device interface
1156 * address) without knowing in advance what that address
1159 if (la->aliasAddress.s_addr != INADDR_ANY &&
1160 src_addr.s_addr == la->aliasAddress.s_addr) {
1161 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1162 link_type, replace_partial_links);
1168 static struct alias_link *
1169 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1170 struct in_addr alias_addr,
1174 int replace_partial_links)
1178 struct alias_link *lnk;
1179 struct alias_link *lnk_fully_specified;
1180 struct alias_link *lnk_unknown_all;
1181 struct alias_link *lnk_unknown_dst_addr;
1182 struct alias_link *lnk_unknown_dst_port;
1184 LIBALIAS_LOCK_ASSERT(la);
1185 /* Initialize pointers */
1186 lnk_fully_specified = NULL;
1187 lnk_unknown_all = NULL;
1188 lnk_unknown_dst_addr = NULL;
1189 lnk_unknown_dst_port = NULL;
1191 /* If either the dest addr or port is unknown, the search
1192 loop will have to know about this. */
1195 if (dst_addr.s_addr == INADDR_ANY)
1196 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1198 flags_in |= LINK_UNKNOWN_DEST_PORT;
1201 start_point = StartPointIn(alias_addr, alias_port, link_type);
1202 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1205 flags = flags_in | lnk->flags;
1206 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1207 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1208 && lnk->alias_port == alias_port
1209 && lnk->dst_addr.s_addr == dst_addr.s_addr
1210 && lnk->dst_port == dst_port
1211 && lnk->link_type == link_type) {
1212 lnk_fully_specified = lnk;
1215 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1216 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1217 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1218 && lnk->alias_port == alias_port
1219 && lnk->link_type == link_type) {
1220 if (lnk_unknown_all == NULL)
1221 lnk_unknown_all = lnk;
1223 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1224 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1225 && lnk->alias_port == alias_port
1226 && lnk->link_type == link_type
1227 && lnk->dst_port == dst_port) {
1228 if (lnk_unknown_dst_addr == NULL)
1229 lnk_unknown_dst_addr = lnk;
1231 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1232 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1233 && lnk->alias_port == alias_port
1234 && lnk->link_type == link_type
1235 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1236 if (lnk_unknown_dst_port == NULL)
1237 lnk_unknown_dst_port = lnk;
1242 if (lnk_fully_specified != NULL) {
1243 lnk_fully_specified->timestamp = la->timeStamp;
1244 lnk = lnk_fully_specified;
1245 } else if (lnk_unknown_dst_port != NULL)
1246 lnk = lnk_unknown_dst_port;
1247 else if (lnk_unknown_dst_addr != NULL)
1248 lnk = lnk_unknown_dst_addr;
1249 else if (lnk_unknown_all != NULL)
1250 lnk = lnk_unknown_all;
1254 if (replace_partial_links &&
1255 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1256 struct in_addr src_addr;
1259 if (lnk->server != NULL) { /* LSNAT link */
1260 src_addr = lnk->server->addr;
1261 src_port = lnk->server->port;
1262 lnk->server = lnk->server->next;
1264 src_addr = lnk->src_addr;
1265 src_port = lnk->src_port;
1268 if (link_type == LINK_SCTP) {
1269 lnk->src_addr = src_addr;
1270 lnk->src_port = src_port;
1274 src_addr, dst_addr, alias_addr,
1275 src_port, dst_port, alias_port,
1281 static struct alias_link *
1282 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1283 struct in_addr alias_addr,
1287 int replace_partial_links)
1289 struct alias_link *lnk;
1291 LIBALIAS_LOCK_ASSERT(la);
1292 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1293 link_type, replace_partial_links);
1297 * The following allows permanent links to be specified as
1298 * using the default aliasing address (i.e. device
1299 * interface address) without knowing in advance what that
1302 if (la->aliasAddress.s_addr != INADDR_ANY &&
1303 alias_addr.s_addr == la->aliasAddress.s_addr) {
1304 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1305 link_type, replace_partial_links);
1311 /* External routines for finding/adding links
1313 -- "external" means outside alias_db.c, but within alias*.c --
1315 FindIcmpIn(), FindIcmpOut()
1316 FindFragmentIn1(), FindFragmentIn2()
1317 AddFragmentPtrLink(), FindFragmentPtr()
1318 FindProtoIn(), FindProtoOut()
1319 FindUdpTcpIn(), FindUdpTcpOut()
1320 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1321 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1322 FindOriginalAddress(), FindAliasAddress()
1324 (prototypes in alias_local.h)
1328 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1329 struct in_addr alias_addr,
1333 struct alias_link *lnk;
1335 LIBALIAS_LOCK_ASSERT(la);
1336 lnk = FindLinkIn(la, dst_addr, alias_addr,
1337 NO_DEST_PORT, id_alias,
1339 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1340 struct in_addr target_addr;
1342 target_addr = FindOriginalAddress(la, alias_addr);
1343 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1344 id_alias, NO_DEST_PORT, id_alias,
1351 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1352 struct in_addr dst_addr,
1356 struct alias_link *lnk;
1358 LIBALIAS_LOCK_ASSERT(la);
1359 lnk = FindLinkOut(la, src_addr, dst_addr,
1362 if (lnk == NULL && create) {
1363 struct in_addr alias_addr;
1365 alias_addr = FindAliasAddress(la, src_addr);
1366 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1367 id, NO_DEST_PORT, GET_ALIAS_ID,
1374 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1375 struct in_addr alias_addr,
1378 struct alias_link *lnk;
1380 LIBALIAS_LOCK_ASSERT(la);
1381 lnk = FindLinkIn(la, dst_addr, alias_addr,
1382 NO_DEST_PORT, ip_id,
1383 LINK_FRAGMENT_ID, 0);
1386 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1387 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1394 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1396 struct in_addr alias_addr, /* is not found. */
1400 LIBALIAS_LOCK_ASSERT(la);
1401 return FindLinkIn(la, dst_addr, alias_addr,
1402 NO_DEST_PORT, ip_id,
1403 LINK_FRAGMENT_ID, 0);
1407 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1411 LIBALIAS_LOCK_ASSERT(la);
1412 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1413 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1418 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1422 LIBALIAS_LOCK_ASSERT(la);
1423 return FindLinkIn(la, dst_addr, la->nullAddress,
1424 NO_DEST_PORT, ip_id,
1425 LINK_FRAGMENT_PTR, 0);
1429 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1430 struct in_addr alias_addr,
1433 struct alias_link *lnk;
1435 LIBALIAS_LOCK_ASSERT(la);
1436 lnk = FindLinkIn(la, dst_addr, alias_addr,
1440 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1441 struct in_addr target_addr;
1443 target_addr = FindOriginalAddress(la, alias_addr);
1444 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1445 NO_SRC_PORT, NO_DEST_PORT, 0,
1452 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1453 struct in_addr dst_addr,
1456 struct alias_link *lnk;
1458 LIBALIAS_LOCK_ASSERT(la);
1459 lnk = FindLinkOut(la, src_addr, dst_addr,
1460 NO_SRC_PORT, NO_DEST_PORT,
1464 struct in_addr alias_addr;
1466 alias_addr = FindAliasAddress(la, src_addr);
1467 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1468 NO_SRC_PORT, NO_DEST_PORT, 0,
1475 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1476 struct in_addr alias_addr,
1483 struct alias_link *lnk;
1485 LIBALIAS_LOCK_ASSERT(la);
1488 link_type = LINK_UDP;
1491 link_type = LINK_TCP;
1498 lnk = FindLinkIn(la, dst_addr, alias_addr,
1499 dst_port, alias_port,
1502 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1503 struct in_addr target_addr;
1505 target_addr = FindOriginalAddress(la, alias_addr);
1506 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1507 alias_port, dst_port, alias_port,
1514 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1515 struct in_addr dst_addr,
1522 struct alias_link *lnk;
1524 LIBALIAS_LOCK_ASSERT(la);
1527 link_type = LINK_UDP;
1530 link_type = LINK_TCP;
1537 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1539 if (lnk == NULL && create) {
1540 struct in_addr alias_addr;
1542 alias_addr = FindAliasAddress(la, src_addr);
1543 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1544 src_port, dst_port, GET_ALIAS_PORT,
1551 AddPptp(struct libalias *la, struct in_addr src_addr,
1552 struct in_addr dst_addr,
1553 struct in_addr alias_addr,
1554 u_int16_t src_call_id)
1556 struct alias_link *lnk;
1558 LIBALIAS_LOCK_ASSERT(la);
1559 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1560 src_call_id, 0, GET_ALIAS_PORT,
1567 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1568 struct in_addr dst_addr,
1569 u_int16_t src_call_id)
1572 struct alias_link *lnk;
1574 LIBALIAS_LOCK_ASSERT(la);
1575 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1576 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1577 if (lnk->link_type == LINK_PPTP &&
1578 lnk->src_addr.s_addr == src_addr.s_addr &&
1579 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1580 lnk->src_port == src_call_id)
1587 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1588 struct in_addr dst_addr,
1589 u_int16_t dst_call_id)
1592 struct alias_link *lnk;
1594 LIBALIAS_LOCK_ASSERT(la);
1595 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1596 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1597 if (lnk->link_type == LINK_PPTP &&
1598 lnk->src_addr.s_addr == src_addr.s_addr &&
1599 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1600 lnk->dst_port == dst_call_id)
1607 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1608 struct in_addr alias_addr,
1609 u_int16_t dst_call_id)
1612 struct alias_link *lnk;
1614 LIBALIAS_LOCK_ASSERT(la);
1615 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1616 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1617 if (lnk->link_type == LINK_PPTP &&
1618 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1619 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1620 lnk->dst_port == dst_call_id)
1627 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1628 struct in_addr alias_addr,
1629 u_int16_t alias_call_id)
1631 struct alias_link *lnk;
1633 LIBALIAS_LOCK_ASSERT(la);
1634 lnk = FindLinkIn(la, dst_addr, alias_addr,
1635 0 /* any */ , alias_call_id,
1642 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1643 struct in_addr dst_addr,
1649 struct alias_link *lnk;
1651 LIBALIAS_LOCK_ASSERT(la);
1654 link_type = LINK_UDP;
1657 link_type = LINK_TCP;
1664 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1667 struct in_addr alias_addr;
1669 alias_addr = FindAliasAddress(la, src_addr);
1670 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1671 src_port, 0, alias_port,
1678 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1680 struct alias_link *lnk;
1682 LIBALIAS_LOCK_ASSERT(la);
1683 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1684 0, 0, LINK_ADDR, 0);
1686 la->newDefaultLink = 1;
1687 if (la->targetAddress.s_addr == INADDR_ANY)
1688 return (alias_addr);
1689 else if (la->targetAddress.s_addr == INADDR_NONE)
1690 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1691 la->aliasAddress : alias_addr;
1693 return (la->targetAddress);
1695 if (lnk->server != NULL) { /* LSNAT link */
1696 struct in_addr src_addr;
1698 src_addr = lnk->server->addr;
1699 lnk->server = lnk->server->next;
1701 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1702 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1703 la->aliasAddress : alias_addr;
1705 return (lnk->src_addr);
1710 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1712 struct alias_link *lnk;
1714 LIBALIAS_LOCK_ASSERT(la);
1715 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1716 0, 0, LINK_ADDR, 0);
1718 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1719 la->aliasAddress : original_addr;
1721 if (lnk->alias_addr.s_addr == INADDR_ANY)
1722 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1723 la->aliasAddress : original_addr;
1725 return (lnk->alias_addr);
1729 /* External routines for getting or changing link data
1730 (external to alias_db.c, but internal to alias*.c)
1732 SetFragmentData(), GetFragmentData()
1733 SetFragmentPtr(), GetFragmentPtr()
1734 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1735 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1736 GetOriginalPort(), GetAliasPort()
1737 SetAckModified(), GetAckModified()
1738 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1739 SetProtocolFlags(), GetProtocolFlags()
1744 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1746 lnk->data.frag_addr = src_addr;
1750 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1752 *src_addr = lnk->data.frag_addr;
1756 SetFragmentPtr(struct alias_link *lnk, void *fptr)
1758 lnk->data.frag_ptr = fptr;
1762 GetFragmentPtr(struct alias_link *lnk, void **fptr)
1764 *fptr = lnk->data.frag_ptr;
1768 SetStateIn(struct alias_link *lnk, int state)
1770 /* TCP input state */
1772 case ALIAS_TCP_STATE_DISCONNECTED:
1773 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1774 lnk->expire_time = TCP_EXPIRE_DEAD;
1776 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1778 case ALIAS_TCP_STATE_CONNECTED:
1779 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1780 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1784 panic("libalias:SetStateIn() unknown state");
1789 lnk->data.tcp->state.in = state;
1793 SetStateOut(struct alias_link *lnk, int state)
1795 /* TCP output state */
1797 case ALIAS_TCP_STATE_DISCONNECTED:
1798 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1799 lnk->expire_time = TCP_EXPIRE_DEAD;
1801 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1803 case ALIAS_TCP_STATE_CONNECTED:
1804 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1805 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1809 panic("libalias:SetStateOut() unknown state");
1814 lnk->data.tcp->state.out = state;
1818 GetStateIn(struct alias_link *lnk)
1820 /* TCP input state */
1821 return (lnk->data.tcp->state.in);
1825 GetStateOut(struct alias_link *lnk)
1827 /* TCP output state */
1828 return (lnk->data.tcp->state.out);
1832 GetOriginalAddress(struct alias_link *lnk)
1834 if (lnk->src_addr.s_addr == INADDR_ANY)
1835 return (lnk->la->aliasAddress);
1837 return (lnk->src_addr);
1841 GetDestAddress(struct alias_link *lnk)
1843 return (lnk->dst_addr);
1847 GetAliasAddress(struct alias_link *lnk)
1849 if (lnk->alias_addr.s_addr == INADDR_ANY)
1850 return (lnk->la->aliasAddress);
1852 return (lnk->alias_addr);
1856 GetDefaultAliasAddress(struct libalias *la)
1859 LIBALIAS_LOCK_ASSERT(la);
1860 return (la->aliasAddress);
1864 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1867 LIBALIAS_LOCK_ASSERT(la);
1868 la->aliasAddress = alias_addr;
1872 GetOriginalPort(struct alias_link *lnk)
1874 return (lnk->src_port);
1878 GetAliasPort(struct alias_link *lnk)
1880 return (lnk->alias_port);
1885 GetDestPort(struct alias_link *lnk)
1887 return (lnk->dst_port);
1893 SetAckModified(struct alias_link *lnk)
1895 /* Indicate that ACK numbers have been modified in a TCP connection */
1896 lnk->data.tcp->state.ack_modified = 1;
1900 GetProxyAddress(struct alias_link *lnk)
1902 return (lnk->proxy_addr);
1906 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1908 lnk->proxy_addr = addr;
1912 GetProxyPort(struct alias_link *lnk)
1914 return (lnk->proxy_port);
1918 SetProxyPort(struct alias_link *lnk, u_short port)
1920 lnk->proxy_port = port;
1924 GetAckModified(struct alias_link *lnk)
1926 /* See if ACK numbers have been modified */
1927 return (lnk->data.tcp->state.ack_modified);
1932 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1935 Find out how much the ACK number has been altered for an incoming
1936 TCP packet. To do this, a circular list of ACK numbers where the TCP
1937 packet size was altered is searched.
1941 int delta, ack_diff_min;
1945 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1946 struct ack_data_record x;
1948 x = lnk->data.tcp->ack[i];
1949 if (x.active == 1) {
1952 ack_diff = SeqDiff(x.ack_new, ack);
1953 if (ack_diff >= 0) {
1954 if (ack_diff_min >= 0) {
1955 if (ack_diff < ack_diff_min) {
1957 ack_diff_min = ack_diff;
1961 ack_diff_min = ack_diff;
1971 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
1974 Find out how much the sequence number has been altered for an outgoing
1975 TCP packet. To do this, a circular list of ACK numbers where the TCP
1976 packet size was altered is searched.
1980 int delta, seq_diff_min;
1984 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1985 struct ack_data_record x;
1987 x = lnk->data.tcp->ack[i];
1988 if (x.active == 1) {
1991 seq_diff = SeqDiff(x.ack_old, seq);
1992 if (seq_diff >= 0) {
1993 if (seq_diff_min >= 0) {
1994 if (seq_diff < seq_diff_min) {
1996 seq_diff_min = seq_diff;
2000 seq_diff_min = seq_diff;
2010 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
2011 u_long th_seq, u_int th_off)
2014 When a TCP packet has been altered in length, save this
2015 information in a circular list. If enough packets have
2016 been altered, then this list will begin to overwrite itself.
2019 struct ack_data_record x;
2020 int hlen, tlen, dlen;
2023 hlen = (ip_hl + th_off) << 2;
2024 tlen = ntohs(ip_len);
2027 x.ack_old = htonl(ntohl(th_seq) + dlen);
2028 x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
2032 i = lnk->data.tcp->state.index;
2033 lnk->data.tcp->ack[i] = x;
2036 if (i == N_LINK_TCP_DATA)
2037 lnk->data.tcp->state.index = 0;
2039 lnk->data.tcp->state.index = i;
2043 SetExpire(struct alias_link *lnk, int expire)
2046 lnk->flags &= ~LINK_PERMANENT;
2048 } else if (expire == -1) {
2049 lnk->flags |= LINK_PERMANENT;
2050 } else if (expire > 0) {
2051 lnk->expire_time = expire;
2053 #ifdef LIBALIAS_DEBUG
2054 fprintf(stderr, "PacketAlias/SetExpire(): ");
2055 fprintf(stderr, "error in expire parameter\n");
2061 ClearCheckNewLink(struct libalias *la)
2064 LIBALIAS_LOCK_ASSERT(la);
2065 la->newDefaultLink = 0;
2069 SetProtocolFlags(struct alias_link *lnk, int pflags)
2072 lnk->pflags = pflags;
2076 GetProtocolFlags(struct alias_link *lnk)
2079 return (lnk->pflags);
2083 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2085 struct libalias *la = lnk->la;
2087 LIBALIAS_LOCK_ASSERT(la);
2088 la->deleteAllLinks = 1;
2089 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2090 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2091 la->deleteAllLinks = 0;
2094 /* Miscellaneous Functions
2097 InitPacketAliasLog()
2098 UninitPacketAliasLog()
2102 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2103 is called to find and remove timed-out aliasing links. Logic exists
2104 to sweep through the entire table and linked list structure
2107 (prototype in alias_local.h)
2111 HouseKeeping(struct libalias *la)
2118 LIBALIAS_LOCK_ASSERT(la);
2120 * Save system time (seconds) in global variable timeStamp for use
2121 * by other functions. This is done so as not to unnecessarily
2122 * waste timeline by making system calls.
2125 la->timeStamp = time_uptime;
2127 gettimeofday(&tv, NULL);
2128 la->timeStamp = tv.tv_sec;
2131 /* Compute number of spokes (output table link chains) to cover */
2132 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2133 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2135 /* Handle different cases */
2137 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2138 n = ALIAS_CLEANUP_MAX_SPOKES;
2139 la->lastCleanupTime = la->timeStamp;
2140 for (i = 0; i < n; i++)
2141 IncrementalCleanup(la);
2143 #ifdef LIBALIAS_DEBUG
2144 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2145 fprintf(stderr, "something unexpected in time values\n");
2147 la->lastCleanupTime = la->timeStamp;
2151 /* Init the log file and enable logging */
2153 InitPacketAliasLog(struct libalias *la)
2156 LIBALIAS_LOCK_ASSERT(la);
2157 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2159 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2162 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2163 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2166 return (ENOMEM); /* log initialization failed */
2167 la->packetAliasMode |= PKT_ALIAS_LOG;
2173 /* Close the log-file and disable logging. */
2175 UninitPacketAliasLog(struct libalias *la)
2178 LIBALIAS_LOCK_ASSERT(la);
2183 fclose(la->logDesc);
2187 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2190 /* Outside world interfaces
2192 -- "outside world" means other than alias*.c routines --
2194 PacketAliasRedirectPort()
2195 PacketAliasAddServer()
2196 PacketAliasRedirectProto()
2197 PacketAliasRedirectAddr()
2198 PacketAliasRedirectDynamic()
2199 PacketAliasRedirectDelete()
2200 PacketAliasSetAddress()
2203 PacketAliasSetMode()
2205 (prototypes in alias.h)
2208 /* Redirection from a specific public addr:port to a
2209 private addr:port */
2211 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2212 struct in_addr dst_addr, u_short dst_port,
2213 struct in_addr alias_addr, u_short alias_port,
2217 struct alias_link *lnk;
2222 link_type = LINK_UDP;
2225 link_type = LINK_TCP;
2228 link_type = LINK_SCTP;
2231 #ifdef LIBALIAS_DEBUG
2232 fprintf(stderr, "PacketAliasRedirectPort(): ");
2233 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
2239 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2240 src_port, dst_port, alias_port,
2244 lnk->flags |= LINK_PERMANENT;
2246 #ifdef LIBALIAS_DEBUG
2248 fprintf(stderr, "PacketAliasRedirectPort(): "
2249 "call to AddLink() failed\n");
2254 LIBALIAS_UNLOCK(la);
2258 /* Add server to the pool of servers */
2260 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2262 struct server *server;
2268 server = malloc(sizeof(struct server));
2270 if (server != NULL) {
2271 struct server *head;
2273 server->addr = addr;
2274 server->port = port;
2278 server->next = server;
2282 for (s = head; s->next != head; s = s->next);
2284 server->next = head;
2286 lnk->server = server;
2291 LIBALIAS_UNLOCK(la);
2295 /* Redirect packets of a given IP protocol from a specific
2296 public address to a private address */
2298 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2299 struct in_addr dst_addr,
2300 struct in_addr alias_addr,
2303 struct alias_link *lnk;
2306 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2307 NO_SRC_PORT, NO_DEST_PORT, 0,
2311 lnk->flags |= LINK_PERMANENT;
2313 #ifdef LIBALIAS_DEBUG
2315 fprintf(stderr, "PacketAliasRedirectProto(): "
2316 "call to AddLink() failed\n");
2320 LIBALIAS_UNLOCK(la);
2324 /* Static address translation */
2326 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2327 struct in_addr alias_addr)
2329 struct alias_link *lnk;
2332 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2337 lnk->flags |= LINK_PERMANENT;
2339 #ifdef LIBALIAS_DEBUG
2341 fprintf(stderr, "PacketAliasRedirectAddr(): "
2342 "call to AddLink() failed\n");
2346 LIBALIAS_UNLOCK(la);
2350 /* Mark the aliasing link dynamic */
2352 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2359 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2362 lnk->flags &= ~LINK_PERMANENT;
2365 LIBALIAS_UNLOCK(la);
2370 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2372 /* This is a dangerous function to put in the API,
2373 because an invalid pointer can crash the program. */
2376 la->deleteAllLinks = 1;
2378 la->deleteAllLinks = 0;
2379 LIBALIAS_UNLOCK(la);
2383 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2387 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2388 && la->aliasAddress.s_addr != addr.s_addr)
2389 CleanupAliasData(la);
2391 la->aliasAddress = addr;
2392 LIBALIAS_UNLOCK(la);
2397 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
2402 la->aliasPortLower = port_low;
2403 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
2404 la->aliasPortLength = port_high - port_low + 1;
2405 LIBALIAS_UNLOCK(la);
2409 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2413 la->targetAddress = target_addr;
2414 LIBALIAS_UNLOCK(la);
2421 while (!LIST_EMPTY(&instancehead))
2422 LibAliasUninit(LIST_FIRST(&instancehead));
2426 LibAliasInit(struct libalias *la)
2435 #undef malloc /* XXX: ugly */
2436 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2438 la = calloc(sizeof *la, 1);
2443 #ifndef _KERNEL /* kernel cleans up on module unload */
2444 if (LIST_EMPTY(&instancehead))
2447 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2450 la->timeStamp = time_uptime;
2451 la->lastCleanupTime = time_uptime;
2453 gettimeofday(&tv, NULL);
2454 la->timeStamp = tv.tv_sec;
2455 la->lastCleanupTime = tv.tv_sec;
2458 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2459 LIST_INIT(&la->linkTableOut[i]);
2460 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2461 LIST_INIT(&la->linkTableIn[i]);
2465 LIBALIAS_LOCK_INIT(la);
2469 la->deleteAllLinks = 1;
2470 CleanupAliasData(la);
2471 la->deleteAllLinks = 0;
2478 la->aliasAddress.s_addr = INADDR_ANY;
2479 la->targetAddress.s_addr = INADDR_ANY;
2481 la->icmpLinkCount = 0;
2482 la->udpLinkCount = 0;
2483 la->tcpLinkCount = 0;
2484 la->sctpLinkCount = 0;
2485 la->pptpLinkCount = 0;
2486 la->protoLinkCount = 0;
2487 la->fragmentIdLinkCount = 0;
2488 la->fragmentPtrLinkCount = 0;
2491 la->cleanupIndex = 0;
2493 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2494 #ifndef NO_USE_SOCKETS
2495 | PKT_ALIAS_USE_SOCKETS
2497 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2499 la->fireWallFD = -1;
2502 LibAliasRefreshModules();
2504 LIBALIAS_UNLOCK(la);
2509 LibAliasUninit(struct libalias *la)
2516 la->deleteAllLinks = 1;
2517 CleanupAliasData(la);
2518 la->deleteAllLinks = 0;
2519 UninitPacketAliasLog(la);
2523 LIST_REMOVE(la, instancelist);
2524 LIBALIAS_UNLOCK(la);
2525 LIBALIAS_LOCK_DESTROY(la);
2529 /* Change mode for some operations */
2532 struct libalias *la,
2533 unsigned int flags, /* Which state to bring flags to */
2534 unsigned int mask /* Mask of which flags to affect (use 0 to
2535 * do a probe for flag values) */
2541 /* Enable logging? */
2542 if (flags & mask & PKT_ALIAS_LOG) {
2544 if (InitPacketAliasLog(la) == ENOMEM)
2547 /* _Disable_ logging? */
2548 if (~flags & mask & PKT_ALIAS_LOG) {
2549 UninitPacketAliasLog(la);
2552 /* Start punching holes in the firewall? */
2553 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2556 /* Stop punching holes in the firewall? */
2557 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2562 /* Other flags can be set/cleared without special action */
2563 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2564 res = la->packetAliasMode;
2566 LIBALIAS_UNLOCK(la);
2571 LibAliasCheckNewLink(struct libalias *la)
2576 res = la->newDefaultLink;
2577 LIBALIAS_UNLOCK(la);
2584 Code to support firewall punching. This shouldn't really be in this
2585 file, but making variables global is evil too.
2588 /* Firewall include files */
2590 #include <netinet/ip_fw.h>
2595 * helper function, updates the pointer to cmd with the length
2596 * of the current command, and also cleans up the first word of
2597 * the new command in case it has been clobbered before.
2600 next_cmd(ipfw_insn * cmd)
2603 bzero(cmd, sizeof(*cmd));
2608 * A function to fill simple commands of size 1.
2609 * Existing flags are preserved.
2612 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2613 int flags, u_int16_t arg)
2615 cmd->opcode = opcode;
2616 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2618 return next_cmd(cmd);
2622 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2624 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2626 cmd->addr.s_addr = addr;
2627 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2631 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2633 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2635 cmd->ports[0] = cmd->ports[1] = port;
2636 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2640 fill_rule(void *buf, int bufsize, int rulenum,
2641 enum ipfw_opcodes action, int proto,
2642 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2644 struct ip_fw *rule = (struct ip_fw *)buf;
2645 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2647 bzero(buf, bufsize);
2648 rule->rulenum = rulenum;
2650 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2651 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2652 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2653 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2654 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2656 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2657 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2659 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2661 return ((char *)cmd - (char *)buf);
2664 static void ClearAllFWHoles(struct libalias *la);
2666 #define fw_setfield(la, field, num) \
2668 (field)[(num) - la->fireWallBaseNum] = 1; \
2669 } /*lint -save -e717 */ while(0)/* lint -restore */
2671 #define fw_clrfield(la, field, num) \
2673 (field)[(num) - la->fireWallBaseNum] = 0; \
2674 } /*lint -save -e717 */ while(0)/* lint -restore */
2676 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2679 InitPunchFW(struct libalias *la)
2682 la->fireWallField = malloc(la->fireWallNumNums);
2683 if (la->fireWallField) {
2684 memset(la->fireWallField, 0, la->fireWallNumNums);
2685 if (la->fireWallFD < 0) {
2686 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2688 ClearAllFWHoles(la);
2689 la->fireWallActiveNum = la->fireWallBaseNum;
2694 UninitPunchFW(struct libalias *la)
2697 ClearAllFWHoles(la);
2698 if (la->fireWallFD >= 0)
2699 close(la->fireWallFD);
2700 la->fireWallFD = -1;
2701 if (la->fireWallField)
2702 free(la->fireWallField);
2703 la->fireWallField = NULL;
2704 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2707 /* Make a certain link go through the firewall */
2709 PunchFWHole(struct alias_link *lnk)
2711 struct libalias *la;
2712 int r; /* Result code */
2713 struct ip_fw rule; /* On-the-fly built rule */
2714 int fwhole; /* Where to punch hole */
2718 /* Don't do anything unless we are asked to */
2719 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2720 la->fireWallFD < 0 ||
2721 lnk->link_type != LINK_TCP)
2724 memset(&rule, 0, sizeof rule);
2728 /* Find empty slot */
2729 for (fwhole = la->fireWallActiveNum;
2730 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2731 fw_tstfield(la, la->fireWallField, fwhole);
2733 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2734 for (fwhole = la->fireWallBaseNum;
2735 fwhole < la->fireWallActiveNum &&
2736 fw_tstfield(la, la->fireWallField, fwhole);
2738 if (fwhole == la->fireWallActiveNum) {
2739 /* No rule point empty - we can't punch more holes. */
2740 la->fireWallActiveNum = la->fireWallBaseNum;
2741 #ifdef LIBALIAS_DEBUG
2742 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2747 /* Start next search at next position */
2748 la->fireWallActiveNum = fwhole + 1;
2751 * generate two rules of the form
2753 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2754 * accept tcp from DAddr DPort to OAddr OPort
2756 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2757 u_int32_t rulebuf[255];
2760 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2761 O_ACCEPT, IPPROTO_TCP,
2762 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2763 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2764 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2766 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2768 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2769 O_ACCEPT, IPPROTO_TCP,
2770 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2771 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2772 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2774 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2777 /* Indicate hole applied */
2778 lnk->data.tcp->fwhole = fwhole;
2779 fw_setfield(la, la->fireWallField, fwhole);
2782 /* Remove a hole in a firewall associated with a particular alias
2783 lnk. Calling this too often is harmless. */
2785 ClearFWHole(struct alias_link *lnk)
2787 struct libalias *la;
2790 if (lnk->link_type == LINK_TCP) {
2791 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2798 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2799 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2800 &fwhole, sizeof fwhole));
2801 fw_clrfield(la, la->fireWallField, fwhole);
2802 lnk->data.tcp->fwhole = -1;
2806 /* Clear out the entire range dedicated to firewall holes. */
2808 ClearAllFWHoles(struct libalias *la)
2810 struct ip_fw rule; /* On-the-fly built rule */
2813 if (la->fireWallFD < 0)
2816 memset(&rule, 0, sizeof rule);
2817 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2820 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2822 /* XXX: third arg correct here ? /phk */
2823 memset(la->fireWallField, 0, la->fireWallNumNums);
2826 #endif /* !NO_FW_PUNCH */
2829 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2834 la->fireWallBaseNum = base;
2835 la->fireWallNumNums = num;
2837 LIBALIAS_UNLOCK(la);
2841 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2845 la->skinnyPort = port;
2846 LIBALIAS_UNLOCK(la);
2850 * Find the address to redirect incoming packets
2853 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm)
2855 struct alias_link *lnk;
2856 struct in_addr redir;
2858 LIBALIAS_LOCK_ASSERT(la);
2859 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2860 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2862 return(lnk->src_addr); /* port redirect */
2864 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2865 if (redir.s_addr == la->aliasAddress.s_addr ||
2866 redir.s_addr == la->targetAddress.s_addr) { /* No address found */
2867 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2868 NO_DEST_PORT, 0, LINK_SCTP, 1);
2870 return(lnk->src_addr); /* redirect proto */
2872 return(redir); /* address redirect */