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/lock.h>
150 #include <sys/module.h>
151 #include <sys/rwlock.h>
152 #include <sys/syslog.h>
157 #include <sys/errno.h>
158 #include <sys/time.h>
162 #include <sys/socket.h>
163 #include <netinet/tcp.h>
166 #include <netinet/libalias/alias.h>
167 #include <netinet/libalias/alias_local.h>
168 #include <netinet/libalias/alias_mod.h>
172 #include "alias_local.h"
173 #include "alias_mod.h"
176 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
180 Constants (note: constants are also defined
181 near relevant functions or structs)
184 /* Parameters used for cleanup of expired links */
185 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
186 #define ALIAS_CLEANUP_INTERVAL_SECS 64
187 #define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
189 /* Timeouts (in seconds) for different link types */
190 #define ICMP_EXPIRE_TIME 60
191 #define UDP_EXPIRE_TIME 60
192 #define PROTO_EXPIRE_TIME 60
193 #define FRAGMENT_ID_EXPIRE_TIME 10
194 #define FRAGMENT_PTR_EXPIRE_TIME 30
196 /* TCP link expire time for different cases */
197 /* When the link has been used and closed - minimal grace time to
198 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
199 #ifndef TCP_EXPIRE_DEAD
200 #define TCP_EXPIRE_DEAD 10
203 /* When the link has been used and closed on one side - the other side
204 is allowed to still send data */
205 #ifndef TCP_EXPIRE_SINGLEDEAD
206 #define TCP_EXPIRE_SINGLEDEAD 90
209 /* When the link isn't yet up */
210 #ifndef TCP_EXPIRE_INITIAL
211 #define TCP_EXPIRE_INITIAL 300
214 /* When the link is up */
215 #ifndef TCP_EXPIRE_CONNECTED
216 #define TCP_EXPIRE_CONNECTED 86400
220 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
221 These constants can be anything except zero, which indicates an
222 unknown port number. */
224 #define NO_DEST_PORT 1
225 #define NO_SRC_PORT 1
231 The fundamental data structure used in this program is
232 "struct alias_link". Whenever a TCP connection is made,
233 a UDP datagram is sent out, or an ICMP echo request is made,
234 a link record is made (if it has not already been created).
235 The link record is identified by the source address/port
236 and the destination address/port. In the case of an ICMP
237 echo request, the source port is treated as being equivalent
238 with the 16-bit ID number of the ICMP packet.
240 The link record also can store some auxiliary data. For
241 TCP connections that have had sequence and acknowledgment
242 modifications, data space is available to track these changes.
243 A state field is used to keep track in changes to the TCP
244 connection state. ID numbers of fragments can also be
245 stored in the auxiliary space. Pointers to unresolved
246 fragments can also be stored.
248 The link records support two independent chainings. Lookup
249 tables for input and out tables hold the initial pointers
250 the link chains. On input, the lookup table indexes on alias
251 port and link type. On output, the lookup table indexes on
252 source address, destination address, source port, destination
256 struct ack_data_record { /* used to save changes to ACK/sequence
264 struct tcp_state { /* Information about TCP connection */
265 int in; /* State for outside -> inside */
266 int out; /* State for inside -> outside */
267 int index; /* Index to ACK data array */
268 int ack_modified; /* Indicates whether ACK and
269 * sequence numbers */
273 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
274 * saved for a modified TCP stream */
276 struct tcp_state state;
277 struct ack_data_record ack[N_LINK_TCP_DATA];
278 int fwhole; /* Which firewall record is used for this
282 struct server { /* LSNAT server pool (circular list) */
288 struct alias_link { /* Main data structure */
290 struct in_addr src_addr; /* Address and port information */
291 struct in_addr dst_addr;
292 struct in_addr alias_addr;
293 struct in_addr proxy_addr;
298 struct server *server;
300 int link_type; /* Type of link: TCP, UDP, ICMP,
303 /* values for link_type */
304 #define LINK_ICMP IPPROTO_ICMP
305 #define LINK_UDP IPPROTO_UDP
306 #define LINK_TCP IPPROTO_TCP
307 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
308 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
309 #define LINK_ADDR (IPPROTO_MAX + 3)
310 #define LINK_PPTP (IPPROTO_MAX + 4)
312 int flags; /* indicates special characteristics */
313 int pflags; /* protocol-specific flags */
316 #define LINK_UNKNOWN_DEST_PORT 0x01
317 #define LINK_UNKNOWN_DEST_ADDR 0x02
318 #define LINK_PERMANENT 0x04
319 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
320 #define LINK_UNFIREWALLED 0x08
322 int timestamp; /* Time link was last accessed */
323 int expire_time; /* Expire time for link */
324 #ifndef NO_USE_SOCKETS
325 int sockfd; /* socket descriptor */
327 LIST_ENTRY (alias_link) list_out; /* Linked list of
329 LIST_ENTRY (alias_link) list_in; /* input and output
332 union { /* Auxiliary data */
334 struct in_addr frag_addr;
339 /* Clean up procedure. */
340 static void finishoff(void);
342 /* Kernel module definition. */
344 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
346 MODULE_VERSION(libalias, 1);
349 alias_mod_handler(module_t mod, int type, void *data)
356 handler_chain_init();
360 handler_chain_destroy();
371 static moduledata_t alias_mod = {
372 "alias", alias_mod_handler, NULL
375 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
378 /* Internal utility routines (used only in alias_db.c)
380 Lookup table starting points:
381 StartPointIn() -- link table initial search point for
383 StartPointOut() -- link table initial search point for
387 SeqDiff() -- difference between two TCP sequences
388 ShowAliasStats() -- send alias statistics to a monitor file
392 /* Local prototypes */
393 static u_int StartPointIn(struct in_addr, u_short, int);
396 StartPointOut(struct in_addr, struct in_addr,
397 u_short, u_short, int);
399 static int SeqDiff(u_long, u_long);
402 /* Firewall control */
403 static void InitPunchFW(struct libalias *);
404 static void UninitPunchFW(struct libalias *);
405 static void ClearFWHole(struct alias_link *);
409 /* Log file control */
410 static void ShowAliasStats(struct libalias *);
411 static int InitPacketAliasLog(struct libalias *);
412 static void UninitPacketAliasLog(struct libalias *);
414 void SctpShowAliasStats(struct libalias *la);
417 StartPointIn(struct in_addr alias_addr,
423 n = alias_addr.s_addr;
424 if (link_type != LINK_PPTP)
427 return (n % LINK_TABLE_IN_SIZE);
432 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
433 u_short src_port, u_short dst_port, int link_type)
438 n += dst_addr.s_addr;
439 if (link_type != LINK_PPTP) {
445 return (n % LINK_TABLE_OUT_SIZE);
450 SeqDiff(u_long x, u_long y)
452 /* Return the difference between two TCP sequence numbers */
455 This function is encapsulated in case there are any unusual
456 arithmetic conditions that need to be considered.
459 return (ntohl(y) - ntohl(x));
465 AliasLog(char *str, const char *format, ...)
469 va_start(ap, format);
470 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
475 AliasLog(FILE *stream, const char *format, ...)
479 va_start(ap, format);
480 vfprintf(stream, format, ap);
487 ShowAliasStats(struct libalias *la)
490 LIBALIAS_LOCK_ASSERT(la);
491 /* Used for debugging */
493 int tot = la->icmpLinkCount + la->udpLinkCount +
494 (la->sctpLinkCount>>1) + /* sctp counts half associations */
495 la->tcpLinkCount + la->pptpLinkCount +
496 la->protoLinkCount + la->fragmentIdLinkCount +
497 la->fragmentPtrLinkCount;
499 AliasLog(la->logDesc,
500 "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
504 la->sctpLinkCount>>1, /* sctp counts half associations */
507 la->fragmentIdLinkCount,
508 la->fragmentPtrLinkCount, tot);
510 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
515 void SctpShowAliasStats(struct libalias *la)
522 /* Internal routines for finding, deleting and adding links
525 GetNewPort() -- find and reserve new alias port number
526 GetSocket() -- try to allocate a socket for a given port
528 Link creation and deletion:
529 CleanupAliasData() - remove all link chains from lookup table
530 IncrementalCleanup() - look for stale links in a single chain
531 DeleteLink() - remove link
533 ReLink() - change link
536 FindLinkOut() - find link for outgoing packets
537 FindLinkIn() - find link for incoming packets
540 FindNewPortGroup() - find an available group of ports
543 /* Local prototypes */
544 static int GetNewPort(struct libalias *, struct alias_link *, int);
545 #ifndef NO_USE_SOCKETS
546 static u_short GetSocket(struct libalias *, u_short, int *, int);
548 static void CleanupAliasData(struct libalias *);
550 static void IncrementalCleanup(struct libalias *);
552 static void DeleteLink(struct alias_link *);
554 static struct alias_link *
555 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
556 u_short, u_short, int, int);
558 static struct alias_link *
559 ReLink(struct alias_link *,
560 struct in_addr, struct in_addr, struct in_addr,
561 u_short, u_short, int, int);
563 static struct alias_link *
564 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
566 static struct alias_link *
567 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
570 #define ALIAS_PORT_BASE 0x08000
571 #define ALIAS_PORT_MASK 0x07fff
572 #define ALIAS_PORT_MASK_EVEN 0x07ffe
573 #define GET_NEW_PORT_MAX_ATTEMPTS 20
575 #define GET_ALIAS_PORT -1
576 #define GET_ALIAS_ID GET_ALIAS_PORT
578 #define FIND_EVEN_ALIAS_BASE 1
580 /* GetNewPort() allocates port numbers. Note that if a port number
581 is already in use, that does not mean that it cannot be used by
582 another link concurrently. This is because GetNewPort() looks for
583 unused triplets: (dest addr, dest port, alias port). */
586 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
593 LIBALIAS_LOCK_ASSERT(la);
595 Description of alias_port_param for GetNewPort(). When
596 this parameter is zero or positive, it precisely specifies
597 the port number. GetNewPort() will return this number
598 without check that it is in use.
600 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
601 selected port number.
604 if (alias_port_param == GET_ALIAS_PORT) {
606 * The aliasing port is automatically selected by one of
609 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
611 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
613 * When the PKT_ALIAS_SAME_PORTS option is chosen,
614 * the first try will be the actual source port. If
615 * this is already in use, the remainder of the
616 * trials will be random.
618 port_net = lnk->src_port;
619 port_sys = ntohs(port_net);
621 /* First trial and all subsequent are random. */
622 port_sys = arc4random() & ALIAS_PORT_MASK;
623 port_sys += ALIAS_PORT_BASE;
624 port_net = htons(port_sys);
626 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
627 lnk->alias_port = (u_short) alias_port_param;
630 #ifdef LIBALIAS_DEBUG
631 fprintf(stderr, "PacketAlias/GetNewPort(): ");
632 fprintf(stderr, "input parameter error\n");
638 /* Port number search */
639 for (i = 0; i < max_trials; i++) {
641 struct alias_link *search_result;
643 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
644 lnk->dst_port, port_net,
647 if (search_result == NULL)
649 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
650 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
656 #ifndef NO_USE_SOCKETS
657 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
658 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
659 && ((lnk->link_type == LINK_TCP) ||
660 (lnk->link_type == LINK_UDP))) {
661 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
662 lnk->alias_port = port_net;
667 lnk->alias_port = port_net;
669 #ifndef NO_USE_SOCKETS
673 port_sys = arc4random() & ALIAS_PORT_MASK;
674 port_sys += ALIAS_PORT_BASE;
675 port_net = htons(port_sys);
678 #ifdef LIBALIAS_DEBUG
679 fprintf(stderr, "PacketAlias/GetnewPort(): ");
680 fprintf(stderr, "could not find free port\n");
686 #ifndef NO_USE_SOCKETS
688 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
692 struct sockaddr_in sock_addr;
694 LIBALIAS_LOCK_ASSERT(la);
695 if (link_type == LINK_TCP)
696 sock = socket(AF_INET, SOCK_STREAM, 0);
697 else if (link_type == LINK_UDP)
698 sock = socket(AF_INET, SOCK_DGRAM, 0);
700 #ifdef LIBALIAS_DEBUG
701 fprintf(stderr, "PacketAlias/GetSocket(): ");
702 fprintf(stderr, "incorrect link type\n");
708 #ifdef LIBALIAS_DEBUG
709 fprintf(stderr, "PacketAlias/GetSocket(): ");
710 fprintf(stderr, "socket() error %d\n", *sockfd);
714 sock_addr.sin_family = AF_INET;
715 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
716 sock_addr.sin_port = port_net;
719 (struct sockaddr *)&sock_addr,
732 /* FindNewPortGroup() returns a base port number for an available
733 range of contiguous port numbers. Note that if a port number
734 is already in use, that does not mean that it cannot be used by
735 another link concurrently. This is because FindNewPortGroup()
736 looks for unused triplets: (dest addr, dest port, alias port). */
739 FindNewPortGroup(struct libalias *la,
740 struct in_addr dst_addr,
741 struct in_addr alias_addr,
753 LIBALIAS_LOCK_ASSERT(la);
755 * Get link_type from protocol
760 link_type = LINK_UDP;
763 link_type = LINK_TCP;
771 * The aliasing port is automatically selected by one of two
774 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
776 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
778 * When the ALIAS_SAME_PORTS option is chosen, the first
779 * try will be the actual source port. If this is already
780 * in use, the remainder of the trials will be random.
782 port_sys = ntohs(src_port);
786 /* First trial and all subsequent are random. */
787 if (align == FIND_EVEN_ALIAS_BASE)
788 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
790 port_sys = arc4random() & ALIAS_PORT_MASK;
792 port_sys += ALIAS_PORT_BASE;
795 /* Port number search */
796 for (i = 0; i < max_trials; i++) {
798 struct alias_link *search_result;
800 for (j = 0; j < port_count; j++)
801 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
802 dst_port, htons(port_sys + j),
806 /* Found a good range, return base */
808 return (htons(port_sys));
810 /* Find a new base to try */
811 if (align == FIND_EVEN_ALIAS_BASE)
812 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
814 port_sys = arc4random() & ALIAS_PORT_MASK;
816 port_sys += ALIAS_PORT_BASE;
819 #ifdef LIBALIAS_DEBUG
820 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
821 fprintf(stderr, "could not find free port(s)\n");
828 CleanupAliasData(struct libalias *la)
830 struct alias_link *lnk;
833 LIBALIAS_LOCK_ASSERT(la);
834 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
835 lnk = LIST_FIRST(&la->linkTableOut[i]);
836 while (lnk != NULL) {
837 struct alias_link *link_next = LIST_NEXT(lnk, list_out);
843 la->cleanupIndex = 0;
848 IncrementalCleanup(struct libalias *la)
850 struct alias_link *lnk, *lnk_tmp;
852 LIBALIAS_LOCK_ASSERT(la);
853 LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
855 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
859 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
860 la->cleanupIndex = 0;
864 DeleteLink(struct alias_link *lnk)
866 struct libalias *la = lnk->la;
868 LIBALIAS_LOCK_ASSERT(la);
869 /* Don't do anything if the link is marked permanent */
870 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
874 /* Delete associated firewall hole, if any */
878 /* Free memory allocated for LSNAT server pool */
879 if (lnk->server != NULL) {
880 struct server *head, *curr, *next;
882 head = curr = lnk->server;
886 } while ((curr = next) != head);
888 /* Adjust output table pointers */
889 LIST_REMOVE(lnk, list_out);
891 /* Adjust input table pointers */
892 LIST_REMOVE(lnk, list_in);
893 #ifndef NO_USE_SOCKETS
894 /* Close socket, if one has been allocated */
895 if (lnk->sockfd != -1) {
900 /* Link-type dependent cleanup */
901 switch (lnk->link_type) {
915 case LINK_FRAGMENT_ID:
916 la->fragmentIdLinkCount--;
918 case LINK_FRAGMENT_PTR:
919 la->fragmentPtrLinkCount--;
920 if (lnk->data.frag_ptr != NULL)
921 free(lnk->data.frag_ptr);
926 la->protoLinkCount--;
933 /* Write statistics, if logging enabled */
934 if (la->packetAliasMode & PKT_ALIAS_LOG) {
940 static struct alias_link *
941 AddLink(struct libalias *la, struct in_addr src_addr,
942 struct in_addr dst_addr,
943 struct in_addr alias_addr,
946 int alias_port_param, /* if less than zero, alias */
948 { /* port will be automatically *//* chosen.
950 u_int start_point; /* zero, equal to alias port */
951 struct alias_link *lnk;
953 LIBALIAS_LOCK_ASSERT(la);
954 lnk = malloc(sizeof(struct alias_link));
956 /* Basic initialization */
958 lnk->src_addr = src_addr;
959 lnk->dst_addr = dst_addr;
960 lnk->alias_addr = alias_addr;
961 lnk->proxy_addr.s_addr = INADDR_ANY;
962 lnk->src_port = src_port;
963 lnk->dst_port = dst_port;
966 lnk->link_type = link_type;
967 #ifndef NO_USE_SOCKETS
972 lnk->timestamp = la->timeStamp;
974 /* Expiration time */
977 lnk->expire_time = ICMP_EXPIRE_TIME;
980 lnk->expire_time = UDP_EXPIRE_TIME;
983 lnk->expire_time = TCP_EXPIRE_INITIAL;
986 lnk->flags |= LINK_PERMANENT; /* no timeout. */
988 case LINK_FRAGMENT_ID:
989 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
991 case LINK_FRAGMENT_PTR:
992 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
997 lnk->expire_time = PROTO_EXPIRE_TIME;
1001 /* Determine alias flags */
1002 if (dst_addr.s_addr == INADDR_ANY)
1003 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
1005 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1007 /* Determine alias port */
1008 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1012 /* Link-type dependent initialization */
1013 switch (link_type) {
1014 struct tcp_dat *aux_tcp;
1017 la->icmpLinkCount++;
1023 aux_tcp = malloc(sizeof(struct tcp_dat));
1024 if (aux_tcp != NULL) {
1028 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1029 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1030 aux_tcp->state.index = 0;
1031 aux_tcp->state.ack_modified = 0;
1032 for (i = 0; i < N_LINK_TCP_DATA; i++)
1033 aux_tcp->ack[i].active = 0;
1034 aux_tcp->fwhole = -1;
1035 lnk->data.tcp = aux_tcp;
1037 #ifdef LIBALIAS_DEBUG
1038 fprintf(stderr, "PacketAlias/AddLink: ");
1039 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1046 la->pptpLinkCount++;
1048 case LINK_FRAGMENT_ID:
1049 la->fragmentIdLinkCount++;
1051 case LINK_FRAGMENT_PTR:
1052 la->fragmentPtrLinkCount++;
1057 la->protoLinkCount++;
1061 /* Set up pointers for output lookup table */
1062 start_point = StartPointOut(src_addr, dst_addr,
1063 src_port, dst_port, link_type);
1064 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1066 /* Set up pointers for input lookup table */
1067 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1068 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1070 #ifdef LIBALIAS_DEBUG
1071 fprintf(stderr, "PacketAlias/AddLink(): ");
1072 fprintf(stderr, "malloc() call failed.\n");
1075 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1081 static struct alias_link *
1082 ReLink(struct alias_link *old_lnk,
1083 struct in_addr src_addr,
1084 struct in_addr dst_addr,
1085 struct in_addr alias_addr,
1088 int alias_port_param, /* if less than zero, alias */
1090 { /* port will be automatically *//* chosen.
1091 * If greater than */
1092 struct alias_link *new_lnk; /* zero, equal to alias port */
1093 struct libalias *la = old_lnk->la;
1095 LIBALIAS_LOCK_ASSERT(la);
1096 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1097 src_port, dst_port, alias_port_param,
1100 if (new_lnk != NULL &&
1101 old_lnk->link_type == LINK_TCP &&
1102 old_lnk->data.tcp->fwhole > 0) {
1103 PunchFWHole(new_lnk);
1106 DeleteLink(old_lnk);
1110 static struct alias_link *
1111 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1112 struct in_addr dst_addr,
1116 int replace_partial_links)
1119 struct alias_link *lnk;
1121 LIBALIAS_LOCK_ASSERT(la);
1122 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1123 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1124 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1125 lnk->src_addr.s_addr == src_addr.s_addr &&
1126 lnk->src_port == src_port &&
1127 lnk->dst_port == dst_port &&
1128 lnk->link_type == link_type &&
1129 lnk->server == NULL) {
1130 lnk->timestamp = la->timeStamp;
1135 /* Search for partially specified links. */
1136 if (lnk == NULL && replace_partial_links) {
1137 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1138 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1141 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1142 dst_port, link_type, 0);
1145 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1146 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1151 src_addr, dst_addr, lnk->alias_addr,
1152 src_port, dst_port, lnk->alias_port,
1159 static struct alias_link *
1160 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1161 struct in_addr dst_addr,
1165 int replace_partial_links)
1167 struct alias_link *lnk;
1169 LIBALIAS_LOCK_ASSERT(la);
1170 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1171 link_type, replace_partial_links);
1175 * The following allows permanent links to be specified as
1176 * using the default source address (i.e. device interface
1177 * address) without knowing in advance what that address
1180 if (la->aliasAddress.s_addr != INADDR_ANY &&
1181 src_addr.s_addr == la->aliasAddress.s_addr) {
1182 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1183 link_type, replace_partial_links);
1190 static struct alias_link *
1191 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1192 struct in_addr alias_addr,
1196 int replace_partial_links)
1200 struct alias_link *lnk;
1201 struct alias_link *lnk_fully_specified;
1202 struct alias_link *lnk_unknown_all;
1203 struct alias_link *lnk_unknown_dst_addr;
1204 struct alias_link *lnk_unknown_dst_port;
1206 LIBALIAS_LOCK_ASSERT(la);
1207 /* Initialize pointers */
1208 lnk_fully_specified = NULL;
1209 lnk_unknown_all = NULL;
1210 lnk_unknown_dst_addr = NULL;
1211 lnk_unknown_dst_port = NULL;
1213 /* If either the dest addr or port is unknown, the search
1214 loop will have to know about this. */
1217 if (dst_addr.s_addr == INADDR_ANY)
1218 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1220 flags_in |= LINK_UNKNOWN_DEST_PORT;
1223 start_point = StartPointIn(alias_addr, alias_port, link_type);
1224 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1227 flags = flags_in | lnk->flags;
1228 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1229 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1230 && lnk->alias_port == alias_port
1231 && lnk->dst_addr.s_addr == dst_addr.s_addr
1232 && lnk->dst_port == dst_port
1233 && lnk->link_type == link_type) {
1234 lnk_fully_specified = lnk;
1237 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1238 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1239 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1240 && lnk->alias_port == alias_port
1241 && lnk->link_type == link_type) {
1242 if (lnk_unknown_all == NULL)
1243 lnk_unknown_all = lnk;
1245 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1246 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1247 && lnk->alias_port == alias_port
1248 && lnk->link_type == link_type
1249 && lnk->dst_port == dst_port) {
1250 if (lnk_unknown_dst_addr == NULL)
1251 lnk_unknown_dst_addr = lnk;
1253 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1254 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1255 && lnk->alias_port == alias_port
1256 && lnk->link_type == link_type
1257 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1258 if (lnk_unknown_dst_port == NULL)
1259 lnk_unknown_dst_port = lnk;
1266 if (lnk_fully_specified != NULL) {
1267 lnk_fully_specified->timestamp = la->timeStamp;
1268 lnk = lnk_fully_specified;
1269 } else if (lnk_unknown_dst_port != NULL)
1270 lnk = lnk_unknown_dst_port;
1271 else if (lnk_unknown_dst_addr != NULL)
1272 lnk = lnk_unknown_dst_addr;
1273 else if (lnk_unknown_all != NULL)
1274 lnk = lnk_unknown_all;
1278 if (replace_partial_links &&
1279 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1280 struct in_addr src_addr;
1283 if (lnk->server != NULL) { /* LSNAT link */
1284 src_addr = lnk->server->addr;
1285 src_port = lnk->server->port;
1286 lnk->server = lnk->server->next;
1288 src_addr = lnk->src_addr;
1289 src_port = lnk->src_port;
1292 if (link_type == LINK_SCTP) {
1293 lnk->src_addr = src_addr;
1294 lnk->src_port = src_port;
1298 src_addr, dst_addr, alias_addr,
1299 src_port, dst_port, alias_port,
1305 static struct alias_link *
1306 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1307 struct in_addr alias_addr,
1311 int replace_partial_links)
1313 struct alias_link *lnk;
1315 LIBALIAS_LOCK_ASSERT(la);
1316 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1317 link_type, replace_partial_links);
1321 * The following allows permanent links to be specified as
1322 * using the default aliasing address (i.e. device
1323 * interface address) without knowing in advance what that
1326 if (la->aliasAddress.s_addr != INADDR_ANY &&
1327 alias_addr.s_addr == la->aliasAddress.s_addr) {
1328 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1329 link_type, replace_partial_links);
1338 /* External routines for finding/adding links
1340 -- "external" means outside alias_db.c, but within alias*.c --
1342 FindIcmpIn(), FindIcmpOut()
1343 FindFragmentIn1(), FindFragmentIn2()
1344 AddFragmentPtrLink(), FindFragmentPtr()
1345 FindProtoIn(), FindProtoOut()
1346 FindUdpTcpIn(), FindUdpTcpOut()
1347 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1348 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1349 FindOriginalAddress(), FindAliasAddress()
1351 (prototypes in alias_local.h)
1356 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1357 struct in_addr alias_addr,
1361 struct alias_link *lnk;
1363 LIBALIAS_LOCK_ASSERT(la);
1364 lnk = FindLinkIn(la, dst_addr, alias_addr,
1365 NO_DEST_PORT, id_alias,
1367 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1368 struct in_addr target_addr;
1370 target_addr = FindOriginalAddress(la, alias_addr);
1371 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1372 id_alias, NO_DEST_PORT, id_alias,
1380 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1381 struct in_addr dst_addr,
1385 struct alias_link *lnk;
1387 LIBALIAS_LOCK_ASSERT(la);
1388 lnk = FindLinkOut(la, src_addr, dst_addr,
1391 if (lnk == NULL && create) {
1392 struct in_addr alias_addr;
1394 alias_addr = FindAliasAddress(la, src_addr);
1395 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1396 id, NO_DEST_PORT, GET_ALIAS_ID,
1404 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1405 struct in_addr alias_addr,
1408 struct alias_link *lnk;
1410 LIBALIAS_LOCK_ASSERT(la);
1411 lnk = FindLinkIn(la, dst_addr, alias_addr,
1412 NO_DEST_PORT, ip_id,
1413 LINK_FRAGMENT_ID, 0);
1416 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1417 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1425 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1427 struct in_addr alias_addr, /* is not found. */
1431 LIBALIAS_LOCK_ASSERT(la);
1432 return FindLinkIn(la, dst_addr, alias_addr,
1433 NO_DEST_PORT, ip_id,
1434 LINK_FRAGMENT_ID, 0);
1439 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1443 LIBALIAS_LOCK_ASSERT(la);
1444 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1445 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1451 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1455 LIBALIAS_LOCK_ASSERT(la);
1456 return FindLinkIn(la, dst_addr, la->nullAddress,
1457 NO_DEST_PORT, ip_id,
1458 LINK_FRAGMENT_PTR, 0);
1463 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1464 struct in_addr alias_addr,
1467 struct alias_link *lnk;
1469 LIBALIAS_LOCK_ASSERT(la);
1470 lnk = FindLinkIn(la, dst_addr, alias_addr,
1474 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1475 struct in_addr target_addr;
1477 target_addr = FindOriginalAddress(la, alias_addr);
1478 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1479 NO_SRC_PORT, NO_DEST_PORT, 0,
1487 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1488 struct in_addr dst_addr,
1491 struct alias_link *lnk;
1493 LIBALIAS_LOCK_ASSERT(la);
1494 lnk = FindLinkOut(la, src_addr, dst_addr,
1495 NO_SRC_PORT, NO_DEST_PORT,
1499 struct in_addr alias_addr;
1501 alias_addr = FindAliasAddress(la, src_addr);
1502 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1503 NO_SRC_PORT, NO_DEST_PORT, 0,
1511 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1512 struct in_addr alias_addr,
1519 struct alias_link *lnk;
1521 LIBALIAS_LOCK_ASSERT(la);
1524 link_type = LINK_UDP;
1527 link_type = LINK_TCP;
1534 lnk = FindLinkIn(la, dst_addr, alias_addr,
1535 dst_port, alias_port,
1538 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1539 struct in_addr target_addr;
1541 target_addr = FindOriginalAddress(la, alias_addr);
1542 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1543 alias_port, dst_port, alias_port,
1551 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1552 struct in_addr dst_addr,
1559 struct alias_link *lnk;
1561 LIBALIAS_LOCK_ASSERT(la);
1564 link_type = LINK_UDP;
1567 link_type = LINK_TCP;
1574 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1576 if (lnk == NULL && create) {
1577 struct in_addr alias_addr;
1579 alias_addr = FindAliasAddress(la, src_addr);
1580 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1581 src_port, dst_port, GET_ALIAS_PORT,
1589 AddPptp(struct libalias *la, struct in_addr src_addr,
1590 struct in_addr dst_addr,
1591 struct in_addr alias_addr,
1592 u_int16_t src_call_id)
1594 struct alias_link *lnk;
1596 LIBALIAS_LOCK_ASSERT(la);
1597 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1598 src_call_id, 0, GET_ALIAS_PORT,
1606 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1607 struct in_addr dst_addr,
1608 u_int16_t src_call_id)
1611 struct alias_link *lnk;
1613 LIBALIAS_LOCK_ASSERT(la);
1614 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1615 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1616 if (lnk->link_type == LINK_PPTP &&
1617 lnk->src_addr.s_addr == src_addr.s_addr &&
1618 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1619 lnk->src_port == src_call_id)
1627 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1628 struct in_addr dst_addr,
1629 u_int16_t dst_call_id)
1632 struct alias_link *lnk;
1634 LIBALIAS_LOCK_ASSERT(la);
1635 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1636 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1637 if (lnk->link_type == LINK_PPTP &&
1638 lnk->src_addr.s_addr == src_addr.s_addr &&
1639 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1640 lnk->dst_port == dst_call_id)
1648 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1649 struct in_addr alias_addr,
1650 u_int16_t dst_call_id)
1653 struct alias_link *lnk;
1655 LIBALIAS_LOCK_ASSERT(la);
1656 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1657 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1658 if (lnk->link_type == LINK_PPTP &&
1659 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1660 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1661 lnk->dst_port == dst_call_id)
1669 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1670 struct in_addr alias_addr,
1671 u_int16_t alias_call_id)
1673 struct alias_link *lnk;
1675 LIBALIAS_LOCK_ASSERT(la);
1676 lnk = FindLinkIn(la, dst_addr, alias_addr,
1677 0 /* any */ , alias_call_id,
1686 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1687 struct in_addr dst_addr,
1693 struct alias_link *lnk;
1695 LIBALIAS_LOCK_ASSERT(la);
1698 link_type = LINK_UDP;
1701 link_type = LINK_TCP;
1708 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1711 struct in_addr alias_addr;
1713 alias_addr = FindAliasAddress(la, src_addr);
1714 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1715 src_port, 0, alias_port,
1723 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1725 struct alias_link *lnk;
1727 LIBALIAS_LOCK_ASSERT(la);
1728 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1729 0, 0, LINK_ADDR, 0);
1731 la->newDefaultLink = 1;
1732 if (la->targetAddress.s_addr == INADDR_ANY)
1733 return (alias_addr);
1734 else if (la->targetAddress.s_addr == INADDR_NONE)
1735 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1736 la->aliasAddress : alias_addr;
1738 return (la->targetAddress);
1740 if (lnk->server != NULL) { /* LSNAT link */
1741 struct in_addr src_addr;
1743 src_addr = lnk->server->addr;
1744 lnk->server = lnk->server->next;
1746 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1747 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1748 la->aliasAddress : alias_addr;
1750 return (lnk->src_addr);
1756 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1758 struct alias_link *lnk;
1760 LIBALIAS_LOCK_ASSERT(la);
1761 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1762 0, 0, LINK_ADDR, 0);
1764 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1765 la->aliasAddress : original_addr;
1767 if (lnk->alias_addr.s_addr == INADDR_ANY)
1768 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1769 la->aliasAddress : original_addr;
1771 return (lnk->alias_addr);
1776 /* External routines for getting or changing link data
1777 (external to alias_db.c, but internal to alias*.c)
1779 SetFragmentData(), GetFragmentData()
1780 SetFragmentPtr(), GetFragmentPtr()
1781 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1782 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1783 GetOriginalPort(), GetAliasPort()
1784 SetAckModified(), GetAckModified()
1785 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1786 SetProtocolFlags(), GetProtocolFlags()
1792 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1794 lnk->data.frag_addr = src_addr;
1799 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1801 *src_addr = lnk->data.frag_addr;
1806 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1808 lnk->data.frag_ptr = fptr;
1813 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1815 *fptr = lnk->data.frag_ptr;
1820 SetStateIn(struct alias_link *lnk, int state)
1822 /* TCP input state */
1824 case ALIAS_TCP_STATE_DISCONNECTED:
1825 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1826 lnk->expire_time = TCP_EXPIRE_DEAD;
1828 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1830 case ALIAS_TCP_STATE_CONNECTED:
1831 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1832 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1836 panic("libalias:SetStateIn() unknown state");
1841 lnk->data.tcp->state.in = state;
1846 SetStateOut(struct alias_link *lnk, int state)
1848 /* TCP output state */
1850 case ALIAS_TCP_STATE_DISCONNECTED:
1851 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1852 lnk->expire_time = TCP_EXPIRE_DEAD;
1854 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1856 case ALIAS_TCP_STATE_CONNECTED:
1857 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1858 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1862 panic("libalias:SetStateOut() unknown state");
1867 lnk->data.tcp->state.out = state;
1872 GetStateIn(struct alias_link *lnk)
1874 /* TCP input state */
1875 return (lnk->data.tcp->state.in);
1880 GetStateOut(struct alias_link *lnk)
1882 /* TCP output state */
1883 return (lnk->data.tcp->state.out);
1888 GetOriginalAddress(struct alias_link *lnk)
1890 if (lnk->src_addr.s_addr == INADDR_ANY)
1891 return (lnk->la->aliasAddress);
1893 return (lnk->src_addr);
1898 GetDestAddress(struct alias_link *lnk)
1900 return (lnk->dst_addr);
1905 GetAliasAddress(struct alias_link *lnk)
1907 if (lnk->alias_addr.s_addr == INADDR_ANY)
1908 return (lnk->la->aliasAddress);
1910 return (lnk->alias_addr);
1915 GetDefaultAliasAddress(struct libalias *la)
1918 LIBALIAS_LOCK_ASSERT(la);
1919 return (la->aliasAddress);
1924 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1927 LIBALIAS_LOCK_ASSERT(la);
1928 la->aliasAddress = alias_addr;
1933 GetOriginalPort(struct alias_link *lnk)
1935 return (lnk->src_port);
1940 GetAliasPort(struct alias_link *lnk)
1942 return (lnk->alias_port);
1947 GetDestPort(struct alias_link *lnk)
1949 return (lnk->dst_port);
1955 SetAckModified(struct alias_link *lnk)
1957 /* Indicate that ACK numbers have been modified in a TCP connection */
1958 lnk->data.tcp->state.ack_modified = 1;
1963 GetProxyAddress(struct alias_link *lnk)
1965 return (lnk->proxy_addr);
1970 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1972 lnk->proxy_addr = addr;
1977 GetProxyPort(struct alias_link *lnk)
1979 return (lnk->proxy_port);
1984 SetProxyPort(struct alias_link *lnk, u_short port)
1986 lnk->proxy_port = port;
1991 GetAckModified(struct alias_link *lnk)
1993 /* See if ACK numbers have been modified */
1994 return (lnk->data.tcp->state.ack_modified);
1999 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
2002 Find out how much the ACK number has been altered for an incoming
2003 TCP packet. To do this, a circular list of ACK numbers where the TCP
2004 packet size was altered is searched.
2008 int delta, ack_diff_min;
2012 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2013 struct ack_data_record x;
2015 x = lnk->data.tcp->ack[i];
2016 if (x.active == 1) {
2019 ack_diff = SeqDiff(x.ack_new, ack);
2020 if (ack_diff >= 0) {
2021 if (ack_diff_min >= 0) {
2022 if (ack_diff < ack_diff_min) {
2024 ack_diff_min = ack_diff;
2028 ack_diff_min = ack_diff;
2038 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
2041 Find out how much the sequence number has been altered for an outgoing
2042 TCP packet. To do this, a circular list of ACK numbers where the TCP
2043 packet size was altered is searched.
2047 int delta, seq_diff_min;
2051 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2052 struct ack_data_record x;
2054 x = lnk->data.tcp->ack[i];
2055 if (x.active == 1) {
2058 seq_diff = SeqDiff(x.ack_old, seq);
2059 if (seq_diff >= 0) {
2060 if (seq_diff_min >= 0) {
2061 if (seq_diff < seq_diff_min) {
2063 seq_diff_min = seq_diff;
2067 seq_diff_min = seq_diff;
2077 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len,
2078 u_long th_seq, u_int th_off)
2081 When a TCP packet has been altered in length, save this
2082 information in a circular list. If enough packets have
2083 been altered, then this list will begin to overwrite itself.
2086 struct ack_data_record x;
2087 int hlen, tlen, dlen;
2090 hlen = (ip_hl + th_off) << 2;
2091 tlen = ntohs(ip_len);
2094 x.ack_old = htonl(ntohl(th_seq) + dlen);
2095 x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
2099 i = lnk->data.tcp->state.index;
2100 lnk->data.tcp->ack[i] = x;
2103 if (i == N_LINK_TCP_DATA)
2104 lnk->data.tcp->state.index = 0;
2106 lnk->data.tcp->state.index = i;
2110 SetExpire(struct alias_link *lnk, int expire)
2113 lnk->flags &= ~LINK_PERMANENT;
2115 } else if (expire == -1) {
2116 lnk->flags |= LINK_PERMANENT;
2117 } else if (expire > 0) {
2118 lnk->expire_time = expire;
2120 #ifdef LIBALIAS_DEBUG
2121 fprintf(stderr, "PacketAlias/SetExpire(): ");
2122 fprintf(stderr, "error in expire parameter\n");
2128 ClearCheckNewLink(struct libalias *la)
2131 LIBALIAS_LOCK_ASSERT(la);
2132 la->newDefaultLink = 0;
2136 SetProtocolFlags(struct alias_link *lnk, int pflags)
2139 lnk->pflags = pflags;;
2143 GetProtocolFlags(struct alias_link *lnk)
2146 return (lnk->pflags);
2150 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2152 struct libalias *la = lnk->la;
2154 LIBALIAS_LOCK_ASSERT(la);
2155 la->deleteAllLinks = 1;
2156 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2157 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2158 la->deleteAllLinks = 0;
2162 /* Miscellaneous Functions
2165 InitPacketAliasLog()
2166 UninitPacketAliasLog()
2170 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2171 is called to find and remove timed-out aliasing links. Logic exists
2172 to sweep through the entire table and linked list structure
2175 (prototype in alias_local.h)
2179 HouseKeeping(struct libalias *la)
2187 LIBALIAS_LOCK_ASSERT(la);
2189 * Save system time (seconds) in global variable timeStamp for use
2190 * by other functions. This is done so as not to unnecessarily
2191 * waste timeline by making system calls.
2194 la->timeStamp = time_uptime;
2196 gettimeofday(&tv, &tz);
2197 la->timeStamp = tv.tv_sec;
2200 /* Compute number of spokes (output table link chains) to cover */
2201 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2202 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2204 /* Handle different cases */
2206 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2207 n = ALIAS_CLEANUP_MAX_SPOKES;
2208 la->lastCleanupTime = la->timeStamp;
2209 for (i = 0; i < n; i++)
2210 IncrementalCleanup(la);
2212 #ifdef LIBALIAS_DEBUG
2213 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2214 fprintf(stderr, "something unexpected in time values\n");
2216 la->lastCleanupTime = la->timeStamp;
2220 /* Init the log file and enable logging */
2222 InitPacketAliasLog(struct libalias *la)
2225 LIBALIAS_LOCK_ASSERT(la);
2226 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2228 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2231 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2232 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2235 return (ENOMEM); /* log initialization failed */
2236 la->packetAliasMode |= PKT_ALIAS_LOG;
2242 /* Close the log-file and disable logging. */
2244 UninitPacketAliasLog(struct libalias *la)
2247 LIBALIAS_LOCK_ASSERT(la);
2252 fclose(la->logDesc);
2256 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2259 /* Outside world interfaces
2261 -- "outside world" means other than alias*.c routines --
2263 PacketAliasRedirectPort()
2264 PacketAliasAddServer()
2265 PacketAliasRedirectProto()
2266 PacketAliasRedirectAddr()
2267 PacketAliasRedirectDynamic()
2268 PacketAliasRedirectDelete()
2269 PacketAliasSetAddress()
2272 PacketAliasSetMode()
2274 (prototypes in alias.h)
2277 /* Redirection from a specific public addr:port to a
2278 private addr:port */
2280 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2281 struct in_addr dst_addr, u_short dst_port,
2282 struct in_addr alias_addr, u_short alias_port,
2286 struct alias_link *lnk;
2291 link_type = LINK_UDP;
2294 link_type = LINK_TCP;
2297 link_type = LINK_SCTP;
2300 #ifdef LIBALIAS_DEBUG
2301 fprintf(stderr, "PacketAliasRedirectPort(): ");
2302 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
2308 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2309 src_port, dst_port, alias_port,
2313 lnk->flags |= LINK_PERMANENT;
2315 #ifdef LIBALIAS_DEBUG
2317 fprintf(stderr, "PacketAliasRedirectPort(): "
2318 "call to AddLink() failed\n");
2323 LIBALIAS_UNLOCK(la);
2327 /* Add server to the pool of servers */
2329 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2331 struct server *server;
2337 server = malloc(sizeof(struct server));
2339 if (server != NULL) {
2340 struct server *head;
2342 server->addr = addr;
2343 server->port = port;
2347 server->next = server;
2351 for (s = head; s->next != head; s = s->next);
2353 server->next = head;
2355 lnk->server = server;
2360 LIBALIAS_UNLOCK(la);
2364 /* Redirect packets of a given IP protocol from a specific
2365 public address to a private address */
2367 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2368 struct in_addr dst_addr,
2369 struct in_addr alias_addr,
2372 struct alias_link *lnk;
2375 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2376 NO_SRC_PORT, NO_DEST_PORT, 0,
2380 lnk->flags |= LINK_PERMANENT;
2382 #ifdef LIBALIAS_DEBUG
2384 fprintf(stderr, "PacketAliasRedirectProto(): "
2385 "call to AddLink() failed\n");
2389 LIBALIAS_UNLOCK(la);
2393 /* Static address translation */
2395 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2396 struct in_addr alias_addr)
2398 struct alias_link *lnk;
2401 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2406 lnk->flags |= LINK_PERMANENT;
2408 #ifdef LIBALIAS_DEBUG
2410 fprintf(stderr, "PacketAliasRedirectAddr(): "
2411 "call to AddLink() failed\n");
2415 LIBALIAS_UNLOCK(la);
2420 /* Mark the aliasing link dynamic */
2422 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2429 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2432 lnk->flags &= ~LINK_PERMANENT;
2435 LIBALIAS_UNLOCK(la);
2441 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2443 /* This is a dangerous function to put in the API,
2444 because an invalid pointer can crash the program. */
2447 la->deleteAllLinks = 1;
2449 la->deleteAllLinks = 0;
2450 LIBALIAS_UNLOCK(la);
2455 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2459 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2460 && la->aliasAddress.s_addr != addr.s_addr)
2461 CleanupAliasData(la);
2463 la->aliasAddress = addr;
2464 LIBALIAS_UNLOCK(la);
2469 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2473 la->targetAddress = target_addr;
2474 LIBALIAS_UNLOCK(la);
2481 while (!LIST_EMPTY(&instancehead))
2482 LibAliasUninit(LIST_FIRST(&instancehead));
2486 LibAliasInit(struct libalias *la)
2495 la = calloc(sizeof *la, 1);
2499 #ifndef _KERNEL /* kernel cleans up on module unload */
2500 if (LIST_EMPTY(&instancehead))
2503 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2506 la->timeStamp = time_uptime;
2507 la->lastCleanupTime = time_uptime;
2509 gettimeofday(&tv, &tz);
2510 la->timeStamp = tv.tv_sec;
2511 la->lastCleanupTime = tv.tv_sec;
2514 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2515 LIST_INIT(&la->linkTableOut[i]);
2516 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2517 LIST_INIT(&la->linkTableIn[i]);
2521 LIBALIAS_LOCK_INIT(la);
2525 la->deleteAllLinks = 1;
2526 CleanupAliasData(la);
2527 la->deleteAllLinks = 0;
2534 la->aliasAddress.s_addr = INADDR_ANY;
2535 la->targetAddress.s_addr = INADDR_ANY;
2537 la->icmpLinkCount = 0;
2538 la->udpLinkCount = 0;
2539 la->tcpLinkCount = 0;
2540 la->sctpLinkCount = 0;
2541 la->pptpLinkCount = 0;
2542 la->protoLinkCount = 0;
2543 la->fragmentIdLinkCount = 0;
2544 la->fragmentPtrLinkCount = 0;
2547 la->cleanupIndex = 0;
2549 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2550 #ifndef NO_USE_SOCKETS
2551 | PKT_ALIAS_USE_SOCKETS
2553 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2555 la->fireWallFD = -1;
2558 LibAliasRefreshModules();
2560 LIBALIAS_UNLOCK(la);
2565 LibAliasUninit(struct libalias *la)
2572 la->deleteAllLinks = 1;
2573 CleanupAliasData(la);
2574 la->deleteAllLinks = 0;
2575 UninitPacketAliasLog(la);
2579 LIST_REMOVE(la, instancelist);
2580 LIBALIAS_UNLOCK(la);
2581 LIBALIAS_LOCK_DESTROY(la);
2585 /* Change mode for some operations */
2588 struct libalias *la,
2589 unsigned int flags, /* Which state to bring flags to */
2590 unsigned int mask /* Mask of which flags to affect (use 0 to
2591 * do a probe for flag values) */
2597 /* Enable logging? */
2598 if (flags & mask & PKT_ALIAS_LOG) {
2600 if (InitPacketAliasLog(la) == ENOMEM)
2603 /* _Disable_ logging? */
2604 if (~flags & mask & PKT_ALIAS_LOG) {
2605 UninitPacketAliasLog(la);
2608 /* Start punching holes in the firewall? */
2609 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2612 /* Stop punching holes in the firewall? */
2613 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2618 /* Other flags can be set/cleared without special action */
2619 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2620 res = la->packetAliasMode;
2622 LIBALIAS_UNLOCK(la);
2628 LibAliasCheckNewLink(struct libalias *la)
2633 res = la->newDefaultLink;
2634 LIBALIAS_UNLOCK(la);
2642 Code to support firewall punching. This shouldn't really be in this
2643 file, but making variables global is evil too.
2646 /* Firewall include files */
2648 #include <netinet/ip_fw.h>
2653 * helper function, updates the pointer to cmd with the length
2654 * of the current command, and also cleans up the first word of
2655 * the new command in case it has been clobbered before.
2658 next_cmd(ipfw_insn * cmd)
2661 bzero(cmd, sizeof(*cmd));
2666 * A function to fill simple commands of size 1.
2667 * Existing flags are preserved.
2670 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2671 int flags, u_int16_t arg)
2673 cmd->opcode = opcode;
2674 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2676 return next_cmd(cmd);
2680 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2682 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2684 cmd->addr.s_addr = addr;
2685 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2689 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2691 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2693 cmd->ports[0] = cmd->ports[1] = port;
2694 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2698 fill_rule(void *buf, int bufsize, int rulenum,
2699 enum ipfw_opcodes action, int proto,
2700 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2702 struct ip_fw *rule = (struct ip_fw *)buf;
2703 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2705 bzero(buf, bufsize);
2706 rule->rulenum = rulenum;
2708 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2709 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2710 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2711 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2712 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2714 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2715 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2717 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2719 return ((char *)cmd - (char *)buf);
2722 static void ClearAllFWHoles(struct libalias *la);
2725 #define fw_setfield(la, field, num) \
2727 (field)[(num) - la->fireWallBaseNum] = 1; \
2728 } /*lint -save -e717 */ while(0)/* lint -restore */
2730 #define fw_clrfield(la, field, num) \
2732 (field)[(num) - la->fireWallBaseNum] = 0; \
2733 } /*lint -save -e717 */ while(0)/* lint -restore */
2735 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2738 InitPunchFW(struct libalias *la)
2741 LIBALIAS_LOCK_ASSERT(la);
2742 la->fireWallField = malloc(la->fireWallNumNums);
2743 if (la->fireWallField) {
2744 memset(la->fireWallField, 0, la->fireWallNumNums);
2745 if (la->fireWallFD < 0) {
2746 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2748 ClearAllFWHoles(la);
2749 la->fireWallActiveNum = la->fireWallBaseNum;
2754 UninitPunchFW(struct libalias *la)
2757 LIBALIAS_LOCK_ASSERT(la);
2758 ClearAllFWHoles(la);
2759 if (la->fireWallFD >= 0)
2760 close(la->fireWallFD);
2761 la->fireWallFD = -1;
2762 if (la->fireWallField)
2763 free(la->fireWallField);
2764 la->fireWallField = NULL;
2765 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2768 /* Make a certain link go through the firewall */
2770 PunchFWHole(struct alias_link *lnk)
2772 struct libalias *la;
2773 int r; /* Result code */
2774 struct ip_fw rule; /* On-the-fly built rule */
2775 int fwhole; /* Where to punch hole */
2777 LIBALIAS_LOCK_ASSERT(la);
2780 /* Don't do anything unless we are asked to */
2781 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2782 la->fireWallFD < 0 ||
2783 lnk->link_type != LINK_TCP)
2786 memset(&rule, 0, sizeof rule);
2790 /* Find empty slot */
2791 for (fwhole = la->fireWallActiveNum;
2792 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2793 fw_tstfield(la, la->fireWallField, fwhole);
2795 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2796 for (fwhole = la->fireWallBaseNum;
2797 fwhole < la->fireWallActiveNum &&
2798 fw_tstfield(la, la->fireWallField, fwhole);
2800 if (fwhole == la->fireWallActiveNum) {
2801 /* No rule point empty - we can't punch more holes. */
2802 la->fireWallActiveNum = la->fireWallBaseNum;
2803 #ifdef LIBALIAS_DEBUG
2804 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2809 /* Start next search at next position */
2810 la->fireWallActiveNum = fwhole + 1;
2813 * generate two rules of the form
2815 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2816 * accept tcp from DAddr DPort to OAddr OPort
2818 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2819 u_int32_t rulebuf[255];
2822 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2823 O_ACCEPT, IPPROTO_TCP,
2824 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2825 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2826 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2828 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2830 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2831 O_ACCEPT, IPPROTO_TCP,
2832 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2833 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2834 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2836 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2839 /* Indicate hole applied */
2840 lnk->data.tcp->fwhole = fwhole;
2841 fw_setfield(la, la->fireWallField, fwhole);
2844 /* Remove a hole in a firewall associated with a particular alias
2845 lnk. Calling this too often is harmless. */
2847 ClearFWHole(struct alias_link *lnk)
2849 struct libalias *la;
2851 LIBALIAS_LOCK_ASSERT(la);
2853 if (lnk->link_type == LINK_TCP) {
2854 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2861 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2862 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2863 &fwhole, sizeof fwhole));
2864 fw_clrfield(la, la->fireWallField, fwhole);
2865 lnk->data.tcp->fwhole = -1;
2869 /* Clear out the entire range dedicated to firewall holes. */
2871 ClearAllFWHoles(struct libalias *la)
2873 struct ip_fw rule; /* On-the-fly built rule */
2876 LIBALIAS_LOCK_ASSERT(la);
2877 if (la->fireWallFD < 0)
2880 memset(&rule, 0, sizeof rule);
2881 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2884 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2886 /* XXX: third arg correct here ? /phk */
2887 memset(la->fireWallField, 0, la->fireWallNumNums);
2893 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2898 la->fireWallBaseNum = base;
2899 la->fireWallNumNums = num;
2901 LIBALIAS_UNLOCK(la);
2905 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2909 la->skinnyPort = port;
2910 LIBALIAS_UNLOCK(la);
2914 * Find the address to redirect incoming packets
2917 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm)
2919 struct alias_link *lnk;
2920 struct in_addr redir;
2922 LIBALIAS_LOCK_ASSERT(la);
2923 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2924 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2926 return(lnk->src_addr); /* port redirect */
2928 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2929 if (redir.s_addr == la->aliasAddress.s_addr ||
2930 redir.s_addr == la->targetAddress.s_addr) { /* No address found */
2931 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2932 NO_DEST_PORT, 0, LINK_SCTP, 1);
2934 return(lnk->src_addr); /* redirect proto */
2936 return(redir); /* address redirect */