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.
52 Initial version: August, 1996 (cjm)
54 Version 1.4: September 16, 1996 (cjm)
55 Facility for handling incoming links added.
57 Version 1.6: September 18, 1996 (cjm)
58 ICMP data handling simplified.
60 Version 1.7: January 9, 1997 (cjm)
61 Fragment handling simplified.
62 Saves pointers for unresolved fragments.
63 Permits links for unspecified remote ports
64 or unspecified remote addresses.
65 Fixed bug which did not properly zero port
66 table entries after a link was deleted.
67 Cleaned up some obsolete comments.
69 Version 1.8: January 14, 1997 (cjm)
70 Fixed data type error in StartPoint().
71 (This error did not exist prior to v1.7
72 and was discovered and fixed by Ari Suutari)
74 Version 1.9: February 1, 1997
75 Optionally, connections initiated from packet aliasing host
76 machine will will not have their port number aliased unless it
77 conflicts with an aliasing port already being used. (cjm)
79 All options earlier being #ifdef'ed are now available through
80 a new interface, SetPacketAliasMode(). This allows run time
81 control (which is now available in PPP+pktAlias through the
82 'alias' keyword). (ee)
84 Added ability to create an alias port without
85 either destination address or port specified.
86 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
88 Removed K&R style function headers
89 and general cleanup. (ee)
91 Added packetAliasMode to replace compiler #defines's (ee)
93 Allocates sockets for partially specified
94 ports if ALIAS_USE_SOCKETS defined. (cjm)
96 Version 2.0: March, 1997
97 SetAliasAddress() will now clean up alias links
98 if the aliasing address is changed. (cjm)
100 PacketAliasPermanentLink() function added to support permanent
101 links. (J. Fortes suggested the need for this.)
104 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
106 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
109 These permanent links allow for incoming connections to
110 machines on the local network. They can be given with a
111 user-chosen amount of specificity, with increasing specificity
112 meaning more security. (cjm)
114 Quite a bit of rework to the basic engine. The portTable[]
115 array, which kept track of which ports were in use was replaced
116 by a table/linked list structure. (cjm)
118 SetExpire() function added. (cjm)
120 DeleteLink() no longer frees memory association with a pointer
121 to a fragment (this bug was first recognized by E. Eklund in
124 Version 2.1: May, 1997 (cjm)
125 Packet aliasing engine reworked so that it can handle
126 multiple external addresses rather than just a single
129 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
130 added to the API. The first function is a more generalized
131 version of PacketAliasPermanentLink(). The second function
132 implements static network address translation.
134 Version 3.2: July, 2000 (salander and satoh)
135 Added FindNewPortGroup to get contiguous range of port values.
137 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
138 link but not actually add one.
140 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
141 except that the alias port (from FindNewPortGroup) is provided
144 See HISTORY file for additional revisions.
148 #include <machine/stdarg.h>
149 #include <sys/param.h>
150 #include <sys/kernel.h>
151 #include <sys/systm.h>
152 #include <sys/lock.h>
153 #include <sys/module.h>
154 #include <sys/rwlock.h>
155 #include <sys/syslog.h>
160 #include <sys/errno.h>
161 #include <sys/time.h>
165 #include <sys/socket.h>
166 #include <netinet/tcp.h>
169 #include <netinet/libalias/alias.h>
170 #include <netinet/libalias/alias_local.h>
171 #include <netinet/libalias/alias_mod.h>
175 #include "alias_local.h"
176 #include "alias_mod.h"
179 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
183 Constants (note: constants are also defined
184 near relevant functions or structs)
187 /* Parameters used for cleanup of expired links */
188 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
189 #define ALIAS_CLEANUP_INTERVAL_SECS 64
190 #define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
192 /* Timeouts (in seconds) for different link types */
193 #define ICMP_EXPIRE_TIME 60
194 #define UDP_EXPIRE_TIME 60
195 #define PROTO_EXPIRE_TIME 60
196 #define FRAGMENT_ID_EXPIRE_TIME 10
197 #define FRAGMENT_PTR_EXPIRE_TIME 30
199 /* TCP link expire time for different cases */
200 /* When the link has been used and closed - minimal grace time to
201 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
202 #ifndef TCP_EXPIRE_DEAD
203 #define TCP_EXPIRE_DEAD 10
206 /* When the link has been used and closed on one side - the other side
207 is allowed to still send data */
208 #ifndef TCP_EXPIRE_SINGLEDEAD
209 #define TCP_EXPIRE_SINGLEDEAD 90
212 /* When the link isn't yet up */
213 #ifndef TCP_EXPIRE_INITIAL
214 #define TCP_EXPIRE_INITIAL 300
217 /* When the link is up */
218 #ifndef TCP_EXPIRE_CONNECTED
219 #define TCP_EXPIRE_CONNECTED 86400
223 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
224 These constants can be anything except zero, which indicates an
225 unknown port number. */
227 #define NO_DEST_PORT 1
228 #define NO_SRC_PORT 1
234 The fundamental data structure used in this program is
235 "struct alias_link". Whenever a TCP connection is made,
236 a UDP datagram is sent out, or an ICMP echo request is made,
237 a link record is made (if it has not already been created).
238 The link record is identified by the source address/port
239 and the destination address/port. In the case of an ICMP
240 echo request, the source port is treated as being equivalent
241 with the 16-bit ID number of the ICMP packet.
243 The link record also can store some auxiliary data. For
244 TCP connections that have had sequence and acknowledgment
245 modifications, data space is available to track these changes.
246 A state field is used to keep track in changes to the TCP
247 connection state. ID numbers of fragments can also be
248 stored in the auxiliary space. Pointers to unresolved
249 fragments can also be stored.
251 The link records support two independent chainings. Lookup
252 tables for input and out tables hold the initial pointers
253 the link chains. On input, the lookup table indexes on alias
254 port and link type. On output, the lookup table indexes on
255 source address, destination address, source port, destination
259 struct ack_data_record { /* used to save changes to ACK/sequence
267 struct tcp_state { /* Information about TCP connection */
268 int in; /* State for outside -> inside */
269 int out; /* State for inside -> outside */
270 int index; /* Index to ACK data array */
271 int ack_modified; /* Indicates whether ACK and
272 * sequence numbers */
276 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
277 * saved for a modified TCP stream */
279 struct tcp_state state;
280 struct ack_data_record ack[N_LINK_TCP_DATA];
281 int fwhole; /* Which firewall record is used for this
285 struct server { /* LSNAT server pool (circular list) */
291 struct alias_link { /* Main data structure */
293 struct in_addr src_addr; /* Address and port information */
294 struct in_addr dst_addr;
295 struct in_addr alias_addr;
296 struct in_addr proxy_addr;
301 struct server *server;
303 int link_type; /* Type of link: TCP, UDP, ICMP,
306 /* values for link_type */
307 #define LINK_ICMP IPPROTO_ICMP
308 #define LINK_UDP IPPROTO_UDP
309 #define LINK_TCP IPPROTO_TCP
310 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
311 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
312 #define LINK_ADDR (IPPROTO_MAX + 3)
313 #define LINK_PPTP (IPPROTO_MAX + 4)
315 int flags; /* indicates special characteristics */
316 int pflags; /* protocol-specific flags */
319 #define LINK_UNKNOWN_DEST_PORT 0x01
320 #define LINK_UNKNOWN_DEST_ADDR 0x02
321 #define LINK_PERMANENT 0x04
322 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
323 #define LINK_UNFIREWALLED 0x08
325 int timestamp; /* Time link was last accessed */
326 int expire_time; /* Expire time for link */
327 #ifndef NO_USE_SOCKETS
328 int sockfd; /* socket descriptor */
330 LIST_ENTRY (alias_link) list_out; /* Linked list of
332 LIST_ENTRY (alias_link) list_in; /* input and output
335 union { /* Auxiliary data */
337 struct in_addr frag_addr;
342 /* Clean up procedure. */
343 static void finishoff(void);
345 /* Kernel module definition. */
347 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
349 MODULE_VERSION(libalias, 1);
352 alias_mod_handler(module_t mod, int type, void *data)
366 static moduledata_t alias_mod = {
367 "alias", alias_mod_handler, NULL
370 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
373 /* Internal utility routines (used only in alias_db.c)
375 Lookup table starting points:
376 StartPointIn() -- link table initial search point for
378 StartPointOut() -- link table initial search point for
382 SeqDiff() -- difference between two TCP sequences
383 ShowAliasStats() -- send alias statistics to a monitor file
387 /* Local prototypes */
388 static u_int StartPointIn(struct in_addr, u_short, int);
391 StartPointOut(struct in_addr, struct in_addr,
392 u_short, u_short, int);
394 static int SeqDiff(u_long, u_long);
397 /* Firewall control */
398 static void InitPunchFW(struct libalias *);
399 static void UninitPunchFW(struct libalias *);
400 static void ClearFWHole(struct alias_link *);
404 /* Log file control */
405 static void ShowAliasStats(struct libalias *);
406 static int InitPacketAliasLog(struct libalias *);
407 static void UninitPacketAliasLog(struct libalias *);
409 void SctpShowAliasStats(struct libalias *la);
412 StartPointIn(struct in_addr alias_addr,
418 n = alias_addr.s_addr;
419 if (link_type != LINK_PPTP)
422 return (n % LINK_TABLE_IN_SIZE);
427 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
428 u_short src_port, u_short dst_port, int link_type)
433 n += dst_addr.s_addr;
434 if (link_type != LINK_PPTP) {
440 return (n % LINK_TABLE_OUT_SIZE);
445 SeqDiff(u_long x, u_long y)
447 /* Return the difference between two TCP sequence numbers */
450 This function is encapsulated in case there are any unusual
451 arithmetic conditions that need to be considered.
454 return (ntohl(y) - ntohl(x));
460 AliasLog(char *str, const char *format, ...)
464 va_start(ap, format);
465 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
470 AliasLog(FILE *stream, const char *format, ...)
474 va_start(ap, format);
475 vfprintf(stream, format, ap);
482 ShowAliasStats(struct libalias *la)
485 LIBALIAS_LOCK_ASSERT(la);
486 /* Used for debugging */
488 int tot = la->icmpLinkCount + la->udpLinkCount +
489 (la->sctpLinkCount>>1) + /* sctp counts half associations */
490 la->tcpLinkCount + la->pptpLinkCount +
491 la->protoLinkCount + la->fragmentIdLinkCount +
492 la->fragmentPtrLinkCount;
494 AliasLog(la->logDesc,
495 "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
499 la->sctpLinkCount>>1, /* sctp counts half associations */
502 la->fragmentIdLinkCount,
503 la->fragmentPtrLinkCount, tot);
505 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
510 void SctpShowAliasStats(struct libalias *la)
517 /* Internal routines for finding, deleting and adding links
520 GetNewPort() -- find and reserve new alias port number
521 GetSocket() -- try to allocate a socket for a given port
523 Link creation and deletion:
524 CleanupAliasData() - remove all link chains from lookup table
525 IncrementalCleanup() - look for stale links in a single chain
526 DeleteLink() - remove link
528 ReLink() - change link
531 FindLinkOut() - find link for outgoing packets
532 FindLinkIn() - find link for incoming packets
535 FindNewPortGroup() - find an available group of ports
538 /* Local prototypes */
539 static int GetNewPort(struct libalias *, struct alias_link *, int);
540 #ifndef NO_USE_SOCKETS
541 static u_short GetSocket(struct libalias *, u_short, int *, int);
543 static void CleanupAliasData(struct libalias *);
545 static void IncrementalCleanup(struct libalias *);
547 static void DeleteLink(struct alias_link *);
549 static struct alias_link *
550 ReLink(struct alias_link *,
551 struct in_addr, struct in_addr, struct in_addr,
552 u_short, u_short, int, int);
554 static struct alias_link *
555 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
557 static struct alias_link *
558 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
561 #define ALIAS_PORT_BASE 0x08000
562 #define ALIAS_PORT_MASK 0x07fff
563 #define ALIAS_PORT_MASK_EVEN 0x07ffe
564 #define GET_NEW_PORT_MAX_ATTEMPTS 20
566 #define FIND_EVEN_ALIAS_BASE 1
568 /* GetNewPort() allocates port numbers. Note that if a port number
569 is already in use, that does not mean that it cannot be used by
570 another link concurrently. This is because GetNewPort() looks for
571 unused triplets: (dest addr, dest port, alias port). */
574 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
581 LIBALIAS_LOCK_ASSERT(la);
583 Description of alias_port_param for GetNewPort(). When
584 this parameter is zero or positive, it precisely specifies
585 the port number. GetNewPort() will return this number
586 without check that it is in use.
588 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
589 selected port number.
592 if (alias_port_param == GET_ALIAS_PORT) {
594 * The aliasing port is automatically selected by one of
597 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
599 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
601 * When the PKT_ALIAS_SAME_PORTS option is chosen,
602 * the first try will be the actual source port. If
603 * this is already in use, the remainder of the
604 * trials will be random.
606 port_net = lnk->src_port;
607 port_sys = ntohs(port_net);
608 } else if (la->aliasPortLower) {
609 /* First trial is a random port in the aliasing range. */
610 port_sys = la->aliasPortLower +
611 (arc4random() % la->aliasPortLength);
612 port_net = htons(port_sys);
614 /* First trial and all subsequent are random. */
615 port_sys = arc4random() & ALIAS_PORT_MASK;
616 port_sys += ALIAS_PORT_BASE;
617 port_net = htons(port_sys);
619 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
620 lnk->alias_port = (u_short) alias_port_param;
623 #ifdef LIBALIAS_DEBUG
624 fprintf(stderr, "PacketAlias/GetNewPort(): ");
625 fprintf(stderr, "input parameter error\n");
631 /* Port number search */
632 for (i = 0; i < max_trials; i++) {
634 struct alias_link *search_result;
636 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
637 lnk->dst_port, port_net,
640 if (search_result == NULL)
642 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
643 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
649 #ifndef NO_USE_SOCKETS
650 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
651 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
652 && ((lnk->link_type == LINK_TCP) ||
653 (lnk->link_type == LINK_UDP))) {
654 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
655 lnk->alias_port = port_net;
660 lnk->alias_port = port_net;
662 #ifndef NO_USE_SOCKETS
666 if (la->aliasPortLower) {
667 port_sys = la->aliasPortLower +
668 (arc4random() % la->aliasPortLength);
669 port_net = htons(port_sys);
671 port_sys = arc4random() & ALIAS_PORT_MASK;
672 port_sys += ALIAS_PORT_BASE;
673 port_net = htons(port_sys);
677 #ifdef LIBALIAS_DEBUG
678 fprintf(stderr, "PacketAlias/GetnewPort(): ");
679 fprintf(stderr, "could not find free port\n");
685 #ifndef NO_USE_SOCKETS
687 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
691 struct sockaddr_in sock_addr;
693 LIBALIAS_LOCK_ASSERT(la);
694 if (link_type == LINK_TCP)
695 sock = socket(AF_INET, SOCK_STREAM, 0);
696 else if (link_type == LINK_UDP)
697 sock = socket(AF_INET, SOCK_DGRAM, 0);
699 #ifdef LIBALIAS_DEBUG
700 fprintf(stderr, "PacketAlias/GetSocket(): ");
701 fprintf(stderr, "incorrect link type\n");
707 #ifdef LIBALIAS_DEBUG
708 fprintf(stderr, "PacketAlias/GetSocket(): ");
709 fprintf(stderr, "socket() error %d\n", *sockfd);
713 sock_addr.sin_family = AF_INET;
714 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
715 sock_addr.sin_port = port_net;
718 (struct sockaddr *)&sock_addr,
731 /* FindNewPortGroup() returns a base port number for an available
732 range of contiguous port numbers. Note that if a port number
733 is already in use, that does not mean that it cannot be used by
734 another link concurrently. This is because FindNewPortGroup()
735 looks for unused triplets: (dest addr, dest port, alias port). */
738 FindNewPortGroup(struct libalias *la,
739 struct in_addr dst_addr,
740 struct in_addr alias_addr,
752 LIBALIAS_LOCK_ASSERT(la);
754 * Get link_type from protocol
759 link_type = LINK_UDP;
762 link_type = LINK_TCP;
770 * The aliasing port is automatically selected by one of two
773 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
775 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
777 * When the ALIAS_SAME_PORTS option is chosen, the first
778 * try will be the actual source port. If this is already
779 * in use, the remainder of the trials will be random.
781 port_sys = ntohs(src_port);
785 /* First trial and all subsequent are random. */
786 if (align == FIND_EVEN_ALIAS_BASE)
787 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
789 port_sys = arc4random() & ALIAS_PORT_MASK;
791 port_sys += ALIAS_PORT_BASE;
794 /* Port number search */
795 for (i = 0; i < max_trials; i++) {
797 struct alias_link *search_result;
799 for (j = 0; j < port_count; j++)
800 if ((search_result = FindLinkIn(la, dst_addr,
801 alias_addr, dst_port, htons(port_sys + j),
802 link_type, 0)) != NULL)
805 /* Found a good range, return base */
807 return (htons(port_sys));
809 /* Find a new base to try */
810 if (align == FIND_EVEN_ALIAS_BASE)
811 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
813 port_sys = arc4random() & ALIAS_PORT_MASK;
815 port_sys += ALIAS_PORT_BASE;
818 #ifdef LIBALIAS_DEBUG
819 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
820 fprintf(stderr, "could not find free port(s)\n");
827 CleanupAliasData(struct libalias *la)
829 struct alias_link *lnk;
832 LIBALIAS_LOCK_ASSERT(la);
833 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
834 lnk = LIST_FIRST(&la->linkTableOut[i]);
835 while (lnk != NULL) {
836 struct alias_link *link_next = LIST_NEXT(lnk, list_out);
842 la->cleanupIndex = 0;
847 IncrementalCleanup(struct libalias *la)
849 struct alias_link *lnk, *lnk_tmp;
851 LIBALIAS_LOCK_ASSERT(la);
852 LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
854 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
858 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
859 la->cleanupIndex = 0;
863 DeleteLink(struct alias_link *lnk)
865 struct libalias *la = lnk->la;
867 LIBALIAS_LOCK_ASSERT(la);
868 /* Don't do anything if the link is marked permanent */
869 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
873 /* Delete associated firewall hole, if any */
877 /* Free memory allocated for LSNAT server pool */
878 if (lnk->server != NULL) {
879 struct server *head, *curr, *next;
881 head = curr = lnk->server;
885 } while ((curr = next) != head);
887 /* Adjust output table pointers */
888 LIST_REMOVE(lnk, list_out);
890 /* Adjust input table pointers */
891 LIST_REMOVE(lnk, list_in);
892 #ifndef NO_USE_SOCKETS
893 /* Close socket, if one has been allocated */
894 if (lnk->sockfd != -1) {
899 /* Link-type dependent cleanup */
900 switch (lnk->link_type) {
914 case LINK_FRAGMENT_ID:
915 la->fragmentIdLinkCount--;
917 case LINK_FRAGMENT_PTR:
918 la->fragmentPtrLinkCount--;
919 if (lnk->data.frag_ptr != NULL)
920 free(lnk->data.frag_ptr);
925 la->protoLinkCount--;
932 /* Write statistics, if logging enabled */
933 if (la->packetAliasMode & PKT_ALIAS_LOG) {
940 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr,
941 struct in_addr alias_addr, u_short src_port, u_short dst_port,
942 int alias_port_param, int link_type)
945 struct alias_link *lnk;
947 LIBALIAS_LOCK_ASSERT(la);
948 lnk = malloc(sizeof(struct alias_link));
950 /* Basic initialization */
952 lnk->src_addr = src_addr;
953 lnk->dst_addr = dst_addr;
954 lnk->alias_addr = alias_addr;
955 lnk->proxy_addr.s_addr = INADDR_ANY;
956 lnk->src_port = src_port;
957 lnk->dst_port = dst_port;
960 lnk->link_type = link_type;
961 #ifndef NO_USE_SOCKETS
966 lnk->timestamp = la->timeStamp;
968 /* Expiration time */
971 lnk->expire_time = ICMP_EXPIRE_TIME;
974 lnk->expire_time = UDP_EXPIRE_TIME;
977 lnk->expire_time = TCP_EXPIRE_INITIAL;
980 lnk->flags |= LINK_PERMANENT; /* no timeout. */
982 case LINK_FRAGMENT_ID:
983 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
985 case LINK_FRAGMENT_PTR:
986 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
991 lnk->expire_time = PROTO_EXPIRE_TIME;
995 /* Determine alias flags */
996 if (dst_addr.s_addr == INADDR_ANY)
997 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
999 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1001 /* Determine alias port */
1002 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1006 /* Link-type dependent initialization */
1007 switch (link_type) {
1008 struct tcp_dat *aux_tcp;
1011 la->icmpLinkCount++;
1017 aux_tcp = malloc(sizeof(struct tcp_dat));
1018 if (aux_tcp != NULL) {
1022 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1023 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1024 aux_tcp->state.index = 0;
1025 aux_tcp->state.ack_modified = 0;
1026 for (i = 0; i < N_LINK_TCP_DATA; i++)
1027 aux_tcp->ack[i].active = 0;
1028 aux_tcp->fwhole = -1;
1029 lnk->data.tcp = aux_tcp;
1031 #ifdef LIBALIAS_DEBUG
1032 fprintf(stderr, "PacketAlias/AddLink: ");
1033 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1040 la->pptpLinkCount++;
1042 case LINK_FRAGMENT_ID:
1043 la->fragmentIdLinkCount++;
1045 case LINK_FRAGMENT_PTR:
1046 la->fragmentPtrLinkCount++;
1051 la->protoLinkCount++;
1055 /* Set up pointers for output lookup table */
1056 start_point = StartPointOut(src_addr, dst_addr,
1057 src_port, dst_port, link_type);
1058 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1060 /* Set up pointers for input lookup table */
1061 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1062 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1064 #ifdef LIBALIAS_DEBUG
1065 fprintf(stderr, "PacketAlias/AddLink(): ");
1066 fprintf(stderr, "malloc() call failed.\n");
1069 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1075 static struct alias_link *
1076 ReLink(struct alias_link *old_lnk,
1077 struct in_addr src_addr,
1078 struct in_addr dst_addr,
1079 struct in_addr alias_addr,
1082 int alias_port_param, /* if less than zero, alias */
1084 { /* port will be automatically *//* chosen.
1085 * If greater than */
1086 struct alias_link *new_lnk; /* zero, equal to alias port */
1087 struct libalias *la = old_lnk->la;
1089 LIBALIAS_LOCK_ASSERT(la);
1090 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1091 src_port, dst_port, alias_port_param,
1094 if (new_lnk != NULL &&
1095 old_lnk->link_type == LINK_TCP &&
1096 old_lnk->data.tcp->fwhole > 0) {
1097 PunchFWHole(new_lnk);
1100 DeleteLink(old_lnk);
1104 static struct alias_link *
1105 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1106 struct in_addr dst_addr,
1110 int replace_partial_links)
1113 struct alias_link *lnk;
1115 LIBALIAS_LOCK_ASSERT(la);
1116 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1117 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1118 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1119 lnk->src_addr.s_addr == src_addr.s_addr &&
1120 lnk->src_port == src_port &&
1121 lnk->dst_port == dst_port &&
1122 lnk->link_type == link_type &&
1123 lnk->server == NULL) {
1124 lnk->timestamp = la->timeStamp;
1129 /* Search for partially specified links. */
1130 if (lnk == NULL && replace_partial_links) {
1131 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1132 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1135 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1136 dst_port, link_type, 0);
1139 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1140 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1145 src_addr, dst_addr, lnk->alias_addr,
1146 src_port, dst_port, lnk->alias_port,
1153 static struct alias_link *
1154 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1155 struct in_addr dst_addr,
1159 int replace_partial_links)
1161 struct alias_link *lnk;
1163 LIBALIAS_LOCK_ASSERT(la);
1164 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1165 link_type, replace_partial_links);
1169 * The following allows permanent links to be specified as
1170 * using the default source address (i.e. device interface
1171 * address) without knowing in advance what that address
1174 if (la->aliasAddress.s_addr != INADDR_ANY &&
1175 src_addr.s_addr == la->aliasAddress.s_addr) {
1176 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1177 link_type, replace_partial_links);
1184 static struct alias_link *
1185 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1186 struct in_addr alias_addr,
1190 int replace_partial_links)
1194 struct alias_link *lnk;
1195 struct alias_link *lnk_fully_specified;
1196 struct alias_link *lnk_unknown_all;
1197 struct alias_link *lnk_unknown_dst_addr;
1198 struct alias_link *lnk_unknown_dst_port;
1200 LIBALIAS_LOCK_ASSERT(la);
1201 /* Initialize pointers */
1202 lnk_fully_specified = NULL;
1203 lnk_unknown_all = NULL;
1204 lnk_unknown_dst_addr = NULL;
1205 lnk_unknown_dst_port = NULL;
1207 /* If either the dest addr or port is unknown, the search
1208 loop will have to know about this. */
1211 if (dst_addr.s_addr == INADDR_ANY)
1212 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1214 flags_in |= LINK_UNKNOWN_DEST_PORT;
1217 start_point = StartPointIn(alias_addr, alias_port, link_type);
1218 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1221 flags = flags_in | lnk->flags;
1222 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1223 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1224 && lnk->alias_port == alias_port
1225 && lnk->dst_addr.s_addr == dst_addr.s_addr
1226 && lnk->dst_port == dst_port
1227 && lnk->link_type == link_type) {
1228 lnk_fully_specified = lnk;
1231 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1232 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1233 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1234 && lnk->alias_port == alias_port
1235 && lnk->link_type == link_type) {
1236 if (lnk_unknown_all == NULL)
1237 lnk_unknown_all = lnk;
1239 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1240 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1241 && lnk->alias_port == alias_port
1242 && lnk->link_type == link_type
1243 && lnk->dst_port == dst_port) {
1244 if (lnk_unknown_dst_addr == NULL)
1245 lnk_unknown_dst_addr = lnk;
1247 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1248 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1249 && lnk->alias_port == alias_port
1250 && lnk->link_type == link_type
1251 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1252 if (lnk_unknown_dst_port == NULL)
1253 lnk_unknown_dst_port = lnk;
1260 if (lnk_fully_specified != NULL) {
1261 lnk_fully_specified->timestamp = la->timeStamp;
1262 lnk = lnk_fully_specified;
1263 } else if (lnk_unknown_dst_port != NULL)
1264 lnk = lnk_unknown_dst_port;
1265 else if (lnk_unknown_dst_addr != NULL)
1266 lnk = lnk_unknown_dst_addr;
1267 else if (lnk_unknown_all != NULL)
1268 lnk = lnk_unknown_all;
1272 if (replace_partial_links &&
1273 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1274 struct in_addr src_addr;
1277 if (lnk->server != NULL) { /* LSNAT link */
1278 src_addr = lnk->server->addr;
1279 src_port = lnk->server->port;
1280 lnk->server = lnk->server->next;
1282 src_addr = lnk->src_addr;
1283 src_port = lnk->src_port;
1286 if (link_type == LINK_SCTP) {
1287 lnk->src_addr = src_addr;
1288 lnk->src_port = src_port;
1292 src_addr, dst_addr, alias_addr,
1293 src_port, dst_port, alias_port,
1299 static struct alias_link *
1300 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1301 struct in_addr alias_addr,
1305 int replace_partial_links)
1307 struct alias_link *lnk;
1309 LIBALIAS_LOCK_ASSERT(la);
1310 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1311 link_type, replace_partial_links);
1315 * The following allows permanent links to be specified as
1316 * using the default aliasing address (i.e. device
1317 * interface address) without knowing in advance what that
1320 if (la->aliasAddress.s_addr != INADDR_ANY &&
1321 alias_addr.s_addr == la->aliasAddress.s_addr) {
1322 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1323 link_type, replace_partial_links);
1332 /* External routines for finding/adding links
1334 -- "external" means outside alias_db.c, but within alias*.c --
1336 FindIcmpIn(), FindIcmpOut()
1337 FindFragmentIn1(), FindFragmentIn2()
1338 AddFragmentPtrLink(), FindFragmentPtr()
1339 FindProtoIn(), FindProtoOut()
1340 FindUdpTcpIn(), FindUdpTcpOut()
1341 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1342 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1343 FindOriginalAddress(), FindAliasAddress()
1345 (prototypes in alias_local.h)
1350 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1351 struct in_addr alias_addr,
1355 struct alias_link *lnk;
1357 LIBALIAS_LOCK_ASSERT(la);
1358 lnk = FindLinkIn(la, dst_addr, alias_addr,
1359 NO_DEST_PORT, id_alias,
1361 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1362 struct in_addr target_addr;
1364 target_addr = FindOriginalAddress(la, alias_addr);
1365 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1366 id_alias, NO_DEST_PORT, id_alias,
1374 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1375 struct in_addr dst_addr,
1379 struct alias_link *lnk;
1381 LIBALIAS_LOCK_ASSERT(la);
1382 lnk = FindLinkOut(la, src_addr, dst_addr,
1385 if (lnk == NULL && create) {
1386 struct in_addr alias_addr;
1388 alias_addr = FindAliasAddress(la, src_addr);
1389 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1390 id, NO_DEST_PORT, GET_ALIAS_ID,
1398 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1399 struct in_addr alias_addr,
1402 struct alias_link *lnk;
1404 LIBALIAS_LOCK_ASSERT(la);
1405 lnk = FindLinkIn(la, dst_addr, alias_addr,
1406 NO_DEST_PORT, ip_id,
1407 LINK_FRAGMENT_ID, 0);
1410 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1411 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1419 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1421 struct in_addr alias_addr, /* is not found. */
1425 LIBALIAS_LOCK_ASSERT(la);
1426 return FindLinkIn(la, dst_addr, alias_addr,
1427 NO_DEST_PORT, ip_id,
1428 LINK_FRAGMENT_ID, 0);
1433 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1437 LIBALIAS_LOCK_ASSERT(la);
1438 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1439 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1445 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1449 LIBALIAS_LOCK_ASSERT(la);
1450 return FindLinkIn(la, dst_addr, la->nullAddress,
1451 NO_DEST_PORT, ip_id,
1452 LINK_FRAGMENT_PTR, 0);
1457 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1458 struct in_addr alias_addr,
1461 struct alias_link *lnk;
1463 LIBALIAS_LOCK_ASSERT(la);
1464 lnk = FindLinkIn(la, dst_addr, alias_addr,
1468 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1469 struct in_addr target_addr;
1471 target_addr = FindOriginalAddress(la, alias_addr);
1472 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1473 NO_SRC_PORT, NO_DEST_PORT, 0,
1481 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1482 struct in_addr dst_addr,
1485 struct alias_link *lnk;
1487 LIBALIAS_LOCK_ASSERT(la);
1488 lnk = FindLinkOut(la, src_addr, dst_addr,
1489 NO_SRC_PORT, NO_DEST_PORT,
1493 struct in_addr alias_addr;
1495 alias_addr = FindAliasAddress(la, src_addr);
1496 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1497 NO_SRC_PORT, NO_DEST_PORT, 0,
1505 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1506 struct in_addr alias_addr,
1513 struct alias_link *lnk;
1515 LIBALIAS_LOCK_ASSERT(la);
1518 link_type = LINK_UDP;
1521 link_type = LINK_TCP;
1528 lnk = FindLinkIn(la, dst_addr, alias_addr,
1529 dst_port, alias_port,
1532 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1533 struct in_addr target_addr;
1535 target_addr = FindOriginalAddress(la, alias_addr);
1536 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1537 alias_port, dst_port, alias_port,
1545 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1546 struct in_addr dst_addr,
1553 struct alias_link *lnk;
1555 LIBALIAS_LOCK_ASSERT(la);
1558 link_type = LINK_UDP;
1561 link_type = LINK_TCP;
1568 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1570 if (lnk == NULL && create) {
1571 struct in_addr alias_addr;
1573 alias_addr = FindAliasAddress(la, src_addr);
1574 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1575 src_port, dst_port, GET_ALIAS_PORT,
1583 AddPptp(struct libalias *la, struct in_addr src_addr,
1584 struct in_addr dst_addr,
1585 struct in_addr alias_addr,
1586 u_int16_t src_call_id)
1588 struct alias_link *lnk;
1590 LIBALIAS_LOCK_ASSERT(la);
1591 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1592 src_call_id, 0, GET_ALIAS_PORT,
1600 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1601 struct in_addr dst_addr,
1602 u_int16_t src_call_id)
1605 struct alias_link *lnk;
1607 LIBALIAS_LOCK_ASSERT(la);
1608 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1609 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1610 if (lnk->link_type == LINK_PPTP &&
1611 lnk->src_addr.s_addr == src_addr.s_addr &&
1612 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1613 lnk->src_port == src_call_id)
1621 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1622 struct in_addr dst_addr,
1623 u_int16_t dst_call_id)
1626 struct alias_link *lnk;
1628 LIBALIAS_LOCK_ASSERT(la);
1629 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1630 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1631 if (lnk->link_type == LINK_PPTP &&
1632 lnk->src_addr.s_addr == src_addr.s_addr &&
1633 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1634 lnk->dst_port == dst_call_id)
1642 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1643 struct in_addr alias_addr,
1644 u_int16_t dst_call_id)
1647 struct alias_link *lnk;
1649 LIBALIAS_LOCK_ASSERT(la);
1650 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1651 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1652 if (lnk->link_type == LINK_PPTP &&
1653 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1654 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1655 lnk->dst_port == dst_call_id)
1663 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1664 struct in_addr alias_addr,
1665 u_int16_t alias_call_id)
1667 struct alias_link *lnk;
1669 LIBALIAS_LOCK_ASSERT(la);
1670 lnk = FindLinkIn(la, dst_addr, alias_addr,
1671 0 /* any */ , alias_call_id,
1680 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1681 struct in_addr dst_addr,
1687 struct alias_link *lnk;
1689 LIBALIAS_LOCK_ASSERT(la);
1692 link_type = LINK_UDP;
1695 link_type = LINK_TCP;
1702 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1705 struct in_addr alias_addr;
1707 alias_addr = FindAliasAddress(la, src_addr);
1708 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1709 src_port, 0, alias_port,
1717 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1719 struct alias_link *lnk;
1721 LIBALIAS_LOCK_ASSERT(la);
1722 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1723 0, 0, LINK_ADDR, 0);
1725 la->newDefaultLink = 1;
1726 if (la->targetAddress.s_addr == INADDR_ANY)
1727 return (alias_addr);
1728 else if (la->targetAddress.s_addr == INADDR_NONE)
1729 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1730 la->aliasAddress : alias_addr;
1732 return (la->targetAddress);
1734 if (lnk->server != NULL) { /* LSNAT link */
1735 struct in_addr src_addr;
1737 src_addr = lnk->server->addr;
1738 lnk->server = lnk->server->next;
1740 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1741 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1742 la->aliasAddress : alias_addr;
1744 return (lnk->src_addr);
1750 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1752 struct alias_link *lnk;
1754 LIBALIAS_LOCK_ASSERT(la);
1755 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1756 0, 0, LINK_ADDR, 0);
1758 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1759 la->aliasAddress : original_addr;
1761 if (lnk->alias_addr.s_addr == INADDR_ANY)
1762 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1763 la->aliasAddress : original_addr;
1765 return (lnk->alias_addr);
1770 /* External routines for getting or changing link data
1771 (external to alias_db.c, but internal to alias*.c)
1773 SetFragmentData(), GetFragmentData()
1774 SetFragmentPtr(), GetFragmentPtr()
1775 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1776 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1777 GetOriginalPort(), GetAliasPort()
1778 SetAckModified(), GetAckModified()
1779 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1780 SetProtocolFlags(), GetProtocolFlags()
1786 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1788 lnk->data.frag_addr = src_addr;
1793 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1795 *src_addr = lnk->data.frag_addr;
1800 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1802 lnk->data.frag_ptr = fptr;
1807 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1809 *fptr = lnk->data.frag_ptr;
1814 SetStateIn(struct alias_link *lnk, int state)
1816 /* TCP input state */
1818 case ALIAS_TCP_STATE_DISCONNECTED:
1819 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1820 lnk->expire_time = TCP_EXPIRE_DEAD;
1822 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1824 case ALIAS_TCP_STATE_CONNECTED:
1825 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1826 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1830 panic("libalias:SetStateIn() unknown state");
1835 lnk->data.tcp->state.in = state;
1840 SetStateOut(struct alias_link *lnk, int state)
1842 /* TCP output state */
1844 case ALIAS_TCP_STATE_DISCONNECTED:
1845 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1846 lnk->expire_time = TCP_EXPIRE_DEAD;
1848 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1850 case ALIAS_TCP_STATE_CONNECTED:
1851 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1852 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1856 panic("libalias:SetStateOut() unknown state");
1861 lnk->data.tcp->state.out = state;
1866 GetStateIn(struct alias_link *lnk)
1868 /* TCP input state */
1869 return (lnk->data.tcp->state.in);
1874 GetStateOut(struct alias_link *lnk)
1876 /* TCP output state */
1877 return (lnk->data.tcp->state.out);
1882 GetOriginalAddress(struct alias_link *lnk)
1884 if (lnk->src_addr.s_addr == INADDR_ANY)
1885 return (lnk->la->aliasAddress);
1887 return (lnk->src_addr);
1892 GetDestAddress(struct alias_link *lnk)
1894 return (lnk->dst_addr);
1899 GetAliasAddress(struct alias_link *lnk)
1901 if (lnk->alias_addr.s_addr == INADDR_ANY)
1902 return (lnk->la->aliasAddress);
1904 return (lnk->alias_addr);
1909 GetDefaultAliasAddress(struct libalias *la)
1912 LIBALIAS_LOCK_ASSERT(la);
1913 return (la->aliasAddress);
1918 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1921 LIBALIAS_LOCK_ASSERT(la);
1922 la->aliasAddress = alias_addr;
1927 GetOriginalPort(struct alias_link *lnk)
1929 return (lnk->src_port);
1934 GetAliasPort(struct alias_link *lnk)
1936 return (lnk->alias_port);
1941 GetDestPort(struct alias_link *lnk)
1943 return (lnk->dst_port);
1949 SetAckModified(struct alias_link *lnk)
1951 /* Indicate that ACK numbers have been modified in a TCP connection */
1952 lnk->data.tcp->state.ack_modified = 1;
1957 GetProxyAddress(struct alias_link *lnk)
1959 return (lnk->proxy_addr);
1964 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1966 lnk->proxy_addr = addr;
1971 GetProxyPort(struct alias_link *lnk)
1973 return (lnk->proxy_port);
1978 SetProxyPort(struct alias_link *lnk, u_short port)
1980 lnk->proxy_port = port;
1985 GetAckModified(struct alias_link *lnk)
1987 /* See if ACK numbers have been modified */
1988 return (lnk->data.tcp->state.ack_modified);
1993 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
1996 Find out how much the ACK number has been altered for an incoming
1997 TCP packet. To do this, a circular list of ACK numbers where the TCP
1998 packet size was altered is searched.
2002 int delta, ack_diff_min;
2006 i = lnk->data.tcp->state.index;
2007 for (j = 0; j < N_LINK_TCP_DATA; j++) {
2008 struct ack_data_record x;
2011 i = N_LINK_TCP_DATA;
2013 x = lnk->data.tcp->ack[i];
2014 if (x.active == 1) {
2017 ack_diff = SeqDiff(x.ack_new, ack);
2018 if (ack_diff >= 0) {
2019 if (ack_diff_min >= 0) {
2020 if (ack_diff < ack_diff_min) {
2022 ack_diff_min = ack_diff;
2026 ack_diff_min = ack_diff;
2036 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
2039 Find out how much the sequence number has been altered for an outgoing
2040 TCP packet. To do this, a circular list of ACK numbers where the TCP
2041 packet size was altered is searched.
2045 int delta, seq_diff_min;
2049 i = lnk->data.tcp->state.index;
2050 for (j = 0; j < N_LINK_TCP_DATA; j++) {
2051 struct ack_data_record x;
2054 i = N_LINK_TCP_DATA;
2056 x = lnk->data.tcp->ack[i];
2057 if (x.active == 1) {
2060 seq_diff = SeqDiff(x.ack_old, seq);
2061 if (seq_diff >= 0) {
2062 if (seq_diff_min >= 0) {
2063 if (seq_diff < seq_diff_min) {
2065 seq_diff_min = seq_diff;
2069 seq_diff_min = seq_diff;
2079 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
2080 u_long th_seq, u_int th_off)
2083 When a TCP packet has been altered in length, save this
2084 information in a circular list. If enough packets have
2085 been altered, then this list will begin to overwrite itself.
2088 struct ack_data_record x;
2089 int hlen, tlen, dlen;
2092 hlen = (ip_hl + th_off) << 2;
2093 tlen = ntohs(ip_len);
2096 x.ack_old = htonl(ntohl(th_seq) + dlen);
2097 x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
2101 i = lnk->data.tcp->state.index;
2102 lnk->data.tcp->ack[i] = x;
2105 if (i == N_LINK_TCP_DATA)
2106 lnk->data.tcp->state.index = 0;
2108 lnk->data.tcp->state.index = i;
2112 SetExpire(struct alias_link *lnk, int expire)
2115 lnk->flags &= ~LINK_PERMANENT;
2117 } else if (expire == -1) {
2118 lnk->flags |= LINK_PERMANENT;
2119 } else if (expire > 0) {
2120 lnk->expire_time = expire;
2122 #ifdef LIBALIAS_DEBUG
2123 fprintf(stderr, "PacketAlias/SetExpire(): ");
2124 fprintf(stderr, "error in expire parameter\n");
2130 ClearCheckNewLink(struct libalias *la)
2133 LIBALIAS_LOCK_ASSERT(la);
2134 la->newDefaultLink = 0;
2138 SetProtocolFlags(struct alias_link *lnk, int pflags)
2141 lnk->pflags = pflags;
2145 GetProtocolFlags(struct alias_link *lnk)
2148 return (lnk->pflags);
2152 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2154 struct libalias *la = lnk->la;
2156 LIBALIAS_LOCK_ASSERT(la);
2157 la->deleteAllLinks = 1;
2158 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2159 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2160 la->deleteAllLinks = 0;
2164 /* Miscellaneous Functions
2167 InitPacketAliasLog()
2168 UninitPacketAliasLog()
2172 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2173 is called to find and remove timed-out aliasing links. Logic exists
2174 to sweep through the entire table and linked list structure
2177 (prototype in alias_local.h)
2181 HouseKeeping(struct libalias *la)
2188 LIBALIAS_LOCK_ASSERT(la);
2190 * Save system time (seconds) in global variable timeStamp for use
2191 * by other functions. This is done so as not to unnecessarily
2192 * waste timeline by making system calls.
2195 la->timeStamp = time_uptime;
2197 gettimeofday(&tv, NULL);
2198 la->timeStamp = tv.tv_sec;
2201 /* Compute number of spokes (output table link chains) to cover */
2202 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2203 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2205 /* Handle different cases */
2207 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2208 n = ALIAS_CLEANUP_MAX_SPOKES;
2209 la->lastCleanupTime = la->timeStamp;
2210 for (i = 0; i < n; i++)
2211 IncrementalCleanup(la);
2213 #ifdef LIBALIAS_DEBUG
2214 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2215 fprintf(stderr, "something unexpected in time values\n");
2217 la->lastCleanupTime = la->timeStamp;
2221 /* Init the log file and enable logging */
2223 InitPacketAliasLog(struct libalias *la)
2226 LIBALIAS_LOCK_ASSERT(la);
2227 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2229 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2232 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2233 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2236 return (ENOMEM); /* log initialization failed */
2237 la->packetAliasMode |= PKT_ALIAS_LOG;
2243 /* Close the log-file and disable logging. */
2245 UninitPacketAliasLog(struct libalias *la)
2248 LIBALIAS_LOCK_ASSERT(la);
2253 fclose(la->logDesc);
2257 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2260 /* Outside world interfaces
2262 -- "outside world" means other than alias*.c routines --
2264 PacketAliasRedirectPort()
2265 PacketAliasAddServer()
2266 PacketAliasRedirectProto()
2267 PacketAliasRedirectAddr()
2268 PacketAliasRedirectDynamic()
2269 PacketAliasRedirectDelete()
2270 PacketAliasSetAddress()
2273 PacketAliasSetMode()
2275 (prototypes in alias.h)
2278 /* Redirection from a specific public addr:port to a
2279 private addr:port */
2281 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2282 struct in_addr dst_addr, u_short dst_port,
2283 struct in_addr alias_addr, u_short alias_port,
2287 struct alias_link *lnk;
2292 link_type = LINK_UDP;
2295 link_type = LINK_TCP;
2298 link_type = LINK_SCTP;
2301 #ifdef LIBALIAS_DEBUG
2302 fprintf(stderr, "PacketAliasRedirectPort(): ");
2303 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
2309 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2310 src_port, dst_port, alias_port,
2314 lnk->flags |= LINK_PERMANENT;
2316 #ifdef LIBALIAS_DEBUG
2318 fprintf(stderr, "PacketAliasRedirectPort(): "
2319 "call to AddLink() failed\n");
2324 LIBALIAS_UNLOCK(la);
2328 /* Add server to the pool of servers */
2330 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2332 struct server *server;
2338 server = malloc(sizeof(struct server));
2340 if (server != NULL) {
2341 struct server *head;
2343 server->addr = addr;
2344 server->port = port;
2348 server->next = server;
2352 for (s = head; s->next != head; s = s->next);
2354 server->next = head;
2356 lnk->server = server;
2361 LIBALIAS_UNLOCK(la);
2365 /* Redirect packets of a given IP protocol from a specific
2366 public address to a private address */
2368 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2369 struct in_addr dst_addr,
2370 struct in_addr alias_addr,
2373 struct alias_link *lnk;
2376 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2377 NO_SRC_PORT, NO_DEST_PORT, 0,
2381 lnk->flags |= LINK_PERMANENT;
2383 #ifdef LIBALIAS_DEBUG
2385 fprintf(stderr, "PacketAliasRedirectProto(): "
2386 "call to AddLink() failed\n");
2390 LIBALIAS_UNLOCK(la);
2394 /* Static address translation */
2396 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2397 struct in_addr alias_addr)
2399 struct alias_link *lnk;
2402 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2407 lnk->flags |= LINK_PERMANENT;
2409 #ifdef LIBALIAS_DEBUG
2411 fprintf(stderr, "PacketAliasRedirectAddr(): "
2412 "call to AddLink() failed\n");
2416 LIBALIAS_UNLOCK(la);
2421 /* Mark the aliasing link dynamic */
2423 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2430 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2433 lnk->flags &= ~LINK_PERMANENT;
2436 LIBALIAS_UNLOCK(la);
2442 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2444 /* This is a dangerous function to put in the API,
2445 because an invalid pointer can crash the program. */
2448 la->deleteAllLinks = 1;
2450 la->deleteAllLinks = 0;
2451 LIBALIAS_UNLOCK(la);
2456 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2460 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2461 && la->aliasAddress.s_addr != addr.s_addr)
2462 CleanupAliasData(la);
2464 la->aliasAddress = addr;
2465 LIBALIAS_UNLOCK(la);
2470 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low,
2475 la->aliasPortLower = port_low;
2476 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */
2477 la->aliasPortLength = port_high - port_low + 1;
2478 LIBALIAS_UNLOCK(la);
2482 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2486 la->targetAddress = target_addr;
2487 LIBALIAS_UNLOCK(la);
2494 while (!LIST_EMPTY(&instancehead))
2495 LibAliasUninit(LIST_FIRST(&instancehead));
2499 LibAliasInit(struct libalias *la)
2508 #undef malloc /* XXX: ugly */
2509 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO);
2511 la = calloc(sizeof *la, 1);
2516 #ifndef _KERNEL /* kernel cleans up on module unload */
2517 if (LIST_EMPTY(&instancehead))
2520 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2523 la->timeStamp = time_uptime;
2524 la->lastCleanupTime = time_uptime;
2526 gettimeofday(&tv, NULL);
2527 la->timeStamp = tv.tv_sec;
2528 la->lastCleanupTime = tv.tv_sec;
2531 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2532 LIST_INIT(&la->linkTableOut[i]);
2533 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2534 LIST_INIT(&la->linkTableIn[i]);
2538 LIBALIAS_LOCK_INIT(la);
2542 la->deleteAllLinks = 1;
2543 CleanupAliasData(la);
2544 la->deleteAllLinks = 0;
2551 la->aliasAddress.s_addr = INADDR_ANY;
2552 la->targetAddress.s_addr = INADDR_ANY;
2554 la->icmpLinkCount = 0;
2555 la->udpLinkCount = 0;
2556 la->tcpLinkCount = 0;
2557 la->sctpLinkCount = 0;
2558 la->pptpLinkCount = 0;
2559 la->protoLinkCount = 0;
2560 la->fragmentIdLinkCount = 0;
2561 la->fragmentPtrLinkCount = 0;
2564 la->cleanupIndex = 0;
2566 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2567 #ifndef NO_USE_SOCKETS
2568 | PKT_ALIAS_USE_SOCKETS
2570 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2572 la->fireWallFD = -1;
2575 LibAliasRefreshModules();
2577 LIBALIAS_UNLOCK(la);
2582 LibAliasUninit(struct libalias *la)
2589 la->deleteAllLinks = 1;
2590 CleanupAliasData(la);
2591 la->deleteAllLinks = 0;
2592 UninitPacketAliasLog(la);
2596 LIST_REMOVE(la, instancelist);
2597 LIBALIAS_UNLOCK(la);
2598 LIBALIAS_LOCK_DESTROY(la);
2602 /* Change mode for some operations */
2605 struct libalias *la,
2606 unsigned int flags, /* Which state to bring flags to */
2607 unsigned int mask /* Mask of which flags to affect (use 0 to
2608 * do a probe for flag values) */
2614 /* Enable logging? */
2615 if (flags & mask & PKT_ALIAS_LOG) {
2617 if (InitPacketAliasLog(la) == ENOMEM)
2620 /* _Disable_ logging? */
2621 if (~flags & mask & PKT_ALIAS_LOG) {
2622 UninitPacketAliasLog(la);
2625 /* Start punching holes in the firewall? */
2626 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2629 /* Stop punching holes in the firewall? */
2630 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2635 /* Other flags can be set/cleared without special action */
2636 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2637 res = la->packetAliasMode;
2639 LIBALIAS_UNLOCK(la);
2645 LibAliasCheckNewLink(struct libalias *la)
2650 res = la->newDefaultLink;
2651 LIBALIAS_UNLOCK(la);
2659 Code to support firewall punching. This shouldn't really be in this
2660 file, but making variables global is evil too.
2663 /* Firewall include files */
2665 #include <netinet/ip_fw.h>
2670 * helper function, updates the pointer to cmd with the length
2671 * of the current command, and also cleans up the first word of
2672 * the new command in case it has been clobbered before.
2675 next_cmd(ipfw_insn * cmd)
2678 bzero(cmd, sizeof(*cmd));
2683 * A function to fill simple commands of size 1.
2684 * Existing flags are preserved.
2687 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2688 int flags, u_int16_t arg)
2690 cmd->opcode = opcode;
2691 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2693 return next_cmd(cmd);
2697 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2699 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2701 cmd->addr.s_addr = addr;
2702 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2706 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2708 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2710 cmd->ports[0] = cmd->ports[1] = port;
2711 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2715 fill_rule(void *buf, int bufsize, int rulenum,
2716 enum ipfw_opcodes action, int proto,
2717 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2719 struct ip_fw *rule = (struct ip_fw *)buf;
2720 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2722 bzero(buf, bufsize);
2723 rule->rulenum = rulenum;
2725 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2726 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2727 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2728 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2729 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2731 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2732 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2734 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2736 return ((char *)cmd - (char *)buf);
2739 static void ClearAllFWHoles(struct libalias *la);
2742 #define fw_setfield(la, field, num) \
2744 (field)[(num) - la->fireWallBaseNum] = 1; \
2745 } /*lint -save -e717 */ while(0)/* lint -restore */
2747 #define fw_clrfield(la, field, num) \
2749 (field)[(num) - la->fireWallBaseNum] = 0; \
2750 } /*lint -save -e717 */ while(0)/* lint -restore */
2752 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2755 InitPunchFW(struct libalias *la)
2758 la->fireWallField = malloc(la->fireWallNumNums);
2759 if (la->fireWallField) {
2760 memset(la->fireWallField, 0, la->fireWallNumNums);
2761 if (la->fireWallFD < 0) {
2762 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2764 ClearAllFWHoles(la);
2765 la->fireWallActiveNum = la->fireWallBaseNum;
2770 UninitPunchFW(struct libalias *la)
2773 ClearAllFWHoles(la);
2774 if (la->fireWallFD >= 0)
2775 close(la->fireWallFD);
2776 la->fireWallFD = -1;
2777 if (la->fireWallField)
2778 free(la->fireWallField);
2779 la->fireWallField = NULL;
2780 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2783 /* Make a certain link go through the firewall */
2785 PunchFWHole(struct alias_link *lnk)
2787 struct libalias *la;
2788 int r; /* Result code */
2789 struct ip_fw rule; /* On-the-fly built rule */
2790 int fwhole; /* Where to punch hole */
2794 /* Don't do anything unless we are asked to */
2795 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2796 la->fireWallFD < 0 ||
2797 lnk->link_type != LINK_TCP)
2800 memset(&rule, 0, sizeof rule);
2804 /* Find empty slot */
2805 for (fwhole = la->fireWallActiveNum;
2806 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2807 fw_tstfield(la, la->fireWallField, fwhole);
2809 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2810 for (fwhole = la->fireWallBaseNum;
2811 fwhole < la->fireWallActiveNum &&
2812 fw_tstfield(la, la->fireWallField, fwhole);
2814 if (fwhole == la->fireWallActiveNum) {
2815 /* No rule point empty - we can't punch more holes. */
2816 la->fireWallActiveNum = la->fireWallBaseNum;
2817 #ifdef LIBALIAS_DEBUG
2818 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2823 /* Start next search at next position */
2824 la->fireWallActiveNum = fwhole + 1;
2827 * generate two rules of the form
2829 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2830 * accept tcp from DAddr DPort to OAddr OPort
2832 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2833 u_int32_t rulebuf[255];
2836 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2837 O_ACCEPT, IPPROTO_TCP,
2838 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2839 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2840 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2842 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2844 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2845 O_ACCEPT, IPPROTO_TCP,
2846 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2847 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2848 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2850 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2853 /* Indicate hole applied */
2854 lnk->data.tcp->fwhole = fwhole;
2855 fw_setfield(la, la->fireWallField, fwhole);
2858 /* Remove a hole in a firewall associated with a particular alias
2859 lnk. Calling this too often is harmless. */
2861 ClearFWHole(struct alias_link *lnk)
2863 struct libalias *la;
2866 if (lnk->link_type == LINK_TCP) {
2867 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2874 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2875 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2876 &fwhole, sizeof fwhole));
2877 fw_clrfield(la, la->fireWallField, fwhole);
2878 lnk->data.tcp->fwhole = -1;
2882 /* Clear out the entire range dedicated to firewall holes. */
2884 ClearAllFWHoles(struct libalias *la)
2886 struct ip_fw rule; /* On-the-fly built rule */
2889 if (la->fireWallFD < 0)
2892 memset(&rule, 0, sizeof rule);
2893 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2896 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2898 /* XXX: third arg correct here ? /phk */
2899 memset(la->fireWallField, 0, la->fireWallNumNums);
2902 #endif /* !NO_FW_PUNCH */
2905 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2910 la->fireWallBaseNum = base;
2911 la->fireWallNumNums = num;
2913 LIBALIAS_UNLOCK(la);
2917 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2921 la->skinnyPort = port;
2922 LIBALIAS_UNLOCK(la);
2926 * Find the address to redirect incoming packets
2929 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm)
2931 struct alias_link *lnk;
2932 struct in_addr redir;
2934 LIBALIAS_LOCK_ASSERT(la);
2935 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2936 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2938 return(lnk->src_addr); /* port redirect */
2940 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2941 if (redir.s_addr == la->aliasAddress.s_addr ||
2942 redir.s_addr == la->targetAddress.s_addr) { /* No address found */
2943 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2944 NO_DEST_PORT, 0, LINK_SCTP, 1);
2946 return(lnk->src_addr); /* redirect proto */
2948 return(redir); /* address redirect */