2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 Alias_db.c encapsulates all data structures used for storing
32 packet aliasing data. Other parts of the aliasing software
33 access data through functions provided in this file.
35 Data storage is based on the notion of a "link", which is
36 established for ICMP echo/reply packets, UDP datagrams and
37 TCP stream connections. A link stores the original source
38 and destination addresses. For UDP and TCP, it also stores
39 source and destination port numbers, as well as an alias
40 port number. Links are also used to store information about
43 There is a facility for sweeping through and deleting old
44 links as new packets are sent through. A simple timeout is
45 used for ICMP and UDP links. TCP links are left alone unless
46 there is an incomplete connection, in which case the link
47 can be deleted after a certain amount of time.
50 Initial version: August, 1996 (cjm)
52 Version 1.4: September 16, 1996 (cjm)
53 Facility for handling incoming links added.
55 Version 1.6: September 18, 1996 (cjm)
56 ICMP data handling simplified.
58 Version 1.7: January 9, 1997 (cjm)
59 Fragment handling simplified.
60 Saves pointers for unresolved fragments.
61 Permits links for unspecified remote ports
62 or unspecified remote addresses.
63 Fixed bug which did not properly zero port
64 table entries after a link was deleted.
65 Cleaned up some obsolete comments.
67 Version 1.8: January 14, 1997 (cjm)
68 Fixed data type error in StartPoint().
69 (This error did not exist prior to v1.7
70 and was discovered and fixed by Ari Suutari)
72 Version 1.9: February 1, 1997
73 Optionally, connections initiated from packet aliasing host
74 machine will will not have their port number aliased unless it
75 conflicts with an aliasing port already being used. (cjm)
77 All options earlier being #ifdef'ed are now available through
78 a new interface, SetPacketAliasMode(). This allows run time
79 control (which is now available in PPP+pktAlias through the
80 'alias' keyword). (ee)
82 Added ability to create an alias port without
83 either destination address or port specified.
84 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
86 Removed K&R style function headers
87 and general cleanup. (ee)
89 Added packetAliasMode to replace compiler #defines's (ee)
91 Allocates sockets for partially specified
92 ports if ALIAS_USE_SOCKETS defined. (cjm)
94 Version 2.0: March, 1997
95 SetAliasAddress() will now clean up alias links
96 if the aliasing address is changed. (cjm)
98 PacketAliasPermanentLink() function added to support permanent
99 links. (J. Fortes suggested the need for this.)
102 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
104 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
107 These permanent links allow for incoming connections to
108 machines on the local network. They can be given with a
109 user-chosen amount of specificity, with increasing specificity
110 meaning more security. (cjm)
112 Quite a bit of rework to the basic engine. The portTable[]
113 array, which kept track of which ports were in use was replaced
114 by a table/linked list structure. (cjm)
116 SetExpire() function added. (cjm)
118 DeleteLink() no longer frees memory association with a pointer
119 to a fragment (this bug was first recognized by E. Eklund in
122 Version 2.1: May, 1997 (cjm)
123 Packet aliasing engine reworked so that it can handle
124 multiple external addresses rather than just a single
127 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
128 added to the API. The first function is a more generalized
129 version of PacketAliasPermanentLink(). The second function
130 implements static network address translation.
132 Version 3.2: July, 2000 (salander and satoh)
133 Added FindNewPortGroup to get contiguous range of port values.
135 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
136 link but not actually add one.
138 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
139 except that the alias port (from FindNewPortGroup) is provided
142 See HISTORY file for additional revisions.
146 #include <machine/stdarg.h>
147 #include <sys/param.h>
148 #include <sys/kernel.h>
149 #include <sys/systm.h>
150 #include <sys/lock.h>
151 #include <sys/module.h>
152 #include <sys/rwlock.h>
153 #include <sys/syslog.h>
158 #include <sys/errno.h>
159 #include <sys/time.h>
163 #include <sys/socket.h>
164 #include <netinet/tcp.h>
167 #include <netinet/libalias/alias.h>
168 #include <netinet/libalias/alias_local.h>
169 #include <netinet/libalias/alias_mod.h>
173 #include "alias_local.h"
174 #include "alias_mod.h"
177 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
221 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
222 These constants can be anything except zero, which indicates an
223 unknown port number. */
225 #define NO_DEST_PORT 1
226 #define NO_SRC_PORT 1
232 The fundamental data structure used in this program is
233 "struct alias_link". Whenever a TCP connection is made,
234 a UDP datagram is sent out, or an ICMP echo request is made,
235 a link record is made (if it has not already been created).
236 The link record is identified by the source address/port
237 and the destination address/port. In the case of an ICMP
238 echo request, the source port is treated as being equivalent
239 with the 16-bit ID number of the ICMP packet.
241 The link record also can store some auxiliary data. For
242 TCP connections that have had sequence and acknowledgment
243 modifications, data space is available to track these changes.
244 A state field is used to keep track in changes to the TCP
245 connection state. ID numbers of fragments can also be
246 stored in the auxiliary space. Pointers to unresolved
247 fragments can also be stored.
249 The link records support two independent chainings. Lookup
250 tables for input and out tables hold the initial pointers
251 the link chains. On input, the lookup table indexes on alias
252 port and link type. On output, the lookup table indexes on
253 source address, destination address, source port, destination
257 struct ack_data_record { /* used to save changes to ACK/sequence
265 struct tcp_state { /* Information about TCP connection */
266 int in; /* State for outside -> inside */
267 int out; /* State for inside -> outside */
268 int index; /* Index to ACK data array */
269 int ack_modified; /* Indicates whether ACK and
270 * sequence numbers */
274 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
275 * saved for a modified TCP stream */
277 struct tcp_state state;
278 struct ack_data_record ack[N_LINK_TCP_DATA];
279 int fwhole; /* Which firewall record is used for this
283 struct server { /* LSNAT server pool (circular list) */
289 struct alias_link { /* Main data structure */
291 struct in_addr src_addr; /* Address and port information */
292 struct in_addr dst_addr;
293 struct in_addr alias_addr;
294 struct in_addr proxy_addr;
299 struct server *server;
301 int link_type; /* Type of link: TCP, UDP, ICMP,
304 /* values for link_type */
305 #define LINK_ICMP IPPROTO_ICMP
306 #define LINK_UDP IPPROTO_UDP
307 #define LINK_TCP IPPROTO_TCP
308 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
309 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
310 #define LINK_ADDR (IPPROTO_MAX + 3)
311 #define LINK_PPTP (IPPROTO_MAX + 4)
313 int flags; /* indicates special characteristics */
314 int pflags; /* protocol-specific flags */
317 #define LINK_UNKNOWN_DEST_PORT 0x01
318 #define LINK_UNKNOWN_DEST_ADDR 0x02
319 #define LINK_PERMANENT 0x04
320 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
321 #define LINK_UNFIREWALLED 0x08
323 int timestamp; /* Time link was last accessed */
324 int expire_time; /* Expire time for link */
325 #ifndef NO_USE_SOCKETS
326 int sockfd; /* socket descriptor */
328 LIST_ENTRY (alias_link) list_out; /* Linked list of
330 LIST_ENTRY (alias_link) list_in; /* input and output
333 union { /* Auxiliary data */
335 struct in_addr frag_addr;
340 /* Clean up procedure. */
341 static void finishoff(void);
343 /* Kernel module definition. */
345 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
347 MODULE_VERSION(libalias, 1);
350 alias_mod_handler(module_t mod, int type, void *data)
364 static moduledata_t alias_mod = {
365 "alias", alias_mod_handler, NULL
368 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
371 /* Internal utility routines (used only in alias_db.c)
373 Lookup table starting points:
374 StartPointIn() -- link table initial search point for
376 StartPointOut() -- link table initial search point for
380 SeqDiff() -- difference between two TCP sequences
381 ShowAliasStats() -- send alias statistics to a monitor file
385 /* Local prototypes */
386 static u_int StartPointIn(struct in_addr, u_short, int);
389 StartPointOut(struct in_addr, struct in_addr,
390 u_short, u_short, int);
392 static int SeqDiff(u_long, u_long);
395 /* Firewall control */
396 static void InitPunchFW(struct libalias *);
397 static void UninitPunchFW(struct libalias *);
398 static void ClearFWHole(struct alias_link *);
402 /* Log file control */
403 static void ShowAliasStats(struct libalias *);
404 static int InitPacketAliasLog(struct libalias *);
405 static void UninitPacketAliasLog(struct libalias *);
407 void SctpShowAliasStats(struct libalias *la);
410 StartPointIn(struct in_addr alias_addr,
416 n = alias_addr.s_addr;
417 if (link_type != LINK_PPTP)
420 return (n % LINK_TABLE_IN_SIZE);
425 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
426 u_short src_port, u_short dst_port, int link_type)
431 n += dst_addr.s_addr;
432 if (link_type != LINK_PPTP) {
438 return (n % LINK_TABLE_OUT_SIZE);
443 SeqDiff(u_long x, u_long y)
445 /* Return the difference between two TCP sequence numbers */
448 This function is encapsulated in case there are any unusual
449 arithmetic conditions that need to be considered.
452 return (ntohl(y) - ntohl(x));
458 AliasLog(char *str, const char *format, ...)
462 va_start(ap, format);
463 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
468 AliasLog(FILE *stream, const char *format, ...)
472 va_start(ap, format);
473 vfprintf(stream, format, ap);
480 ShowAliasStats(struct libalias *la)
483 LIBALIAS_LOCK_ASSERT(la);
484 /* Used for debugging */
486 int tot = la->icmpLinkCount + la->udpLinkCount +
487 (la->sctpLinkCount>>1) + /* sctp counts half associations */
488 la->tcpLinkCount + la->pptpLinkCount +
489 la->protoLinkCount + la->fragmentIdLinkCount +
490 la->fragmentPtrLinkCount;
492 AliasLog(la->logDesc,
493 "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
497 la->sctpLinkCount>>1, /* sctp counts half associations */
500 la->fragmentIdLinkCount,
501 la->fragmentPtrLinkCount, tot);
503 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
508 void SctpShowAliasStats(struct libalias *la)
515 /* Internal routines for finding, deleting and adding links
518 GetNewPort() -- find and reserve new alias port number
519 GetSocket() -- try to allocate a socket for a given port
521 Link creation and deletion:
522 CleanupAliasData() - remove all link chains from lookup table
523 IncrementalCleanup() - look for stale links in a single chain
524 DeleteLink() - remove link
526 ReLink() - change link
529 FindLinkOut() - find link for outgoing packets
530 FindLinkIn() - find link for incoming packets
533 FindNewPortGroup() - find an available group of ports
536 /* Local prototypes */
537 static int GetNewPort(struct libalias *, struct alias_link *, int);
538 #ifndef NO_USE_SOCKETS
539 static u_short GetSocket(struct libalias *, u_short, int *, int);
541 static void CleanupAliasData(struct libalias *);
543 static void IncrementalCleanup(struct libalias *);
545 static void DeleteLink(struct alias_link *);
547 static struct alias_link *
548 ReLink(struct alias_link *,
549 struct in_addr, struct in_addr, struct in_addr,
550 u_short, u_short, int, int);
552 static struct alias_link *
553 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
555 static struct alias_link *
556 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
559 #define ALIAS_PORT_BASE 0x08000
560 #define ALIAS_PORT_MASK 0x07fff
561 #define ALIAS_PORT_MASK_EVEN 0x07ffe
562 #define GET_NEW_PORT_MAX_ATTEMPTS 20
564 #define FIND_EVEN_ALIAS_BASE 1
566 /* GetNewPort() allocates port numbers. Note that if a port number
567 is already in use, that does not mean that it cannot be used by
568 another link concurrently. This is because GetNewPort() looks for
569 unused triplets: (dest addr, dest port, alias port). */
572 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
579 LIBALIAS_LOCK_ASSERT(la);
581 Description of alias_port_param for GetNewPort(). When
582 this parameter is zero or positive, it precisely specifies
583 the port number. GetNewPort() will return this number
584 without check that it is in use.
586 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
587 selected port number.
590 if (alias_port_param == GET_ALIAS_PORT) {
592 * The aliasing port is automatically selected by one of
595 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
597 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
599 * When the PKT_ALIAS_SAME_PORTS option is chosen,
600 * the first try will be the actual source port. If
601 * this is already in use, the remainder of the
602 * trials will be random.
604 port_net = lnk->src_port;
605 port_sys = ntohs(port_net);
607 /* First trial and all subsequent are random. */
608 port_sys = arc4random() & ALIAS_PORT_MASK;
609 port_sys += ALIAS_PORT_BASE;
610 port_net = htons(port_sys);
612 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
613 lnk->alias_port = (u_short) alias_port_param;
616 #ifdef LIBALIAS_DEBUG
617 fprintf(stderr, "PacketAlias/GetNewPort(): ");
618 fprintf(stderr, "input parameter error\n");
624 /* Port number search */
625 for (i = 0; i < max_trials; i++) {
627 struct alias_link *search_result;
629 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
630 lnk->dst_port, port_net,
633 if (search_result == NULL)
635 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
636 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
642 #ifndef NO_USE_SOCKETS
643 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
644 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
645 && ((lnk->link_type == LINK_TCP) ||
646 (lnk->link_type == LINK_UDP))) {
647 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
648 lnk->alias_port = port_net;
653 lnk->alias_port = port_net;
655 #ifndef NO_USE_SOCKETS
659 port_sys = arc4random() & ALIAS_PORT_MASK;
660 port_sys += ALIAS_PORT_BASE;
661 port_net = htons(port_sys);
664 #ifdef LIBALIAS_DEBUG
665 fprintf(stderr, "PacketAlias/GetnewPort(): ");
666 fprintf(stderr, "could not find free port\n");
672 #ifndef NO_USE_SOCKETS
674 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
678 struct sockaddr_in sock_addr;
680 LIBALIAS_LOCK_ASSERT(la);
681 if (link_type == LINK_TCP)
682 sock = socket(AF_INET, SOCK_STREAM, 0);
683 else if (link_type == LINK_UDP)
684 sock = socket(AF_INET, SOCK_DGRAM, 0);
686 #ifdef LIBALIAS_DEBUG
687 fprintf(stderr, "PacketAlias/GetSocket(): ");
688 fprintf(stderr, "incorrect link type\n");
694 #ifdef LIBALIAS_DEBUG
695 fprintf(stderr, "PacketAlias/GetSocket(): ");
696 fprintf(stderr, "socket() error %d\n", *sockfd);
700 sock_addr.sin_family = AF_INET;
701 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
702 sock_addr.sin_port = port_net;
705 (struct sockaddr *)&sock_addr,
718 /* FindNewPortGroup() returns a base port number for an available
719 range of contiguous port numbers. Note that if a port number
720 is already in use, that does not mean that it cannot be used by
721 another link concurrently. This is because FindNewPortGroup()
722 looks for unused triplets: (dest addr, dest port, alias port). */
725 FindNewPortGroup(struct libalias *la,
726 struct in_addr dst_addr,
727 struct in_addr alias_addr,
739 LIBALIAS_LOCK_ASSERT(la);
741 * Get link_type from protocol
746 link_type = LINK_UDP;
749 link_type = LINK_TCP;
757 * The aliasing port is automatically selected by one of two
760 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
762 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
764 * When the ALIAS_SAME_PORTS option is chosen, the first
765 * try will be the actual source port. If this is already
766 * in use, the remainder of the trials will be random.
768 port_sys = ntohs(src_port);
772 /* First trial and all subsequent are random. */
773 if (align == FIND_EVEN_ALIAS_BASE)
774 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
776 port_sys = arc4random() & ALIAS_PORT_MASK;
778 port_sys += ALIAS_PORT_BASE;
781 /* Port number search */
782 for (i = 0; i < max_trials; i++) {
784 struct alias_link *search_result;
786 for (j = 0; j < port_count; j++)
787 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
788 dst_port, htons(port_sys + j),
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;
834 IncrementalCleanup(struct libalias *la)
836 struct alias_link *lnk, *lnk_tmp;
838 LIBALIAS_LOCK_ASSERT(la);
839 LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
841 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
845 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
846 la->cleanupIndex = 0;
850 DeleteLink(struct alias_link *lnk)
852 struct libalias *la = lnk->la;
854 LIBALIAS_LOCK_ASSERT(la);
855 /* Don't do anything if the link is marked permanent */
856 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
860 /* Delete associated firewall hole, if any */
864 /* Free memory allocated for LSNAT server pool */
865 if (lnk->server != NULL) {
866 struct server *head, *curr, *next;
868 head = curr = lnk->server;
872 } while ((curr = next) != head);
874 /* Adjust output table pointers */
875 LIST_REMOVE(lnk, list_out);
877 /* Adjust input table pointers */
878 LIST_REMOVE(lnk, list_in);
879 #ifndef NO_USE_SOCKETS
880 /* Close socket, if one has been allocated */
881 if (lnk->sockfd != -1) {
886 /* Link-type dependent cleanup */
887 switch (lnk->link_type) {
901 case LINK_FRAGMENT_ID:
902 la->fragmentIdLinkCount--;
904 case LINK_FRAGMENT_PTR:
905 la->fragmentPtrLinkCount--;
906 if (lnk->data.frag_ptr != NULL)
907 free(lnk->data.frag_ptr);
912 la->protoLinkCount--;
919 /* Write statistics, if logging enabled */
920 if (la->packetAliasMode & PKT_ALIAS_LOG) {
927 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
928 struct in_addr alias_addr, u_short src_port, u_short dst_port,
929 int alias_port_param, int link_type)
932 struct alias_link *lnk;
934 LIBALIAS_LOCK_ASSERT(la);
935 lnk = malloc(sizeof(struct alias_link));
937 /* Basic initialization */
939 lnk->src_addr = src_addr;
940 lnk->dst_addr = dst_addr;
941 lnk->alias_addr = alias_addr;
942 lnk->proxy_addr.s_addr = INADDR_ANY;
943 lnk->src_port = src_port;
944 lnk->dst_port = dst_port;
947 lnk->link_type = link_type;
948 #ifndef NO_USE_SOCKETS
953 lnk->timestamp = la->timeStamp;
955 /* Expiration time */
958 lnk->expire_time = ICMP_EXPIRE_TIME;
961 lnk->expire_time = UDP_EXPIRE_TIME;
964 lnk->expire_time = TCP_EXPIRE_INITIAL;
967 lnk->flags |= LINK_PERMANENT; /* no timeout. */
969 case LINK_FRAGMENT_ID:
970 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
972 case LINK_FRAGMENT_PTR:
973 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
978 lnk->expire_time = PROTO_EXPIRE_TIME;
982 /* Determine alias flags */
983 if (dst_addr.s_addr == INADDR_ANY)
984 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
986 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
988 /* Determine alias port */
989 if (GetNewPort(la, lnk, alias_port_param) != 0) {
993 /* Link-type dependent initialization */
995 struct tcp_dat *aux_tcp;
1004 aux_tcp = malloc(sizeof(struct tcp_dat));
1005 if (aux_tcp != NULL) {
1009 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1010 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1011 aux_tcp->state.index = 0;
1012 aux_tcp->state.ack_modified = 0;
1013 for (i = 0; i < N_LINK_TCP_DATA; i++)
1014 aux_tcp->ack[i].active = 0;
1015 aux_tcp->fwhole = -1;
1016 lnk->data.tcp = aux_tcp;
1018 #ifdef LIBALIAS_DEBUG
1019 fprintf(stderr, "PacketAlias/AddLink: ");
1020 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1027 la->pptpLinkCount++;
1029 case LINK_FRAGMENT_ID:
1030 la->fragmentIdLinkCount++;
1032 case LINK_FRAGMENT_PTR:
1033 la->fragmentPtrLinkCount++;
1038 la->protoLinkCount++;
1042 /* Set up pointers for output lookup table */
1043 start_point = StartPointOut(src_addr, dst_addr,
1044 src_port, dst_port, link_type);
1045 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1047 /* Set up pointers for input lookup table */
1048 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1049 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1051 #ifdef LIBALIAS_DEBUG
1052 fprintf(stderr, "PacketAlias/AddLink(): ");
1053 fprintf(stderr, "malloc() call failed.\n");
1056 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1062 static struct alias_link *
1063 ReLink(struct alias_link *old_lnk,
1064 struct in_addr src_addr,
1065 struct in_addr dst_addr,
1066 struct in_addr alias_addr,
1069 int alias_port_param, /* if less than zero, alias */
1071 { /* port will be automatically *//* chosen.
1072 * If greater than */
1073 struct alias_link *new_lnk; /* zero, equal to alias port */
1074 struct libalias *la = old_lnk->la;
1076 LIBALIAS_LOCK_ASSERT(la);
1077 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1078 src_port, dst_port, alias_port_param,
1081 if (new_lnk != NULL &&
1082 old_lnk->link_type == LINK_TCP &&
1083 old_lnk->data.tcp->fwhole > 0) {
1084 PunchFWHole(new_lnk);
1087 DeleteLink(old_lnk);
1091 static struct alias_link *
1092 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1093 struct in_addr dst_addr,
1097 int replace_partial_links)
1100 struct alias_link *lnk;
1102 LIBALIAS_LOCK_ASSERT(la);
1103 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1104 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1105 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1106 lnk->src_addr.s_addr == src_addr.s_addr &&
1107 lnk->src_port == src_port &&
1108 lnk->dst_port == dst_port &&
1109 lnk->link_type == link_type &&
1110 lnk->server == NULL) {
1111 lnk->timestamp = la->timeStamp;
1116 /* Search for partially specified links. */
1117 if (lnk == NULL && replace_partial_links) {
1118 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1119 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1122 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1123 dst_port, link_type, 0);
1126 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1127 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1132 src_addr, dst_addr, lnk->alias_addr,
1133 src_port, dst_port, lnk->alias_port,
1140 static struct alias_link *
1141 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1142 struct in_addr dst_addr,
1146 int replace_partial_links)
1148 struct alias_link *lnk;
1150 LIBALIAS_LOCK_ASSERT(la);
1151 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1152 link_type, replace_partial_links);
1156 * The following allows permanent links to be specified as
1157 * using the default source address (i.e. device interface
1158 * address) without knowing in advance what that address
1161 if (la->aliasAddress.s_addr != INADDR_ANY &&
1162 src_addr.s_addr == la->aliasAddress.s_addr) {
1163 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1164 link_type, replace_partial_links);
1171 static struct alias_link *
1172 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1173 struct in_addr alias_addr,
1177 int replace_partial_links)
1181 struct alias_link *lnk;
1182 struct alias_link *lnk_fully_specified;
1183 struct alias_link *lnk_unknown_all;
1184 struct alias_link *lnk_unknown_dst_addr;
1185 struct alias_link *lnk_unknown_dst_port;
1187 LIBALIAS_LOCK_ASSERT(la);
1188 /* Initialize pointers */
1189 lnk_fully_specified = NULL;
1190 lnk_unknown_all = NULL;
1191 lnk_unknown_dst_addr = NULL;
1192 lnk_unknown_dst_port = NULL;
1194 /* If either the dest addr or port is unknown, the search
1195 loop will have to know about this. */
1198 if (dst_addr.s_addr == INADDR_ANY)
1199 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1201 flags_in |= LINK_UNKNOWN_DEST_PORT;
1204 start_point = StartPointIn(alias_addr, alias_port, link_type);
1205 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1208 flags = flags_in | lnk->flags;
1209 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1210 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1211 && lnk->alias_port == alias_port
1212 && lnk->dst_addr.s_addr == dst_addr.s_addr
1213 && lnk->dst_port == dst_port
1214 && lnk->link_type == link_type) {
1215 lnk_fully_specified = lnk;
1218 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1219 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1220 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1221 && lnk->alias_port == alias_port
1222 && lnk->link_type == link_type) {
1223 if (lnk_unknown_all == NULL)
1224 lnk_unknown_all = lnk;
1226 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1227 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1228 && lnk->alias_port == alias_port
1229 && lnk->link_type == link_type
1230 && lnk->dst_port == dst_port) {
1231 if (lnk_unknown_dst_addr == NULL)
1232 lnk_unknown_dst_addr = lnk;
1234 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1235 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1236 && lnk->alias_port == alias_port
1237 && lnk->link_type == link_type
1238 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1239 if (lnk_unknown_dst_port == NULL)
1240 lnk_unknown_dst_port = lnk;
1247 if (lnk_fully_specified != NULL) {
1248 lnk_fully_specified->timestamp = la->timeStamp;
1249 lnk = lnk_fully_specified;
1250 } else if (lnk_unknown_dst_port != NULL)
1251 lnk = lnk_unknown_dst_port;
1252 else if (lnk_unknown_dst_addr != NULL)
1253 lnk = lnk_unknown_dst_addr;
1254 else if (lnk_unknown_all != NULL)
1255 lnk = lnk_unknown_all;
1259 if (replace_partial_links &&
1260 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1261 struct in_addr src_addr;
1264 if (lnk->server != NULL) { /* LSNAT link */
1265 src_addr = lnk->server->addr;
1266 src_port = lnk->server->port;
1267 lnk->server = lnk->server->next;
1269 src_addr = lnk->src_addr;
1270 src_port = lnk->src_port;
1273 if (link_type == LINK_SCTP) {
1274 lnk->src_addr = src_addr;
1275 lnk->src_port = src_port;
1279 src_addr, dst_addr, alias_addr,
1280 src_port, dst_port, alias_port,
1286 static struct alias_link *
1287 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1288 struct in_addr alias_addr,
1292 int replace_partial_links)
1294 struct alias_link *lnk;
1296 LIBALIAS_LOCK_ASSERT(la);
1297 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1298 link_type, replace_partial_links);
1302 * The following allows permanent links to be specified as
1303 * using the default aliasing address (i.e. device
1304 * interface address) without knowing in advance what that
1307 if (la->aliasAddress.s_addr != INADDR_ANY &&
1308 alias_addr.s_addr == la->aliasAddress.s_addr) {
1309 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1310 link_type, replace_partial_links);
1319 /* External routines for finding/adding links
1321 -- "external" means outside alias_db.c, but within alias*.c --
1323 FindIcmpIn(), FindIcmpOut()
1324 FindFragmentIn1(), FindFragmentIn2()
1325 AddFragmentPtrLink(), FindFragmentPtr()
1326 FindProtoIn(), FindProtoOut()
1327 FindUdpTcpIn(), FindUdpTcpOut()
1328 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1329 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1330 FindOriginalAddress(), FindAliasAddress()
1332 (prototypes in alias_local.h)
1337 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1338 struct in_addr alias_addr,
1342 struct alias_link *lnk;
1344 LIBALIAS_LOCK_ASSERT(la);
1345 lnk = FindLinkIn(la, dst_addr, alias_addr,
1346 NO_DEST_PORT, id_alias,
1348 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1349 struct in_addr target_addr;
1351 target_addr = FindOriginalAddress(la, alias_addr);
1352 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1353 id_alias, NO_DEST_PORT, id_alias,
1361 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1362 struct in_addr dst_addr,
1366 struct alias_link *lnk;
1368 LIBALIAS_LOCK_ASSERT(la);
1369 lnk = FindLinkOut(la, src_addr, dst_addr,
1372 if (lnk == NULL && create) {
1373 struct in_addr alias_addr;
1375 alias_addr = FindAliasAddress(la, src_addr);
1376 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1377 id, NO_DEST_PORT, GET_ALIAS_ID,
1385 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1386 struct in_addr alias_addr,
1389 struct alias_link *lnk;
1391 LIBALIAS_LOCK_ASSERT(la);
1392 lnk = FindLinkIn(la, dst_addr, alias_addr,
1393 NO_DEST_PORT, ip_id,
1394 LINK_FRAGMENT_ID, 0);
1397 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1398 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1406 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1408 struct in_addr alias_addr, /* is not found. */
1412 LIBALIAS_LOCK_ASSERT(la);
1413 return FindLinkIn(la, dst_addr, alias_addr,
1414 NO_DEST_PORT, ip_id,
1415 LINK_FRAGMENT_ID, 0);
1420 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1424 LIBALIAS_LOCK_ASSERT(la);
1425 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1426 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1432 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1436 LIBALIAS_LOCK_ASSERT(la);
1437 return FindLinkIn(la, dst_addr, la->nullAddress,
1438 NO_DEST_PORT, ip_id,
1439 LINK_FRAGMENT_PTR, 0);
1444 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1445 struct in_addr alias_addr,
1448 struct alias_link *lnk;
1450 LIBALIAS_LOCK_ASSERT(la);
1451 lnk = FindLinkIn(la, dst_addr, alias_addr,
1455 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1456 struct in_addr target_addr;
1458 target_addr = FindOriginalAddress(la, alias_addr);
1459 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1460 NO_SRC_PORT, NO_DEST_PORT, 0,
1468 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1469 struct in_addr dst_addr,
1472 struct alias_link *lnk;
1474 LIBALIAS_LOCK_ASSERT(la);
1475 lnk = FindLinkOut(la, src_addr, dst_addr,
1476 NO_SRC_PORT, NO_DEST_PORT,
1480 struct in_addr alias_addr;
1482 alias_addr = FindAliasAddress(la, src_addr);
1483 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1484 NO_SRC_PORT, NO_DEST_PORT, 0,
1492 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1493 struct in_addr alias_addr,
1500 struct alias_link *lnk;
1502 LIBALIAS_LOCK_ASSERT(la);
1505 link_type = LINK_UDP;
1508 link_type = LINK_TCP;
1515 lnk = FindLinkIn(la, dst_addr, alias_addr,
1516 dst_port, alias_port,
1519 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1520 struct in_addr target_addr;
1522 target_addr = FindOriginalAddress(la, alias_addr);
1523 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1524 alias_port, dst_port, alias_port,
1532 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1533 struct in_addr dst_addr,
1540 struct alias_link *lnk;
1542 LIBALIAS_LOCK_ASSERT(la);
1545 link_type = LINK_UDP;
1548 link_type = LINK_TCP;
1555 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1557 if (lnk == NULL && create) {
1558 struct in_addr alias_addr;
1560 alias_addr = FindAliasAddress(la, src_addr);
1561 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1562 src_port, dst_port, GET_ALIAS_PORT,
1570 AddPptp(struct libalias *la, struct in_addr src_addr,
1571 struct in_addr dst_addr,
1572 struct in_addr alias_addr,
1573 u_int16_t src_call_id)
1575 struct alias_link *lnk;
1577 LIBALIAS_LOCK_ASSERT(la);
1578 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1579 src_call_id, 0, GET_ALIAS_PORT,
1587 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1588 struct in_addr dst_addr,
1589 u_int16_t src_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->src_port == src_call_id)
1608 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1609 struct in_addr dst_addr,
1610 u_int16_t dst_call_id)
1613 struct alias_link *lnk;
1615 LIBALIAS_LOCK_ASSERT(la);
1616 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1617 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1618 if (lnk->link_type == LINK_PPTP &&
1619 lnk->src_addr.s_addr == src_addr.s_addr &&
1620 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1621 lnk->dst_port == dst_call_id)
1629 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1630 struct in_addr alias_addr,
1631 u_int16_t dst_call_id)
1634 struct alias_link *lnk;
1636 LIBALIAS_LOCK_ASSERT(la);
1637 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1638 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1639 if (lnk->link_type == LINK_PPTP &&
1640 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1641 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1642 lnk->dst_port == dst_call_id)
1650 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1651 struct in_addr alias_addr,
1652 u_int16_t alias_call_id)
1654 struct alias_link *lnk;
1656 LIBALIAS_LOCK_ASSERT(la);
1657 lnk = FindLinkIn(la, dst_addr, alias_addr,
1658 0 /* any */ , alias_call_id,
1667 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1668 struct in_addr dst_addr,
1674 struct alias_link *lnk;
1676 LIBALIAS_LOCK_ASSERT(la);
1679 link_type = LINK_UDP;
1682 link_type = LINK_TCP;
1689 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1692 struct in_addr alias_addr;
1694 alias_addr = FindAliasAddress(la, src_addr);
1695 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1696 src_port, 0, alias_port,
1704 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1706 struct alias_link *lnk;
1708 LIBALIAS_LOCK_ASSERT(la);
1709 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1710 0, 0, LINK_ADDR, 0);
1712 la->newDefaultLink = 1;
1713 if (la->targetAddress.s_addr == INADDR_ANY)
1714 return (alias_addr);
1715 else if (la->targetAddress.s_addr == INADDR_NONE)
1716 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1717 la->aliasAddress : alias_addr;
1719 return (la->targetAddress);
1721 if (lnk->server != NULL) { /* LSNAT link */
1722 struct in_addr src_addr;
1724 src_addr = lnk->server->addr;
1725 lnk->server = lnk->server->next;
1727 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1728 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1729 la->aliasAddress : alias_addr;
1731 return (lnk->src_addr);
1737 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1739 struct alias_link *lnk;
1741 LIBALIAS_LOCK_ASSERT(la);
1742 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1743 0, 0, LINK_ADDR, 0);
1745 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1746 la->aliasAddress : original_addr;
1748 if (lnk->alias_addr.s_addr == INADDR_ANY)
1749 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1750 la->aliasAddress : original_addr;
1752 return (lnk->alias_addr);
1757 /* External routines for getting or changing link data
1758 (external to alias_db.c, but internal to alias*.c)
1760 SetFragmentData(), GetFragmentData()
1761 SetFragmentPtr(), GetFragmentPtr()
1762 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1763 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1764 GetOriginalPort(), GetAliasPort()
1765 SetAckModified(), GetAckModified()
1766 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1767 SetProtocolFlags(), GetProtocolFlags()
1773 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1775 lnk->data.frag_addr = src_addr;
1780 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1782 *src_addr = lnk->data.frag_addr;
1787 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1789 lnk->data.frag_ptr = fptr;
1794 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1796 *fptr = lnk->data.frag_ptr;
1801 SetStateIn(struct alias_link *lnk, int state)
1803 /* TCP input state */
1805 case ALIAS_TCP_STATE_DISCONNECTED:
1806 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1807 lnk->expire_time = TCP_EXPIRE_DEAD;
1809 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1811 case ALIAS_TCP_STATE_CONNECTED:
1812 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1813 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1817 panic("libalias:SetStateIn() unknown state");
1822 lnk->data.tcp->state.in = state;
1827 SetStateOut(struct alias_link *lnk, int state)
1829 /* TCP output state */
1831 case ALIAS_TCP_STATE_DISCONNECTED:
1832 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1833 lnk->expire_time = TCP_EXPIRE_DEAD;
1835 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1837 case ALIAS_TCP_STATE_CONNECTED:
1838 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1839 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1843 panic("libalias:SetStateOut() unknown state");
1848 lnk->data.tcp->state.out = state;
1853 GetStateIn(struct alias_link *lnk)
1855 /* TCP input state */
1856 return (lnk->data.tcp->state.in);
1861 GetStateOut(struct alias_link *lnk)
1863 /* TCP output state */
1864 return (lnk->data.tcp->state.out);
1869 GetOriginalAddress(struct alias_link *lnk)
1871 if (lnk->src_addr.s_addr == INADDR_ANY)
1872 return (lnk->la->aliasAddress);
1874 return (lnk->src_addr);
1879 GetDestAddress(struct alias_link *lnk)
1881 return (lnk->dst_addr);
1886 GetAliasAddress(struct alias_link *lnk)
1888 if (lnk->alias_addr.s_addr == INADDR_ANY)
1889 return (lnk->la->aliasAddress);
1891 return (lnk->alias_addr);
1896 GetDefaultAliasAddress(struct libalias *la)
1899 LIBALIAS_LOCK_ASSERT(la);
1900 return (la->aliasAddress);
1905 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1908 LIBALIAS_LOCK_ASSERT(la);
1909 la->aliasAddress = alias_addr;
1914 GetOriginalPort(struct alias_link *lnk)
1916 return (lnk->src_port);
1921 GetAliasPort(struct alias_link *lnk)
1923 return (lnk->alias_port);
1928 GetDestPort(struct alias_link *lnk)
1930 return (lnk->dst_port);
1936 SetAckModified(struct alias_link *lnk)
1938 /* Indicate that ACK numbers have been modified in a TCP connection */
1939 lnk->data.tcp->state.ack_modified = 1;
1944 GetProxyAddress(struct alias_link *lnk)
1946 return (lnk->proxy_addr);
1951 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1953 lnk->proxy_addr = addr;
1958 GetProxyPort(struct alias_link *lnk)
1960 return (lnk->proxy_port);
1965 SetProxyPort(struct alias_link *lnk, u_short port)
1967 lnk->proxy_port = port;
1972 GetAckModified(struct alias_link *lnk)
1974 /* See if ACK numbers have been modified */
1975 return (lnk->data.tcp->state.ack_modified);
1980 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1983 Find out how much the ACK number has been altered for an incoming
1984 TCP packet. To do this, a circular list of ACK numbers where the TCP
1985 packet size was altered is searched.
1989 int delta, ack_diff_min;
1993 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1994 struct ack_data_record x;
1996 x = lnk->data.tcp->ack[i];
1997 if (x.active == 1) {
2000 ack_diff = SeqDiff(x.ack_new, ack);
2001 if (ack_diff >= 0) {
2002 if (ack_diff_min >= 0) {
2003 if (ack_diff < ack_diff_min) {
2005 ack_diff_min = ack_diff;
2009 ack_diff_min = ack_diff;
2019 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
2022 Find out how much the sequence number has been altered for an outgoing
2023 TCP packet. To do this, a circular list of ACK numbers where the TCP
2024 packet size was altered is searched.
2028 int delta, seq_diff_min;
2032 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2033 struct ack_data_record x;
2035 x = lnk->data.tcp->ack[i];
2036 if (x.active == 1) {
2039 seq_diff = SeqDiff(x.ack_old, seq);
2040 if (seq_diff >= 0) {
2041 if (seq_diff_min >= 0) {
2042 if (seq_diff < seq_diff_min) {
2044 seq_diff_min = seq_diff;
2048 seq_diff_min = seq_diff;
2058 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
2059 u_long th_seq, u_int th_off)
2062 When a TCP packet has been altered in length, save this
2063 information in a circular list. If enough packets have
2064 been altered, then this list will begin to overwrite itself.
2067 struct ack_data_record x;
2068 int hlen, tlen, dlen;
2071 hlen = (ip_hl + th_off) << 2;
2072 tlen = ntohs(ip_len);
2075 x.ack_old = htonl(ntohl(th_seq) + dlen);
2076 x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
2080 i = lnk->data.tcp->state.index;
2081 lnk->data.tcp->ack[i] = x;
2084 if (i == N_LINK_TCP_DATA)
2085 lnk->data.tcp->state.index = 0;
2087 lnk->data.tcp->state.index = i;
2091 SetExpire(struct alias_link *lnk, int expire)
2094 lnk->flags &= ~LINK_PERMANENT;
2096 } else if (expire == -1) {
2097 lnk->flags |= LINK_PERMANENT;
2098 } else if (expire > 0) {
2099 lnk->expire_time = expire;
2101 #ifdef LIBALIAS_DEBUG
2102 fprintf(stderr, "PacketAlias/SetExpire(): ");
2103 fprintf(stderr, "error in expire parameter\n");
2109 ClearCheckNewLink(struct libalias *la)
2112 LIBALIAS_LOCK_ASSERT(la);
2113 la->newDefaultLink = 0;
2117 SetProtocolFlags(struct alias_link *lnk, int pflags)
2120 lnk->pflags = pflags;
2124 GetProtocolFlags(struct alias_link *lnk)
2127 return (lnk->pflags);
2131 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2133 struct libalias *la = lnk->la;
2135 LIBALIAS_LOCK_ASSERT(la);
2136 la->deleteAllLinks = 1;
2137 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2138 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2139 la->deleteAllLinks = 0;
2143 /* Miscellaneous Functions
2146 InitPacketAliasLog()
2147 UninitPacketAliasLog()
2151 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2152 is called to find and remove timed-out aliasing links. Logic exists
2153 to sweep through the entire table and linked list structure
2156 (prototype in alias_local.h)
2160 HouseKeeping(struct libalias *la)
2167 LIBALIAS_LOCK_ASSERT(la);
2169 * Save system time (seconds) in global variable timeStamp for use
2170 * by other functions. This is done so as not to unnecessarily
2171 * waste timeline by making system calls.
2174 la->timeStamp = time_uptime;
2176 gettimeofday(&tv, NULL);
2177 la->timeStamp = tv.tv_sec;
2180 /* Compute number of spokes (output table link chains) to cover */
2181 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2182 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2184 /* Handle different cases */
2186 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2187 n = ALIAS_CLEANUP_MAX_SPOKES;
2188 la->lastCleanupTime = la->timeStamp;
2189 for (i = 0; i < n; i++)
2190 IncrementalCleanup(la);
2192 #ifdef LIBALIAS_DEBUG
2193 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2194 fprintf(stderr, "something unexpected in time values\n");
2196 la->lastCleanupTime = la->timeStamp;
2200 /* Init the log file and enable logging */
2202 InitPacketAliasLog(struct libalias *la)
2205 LIBALIAS_LOCK_ASSERT(la);
2206 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2208 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2211 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2212 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2215 return (ENOMEM); /* log initialization failed */
2216 la->packetAliasMode |= PKT_ALIAS_LOG;
2222 /* Close the log-file and disable logging. */
2224 UninitPacketAliasLog(struct libalias *la)
2227 LIBALIAS_LOCK_ASSERT(la);
2232 fclose(la->logDesc);
2236 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2239 /* Outside world interfaces
2241 -- "outside world" means other than alias*.c routines --
2243 PacketAliasRedirectPort()
2244 PacketAliasAddServer()
2245 PacketAliasRedirectProto()
2246 PacketAliasRedirectAddr()
2247 PacketAliasRedirectDynamic()
2248 PacketAliasRedirectDelete()
2249 PacketAliasSetAddress()
2252 PacketAliasSetMode()
2254 (prototypes in alias.h)
2257 /* Redirection from a specific public addr:port to a
2258 private addr:port */
2260 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2261 struct in_addr dst_addr, u_short dst_port,
2262 struct in_addr alias_addr, u_short alias_port,
2266 struct alias_link *lnk;
2271 link_type = LINK_UDP;
2274 link_type = LINK_TCP;
2277 link_type = LINK_SCTP;
2280 #ifdef LIBALIAS_DEBUG
2281 fprintf(stderr, "PacketAliasRedirectPort(): ");
2282 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
2288 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2289 src_port, dst_port, alias_port,
2293 lnk->flags |= LINK_PERMANENT;
2295 #ifdef LIBALIAS_DEBUG
2297 fprintf(stderr, "PacketAliasRedirectPort(): "
2298 "call to AddLink() failed\n");
2303 LIBALIAS_UNLOCK(la);
2307 /* Add server to the pool of servers */
2309 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2311 struct server *server;
2317 server = malloc(sizeof(struct server));
2319 if (server != NULL) {
2320 struct server *head;
2322 server->addr = addr;
2323 server->port = port;
2327 server->next = server;
2331 for (s = head; s->next != head; s = s->next);
2333 server->next = head;
2335 lnk->server = server;
2340 LIBALIAS_UNLOCK(la);
2344 /* Redirect packets of a given IP protocol from a specific
2345 public address to a private address */
2347 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2348 struct in_addr dst_addr,
2349 struct in_addr alias_addr,
2352 struct alias_link *lnk;
2355 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2356 NO_SRC_PORT, NO_DEST_PORT, 0,
2360 lnk->flags |= LINK_PERMANENT;
2362 #ifdef LIBALIAS_DEBUG
2364 fprintf(stderr, "PacketAliasRedirectProto(): "
2365 "call to AddLink() failed\n");
2369 LIBALIAS_UNLOCK(la);
2373 /* Static address translation */
2375 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2376 struct in_addr alias_addr)
2378 struct alias_link *lnk;
2381 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2386 lnk->flags |= LINK_PERMANENT;
2388 #ifdef LIBALIAS_DEBUG
2390 fprintf(stderr, "PacketAliasRedirectAddr(): "
2391 "call to AddLink() failed\n");
2395 LIBALIAS_UNLOCK(la);
2400 /* Mark the aliasing link dynamic */
2402 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2409 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2412 lnk->flags &= ~LINK_PERMANENT;
2415 LIBALIAS_UNLOCK(la);
2421 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2423 /* This is a dangerous function to put in the API,
2424 because an invalid pointer can crash the program. */
2427 la->deleteAllLinks = 1;
2429 la->deleteAllLinks = 0;
2430 LIBALIAS_UNLOCK(la);
2435 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2439 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2440 && la->aliasAddress.s_addr != addr.s_addr)
2441 CleanupAliasData(la);
2443 la->aliasAddress = addr;
2444 LIBALIAS_UNLOCK(la);
2449 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2453 la->targetAddress = target_addr;
2454 LIBALIAS_UNLOCK(la);
2461 while (!LIST_EMPTY(&instancehead))
2462 LibAliasUninit(LIST_FIRST(&instancehead));
2466 LibAliasInit(struct libalias *la)
2475 #undef malloc /* XXX: ugly */
2476 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2478 la = calloc(sizeof *la, 1);
2483 #ifndef _KERNEL /* kernel cleans up on module unload */
2484 if (LIST_EMPTY(&instancehead))
2487 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2490 la->timeStamp = time_uptime;
2491 la->lastCleanupTime = time_uptime;
2493 gettimeofday(&tv, NULL);
2494 la->timeStamp = tv.tv_sec;
2495 la->lastCleanupTime = tv.tv_sec;
2498 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2499 LIST_INIT(&la->linkTableOut[i]);
2500 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2501 LIST_INIT(&la->linkTableIn[i]);
2505 LIBALIAS_LOCK_INIT(la);
2509 la->deleteAllLinks = 1;
2510 CleanupAliasData(la);
2511 la->deleteAllLinks = 0;
2518 la->aliasAddress.s_addr = INADDR_ANY;
2519 la->targetAddress.s_addr = INADDR_ANY;
2521 la->icmpLinkCount = 0;
2522 la->udpLinkCount = 0;
2523 la->tcpLinkCount = 0;
2524 la->sctpLinkCount = 0;
2525 la->pptpLinkCount = 0;
2526 la->protoLinkCount = 0;
2527 la->fragmentIdLinkCount = 0;
2528 la->fragmentPtrLinkCount = 0;
2531 la->cleanupIndex = 0;
2533 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2534 #ifndef NO_USE_SOCKETS
2535 | PKT_ALIAS_USE_SOCKETS
2537 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2539 la->fireWallFD = -1;
2542 LibAliasRefreshModules();
2544 LIBALIAS_UNLOCK(la);
2549 LibAliasUninit(struct libalias *la)
2556 la->deleteAllLinks = 1;
2557 CleanupAliasData(la);
2558 la->deleteAllLinks = 0;
2559 UninitPacketAliasLog(la);
2563 LIST_REMOVE(la, instancelist);
2564 LIBALIAS_UNLOCK(la);
2565 LIBALIAS_LOCK_DESTROY(la);
2569 /* Change mode for some operations */
2572 struct libalias *la,
2573 unsigned int flags, /* Which state to bring flags to */
2574 unsigned int mask /* Mask of which flags to affect (use 0 to
2575 * do a probe for flag values) */
2581 /* Enable logging? */
2582 if (flags & mask & PKT_ALIAS_LOG) {
2584 if (InitPacketAliasLog(la) == ENOMEM)
2587 /* _Disable_ logging? */
2588 if (~flags & mask & PKT_ALIAS_LOG) {
2589 UninitPacketAliasLog(la);
2592 /* Start punching holes in the firewall? */
2593 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2596 /* Stop punching holes in the firewall? */
2597 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2602 /* Other flags can be set/cleared without special action */
2603 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2604 res = la->packetAliasMode;
2606 LIBALIAS_UNLOCK(la);
2612 LibAliasCheckNewLink(struct libalias *la)
2617 res = la->newDefaultLink;
2618 LIBALIAS_UNLOCK(la);
2626 Code to support firewall punching. This shouldn't really be in this
2627 file, but making variables global is evil too.
2630 /* Firewall include files */
2632 #include <netinet/ip_fw.h>
2637 * helper function, updates the pointer to cmd with the length
2638 * of the current command, and also cleans up the first word of
2639 * the new command in case it has been clobbered before.
2642 next_cmd(ipfw_insn * cmd)
2645 bzero(cmd, sizeof(*cmd));
2650 * A function to fill simple commands of size 1.
2651 * Existing flags are preserved.
2654 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2655 int flags, u_int16_t arg)
2657 cmd->opcode = opcode;
2658 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2660 return next_cmd(cmd);
2664 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2666 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2668 cmd->addr.s_addr = addr;
2669 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2673 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2675 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2677 cmd->ports[0] = cmd->ports[1] = port;
2678 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2682 fill_rule(void *buf, int bufsize, int rulenum,
2683 enum ipfw_opcodes action, int proto,
2684 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2686 struct ip_fw *rule = (struct ip_fw *)buf;
2687 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2689 bzero(buf, bufsize);
2690 rule->rulenum = rulenum;
2692 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2693 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2694 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2695 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2696 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2698 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2699 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2701 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2703 return ((char *)cmd - (char *)buf);
2706 static void ClearAllFWHoles(struct libalias *la);
2709 #define fw_setfield(la, field, num) \
2711 (field)[(num) - la->fireWallBaseNum] = 1; \
2712 } /*lint -save -e717 */ while(0)/* lint -restore */
2714 #define fw_clrfield(la, field, num) \
2716 (field)[(num) - la->fireWallBaseNum] = 0; \
2717 } /*lint -save -e717 */ while(0)/* lint -restore */
2719 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2722 InitPunchFW(struct libalias *la)
2725 la->fireWallField = malloc(la->fireWallNumNums);
2726 if (la->fireWallField) {
2727 memset(la->fireWallField, 0, la->fireWallNumNums);
2728 if (la->fireWallFD < 0) {
2729 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2731 ClearAllFWHoles(la);
2732 la->fireWallActiveNum = la->fireWallBaseNum;
2737 UninitPunchFW(struct libalias *la)
2740 ClearAllFWHoles(la);
2741 if (la->fireWallFD >= 0)
2742 close(la->fireWallFD);
2743 la->fireWallFD = -1;
2744 if (la->fireWallField)
2745 free(la->fireWallField);
2746 la->fireWallField = NULL;
2747 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2750 /* Make a certain link go through the firewall */
2752 PunchFWHole(struct alias_link *lnk)
2754 struct libalias *la;
2755 int r; /* Result code */
2756 struct ip_fw rule; /* On-the-fly built rule */
2757 int fwhole; /* Where to punch hole */
2761 /* Don't do anything unless we are asked to */
2762 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2763 la->fireWallFD < 0 ||
2764 lnk->link_type != LINK_TCP)
2767 memset(&rule, 0, sizeof rule);
2771 /* Find empty slot */
2772 for (fwhole = la->fireWallActiveNum;
2773 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2774 fw_tstfield(la, la->fireWallField, fwhole);
2776 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2777 for (fwhole = la->fireWallBaseNum;
2778 fwhole < la->fireWallActiveNum &&
2779 fw_tstfield(la, la->fireWallField, fwhole);
2781 if (fwhole == la->fireWallActiveNum) {
2782 /* No rule point empty - we can't punch more holes. */
2783 la->fireWallActiveNum = la->fireWallBaseNum;
2784 #ifdef LIBALIAS_DEBUG
2785 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2790 /* Start next search at next position */
2791 la->fireWallActiveNum = fwhole + 1;
2794 * generate two rules of the form
2796 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2797 * accept tcp from DAddr DPort to OAddr OPort
2799 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2800 u_int32_t rulebuf[255];
2803 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2804 O_ACCEPT, IPPROTO_TCP,
2805 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2806 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2807 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2809 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2811 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2812 O_ACCEPT, IPPROTO_TCP,
2813 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2814 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2815 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2817 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2820 /* Indicate hole applied */
2821 lnk->data.tcp->fwhole = fwhole;
2822 fw_setfield(la, la->fireWallField, fwhole);
2825 /* Remove a hole in a firewall associated with a particular alias
2826 lnk. Calling this too often is harmless. */
2828 ClearFWHole(struct alias_link *lnk)
2830 struct libalias *la;
2833 if (lnk->link_type == LINK_TCP) {
2834 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2841 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2842 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2843 &fwhole, sizeof fwhole));
2844 fw_clrfield(la, la->fireWallField, fwhole);
2845 lnk->data.tcp->fwhole = -1;
2849 /* Clear out the entire range dedicated to firewall holes. */
2851 ClearAllFWHoles(struct libalias *la)
2853 struct ip_fw rule; /* On-the-fly built rule */
2856 if (la->fireWallFD < 0)
2859 memset(&rule, 0, sizeof rule);
2860 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2863 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2865 /* XXX: third arg correct here ? /phk */
2866 memset(la->fireWallField, 0, la->fireWallNumNums);
2869 #endif /* !NO_FW_PUNCH */
2872 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2877 la->fireWallBaseNum = base;
2878 la->fireWallNumNums = num;
2880 LIBALIAS_UNLOCK(la);
2884 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2888 la->skinnyPort = port;
2889 LIBALIAS_UNLOCK(la);
2893 * Find the address to redirect incoming packets
2896 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm)
2898 struct alias_link *lnk;
2899 struct in_addr redir;
2901 LIBALIAS_LOCK_ASSERT(la);
2902 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2903 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2905 return(lnk->src_addr); /* port redirect */
2907 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2908 if (redir.s_addr == la->aliasAddress.s_addr ||
2909 redir.s_addr == la->targetAddress.s_addr) { /* No address found */
2910 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2911 NO_DEST_PORT, 0, LINK_SCTP, 1);
2913 return(lnk->src_addr); /* redirect proto */
2915 return(redir); /* address redirect */