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/module.h>
150 #include <sys/syslog.h>
155 #include <sys/errno.h>
156 #include <sys/time.h>
160 #include <sys/socket.h>
161 #include <netinet/tcp.h>
164 #include <netinet/libalias/alias.h>
165 #include <netinet/libalias/alias_local.h>
166 #include <netinet/libalias/alias_mod.h>
170 #include "alias_local.h"
171 #include "alias_mod.h"
174 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
178 Constants (note: constants are also defined
179 near relevant functions or structs)
182 /* Parameters used for cleanup of expired links */
183 #define ALIAS_CLEANUP_INTERVAL_SECS 60
184 #define ALIAS_CLEANUP_MAX_SPOKES 30
186 /* Timeouts (in seconds) for different link types */
187 #define ICMP_EXPIRE_TIME 60
188 #define UDP_EXPIRE_TIME 60
189 #define PROTO_EXPIRE_TIME 60
190 #define FRAGMENT_ID_EXPIRE_TIME 10
191 #define FRAGMENT_PTR_EXPIRE_TIME 30
193 /* TCP link expire time for different cases */
194 /* When the link has been used and closed - minimal grace time to
195 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
196 #ifndef TCP_EXPIRE_DEAD
197 #define TCP_EXPIRE_DEAD 10
200 /* When the link has been used and closed on one side - the other side
201 is allowed to still send data */
202 #ifndef TCP_EXPIRE_SINGLEDEAD
203 #define TCP_EXPIRE_SINGLEDEAD 90
206 /* When the link isn't yet up */
207 #ifndef TCP_EXPIRE_INITIAL
208 #define TCP_EXPIRE_INITIAL 300
211 /* When the link is up */
212 #ifndef TCP_EXPIRE_CONNECTED
213 #define TCP_EXPIRE_CONNECTED 86400
217 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
218 These constants can be anything except zero, which indicates an
219 unknown port number. */
221 #define NO_DEST_PORT 1
222 #define NO_SRC_PORT 1
228 The fundamental data structure used in this program is
229 "struct alias_link". Whenever a TCP connection is made,
230 a UDP datagram is sent out, or an ICMP echo request is made,
231 a link record is made (if it has not already been created).
232 The link record is identified by the source address/port
233 and the destination address/port. In the case of an ICMP
234 echo request, the source port is treated as being equivalent
235 with the 16-bit ID number of the ICMP packet.
237 The link record also can store some auxiliary data. For
238 TCP connections that have had sequence and acknowledgment
239 modifications, data space is available to track these changes.
240 A state field is used to keep track in changes to the TCP
241 connection state. ID numbers of fragments can also be
242 stored in the auxiliary space. Pointers to unresolved
243 fragments can also be stored.
245 The link records support two independent chainings. Lookup
246 tables for input and out tables hold the initial pointers
247 the link chains. On input, the lookup table indexes on alias
248 port and link type. On output, the lookup table indexes on
249 source address, destination address, source port, destination
253 struct ack_data_record { /* used to save changes to ACK/sequence
261 struct tcp_state { /* Information about TCP connection */
262 int in; /* State for outside -> inside */
263 int out; /* State for inside -> outside */
264 int index; /* Index to ACK data array */
265 int ack_modified; /* Indicates whether ACK and
266 * sequence numbers */
270 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
271 * saved for a modified TCP stream */
273 struct tcp_state state;
274 struct ack_data_record ack[N_LINK_TCP_DATA];
275 int fwhole; /* Which firewall record is used for this
279 struct server { /* LSNAT server pool (circular list) */
285 struct alias_link { /* Main data structure */
287 struct in_addr src_addr; /* Address and port information */
288 struct in_addr dst_addr;
289 struct in_addr alias_addr;
290 struct in_addr proxy_addr;
295 struct server *server;
297 int link_type; /* Type of link: TCP, UDP, ICMP,
300 /* values for link_type */
301 #define LINK_ICMP IPPROTO_ICMP
302 #define LINK_UDP IPPROTO_UDP
303 #define LINK_TCP IPPROTO_TCP
304 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
305 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
306 #define LINK_ADDR (IPPROTO_MAX + 3)
307 #define LINK_PPTP (IPPROTO_MAX + 4)
309 int flags; /* indicates special characteristics */
310 int pflags; /* protocol-specific flags */
313 #define LINK_UNKNOWN_DEST_PORT 0x01
314 #define LINK_UNKNOWN_DEST_ADDR 0x02
315 #define LINK_PERMANENT 0x04
316 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
317 #define LINK_UNFIREWALLED 0x08
319 int timestamp; /* Time link was last accessed */
320 int expire_time; /* Expire time for link */
321 #ifndef NO_USE_SOCKETS
322 int sockfd; /* socket descriptor */
324 LIST_ENTRY (alias_link) list_out; /* Linked list of
326 LIST_ENTRY (alias_link) list_in; /* input and output
329 union { /* Auxiliary data */
331 struct in_addr frag_addr;
336 /* Clean up procedure. */
337 static void finishoff(void);
339 /* Kernel module definition. */
341 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
343 MODULE_VERSION(libalias, 1);
346 alias_mod_handler(module_t mod, int type, void *data)
353 handler_chain_init();
357 handler_chain_destroy();
368 static moduledata_t alias_mod = {
369 "alias", alias_mod_handler, NULL
372 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
375 /* Internal utility routines (used only in alias_db.c)
377 Lookup table starting points:
378 StartPointIn() -- link table initial search point for
380 StartPointOut() -- link table initial search point for
384 SeqDiff() -- difference between two TCP sequences
385 ShowAliasStats() -- send alias statistics to a monitor file
389 /* Local prototypes */
390 static u_int StartPointIn(struct in_addr, u_short, int);
393 StartPointOut(struct in_addr, struct in_addr,
394 u_short, u_short, int);
396 static int SeqDiff(u_long, u_long);
399 /* Firewall control */
400 static void InitPunchFW(struct libalias *);
401 static void UninitPunchFW(struct libalias *);
402 static void ClearFWHole(struct alias_link *);
406 /* Log file control */
407 static void ShowAliasStats(struct libalias *);
408 static int InitPacketAliasLog(struct libalias *);
409 static void UninitPacketAliasLog(struct libalias *);
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->tcpLinkCount + la->pptpLinkCount +
490 la->protoLinkCount + la->fragmentIdLinkCount +
491 la->fragmentPtrLinkCount;
493 AliasLog(la->logDesc,
494 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
500 la->fragmentIdLinkCount,
501 la->fragmentPtrLinkCount, tot);
503 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
508 /* Internal routines for finding, deleting and adding links
511 GetNewPort() -- find and reserve new alias port number
512 GetSocket() -- try to allocate a socket for a given port
514 Link creation and deletion:
515 CleanupAliasData() - remove all link chains from lookup table
516 IncrementalCleanup() - look for stale links in a single chain
517 DeleteLink() - remove link
519 ReLink() - change link
522 FindLinkOut() - find link for outgoing packets
523 FindLinkIn() - find link for incoming packets
526 FindNewPortGroup() - find an available group of ports
529 /* Local prototypes */
530 static int GetNewPort(struct libalias *, struct alias_link *, int);
531 #ifndef NO_USE_SOCKETS
532 static u_short GetSocket(struct libalias *, u_short, int *, int);
534 static void CleanupAliasData(struct libalias *);
536 static void IncrementalCleanup(struct libalias *);
538 static void DeleteLink(struct alias_link *);
540 static struct alias_link *
541 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
542 u_short, u_short, int, int);
544 static struct alias_link *
545 ReLink(struct alias_link *,
546 struct in_addr, struct in_addr, struct in_addr,
547 u_short, u_short, int, int);
549 static struct alias_link *
550 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
552 static struct alias_link *
553 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
556 #define ALIAS_PORT_BASE 0x08000
557 #define ALIAS_PORT_MASK 0x07fff
558 #define ALIAS_PORT_MASK_EVEN 0x07ffe
559 #define GET_NEW_PORT_MAX_ATTEMPTS 20
561 #define GET_ALIAS_PORT -1
562 #define GET_ALIAS_ID GET_ALIAS_PORT
564 #define FIND_EVEN_ALIAS_BASE 1
566 /* GetNewPort() allocates port numbers. Note that if a port number
567 is already in use, that does not mean that it cannot be used by
568 another link concurrently. This is because GetNewPort() looks for
569 unused triplets: (dest addr, dest port, alias port). */
572 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
579 LIBALIAS_LOCK_ASSERT(la);
581 Description of alias_port_param for GetNewPort(). When
582 this parameter is zero or positive, it precisely specifies
583 the port number. GetNewPort() will return this number
584 without check that it is in use.
586 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
587 selected port number.
590 if (alias_port_param == GET_ALIAS_PORT) {
592 * The aliasing port is automatically selected by one of
595 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
597 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
599 * When the PKT_ALIAS_SAME_PORTS option is chosen,
600 * the first try will be the actual source port. If
601 * this is already in use, the remainder of the
602 * trials will be random.
604 port_net = lnk->src_port;
605 port_sys = ntohs(port_net);
607 /* First trial and all subsequent are random. */
608 port_sys = random() & ALIAS_PORT_MASK;
609 port_sys += ALIAS_PORT_BASE;
610 port_net = htons(port_sys);
612 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
613 lnk->alias_port = (u_short) alias_port_param;
616 #ifdef LIBALIAS_DEBUG
617 fprintf(stderr, "PacketAlias/GetNewPort(): ");
618 fprintf(stderr, "input parameter error\n");
624 /* Port number search */
625 for (i = 0; i < max_trials; i++) {
627 struct alias_link *search_result;
629 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
630 lnk->dst_port, port_net,
633 if (search_result == NULL)
635 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
636 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
642 #ifndef NO_USE_SOCKETS
643 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
644 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
645 && ((lnk->link_type == LINK_TCP) ||
646 (lnk->link_type == LINK_UDP))) {
647 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
648 lnk->alias_port = port_net;
653 lnk->alias_port = port_net;
655 #ifndef NO_USE_SOCKETS
659 port_sys = random() & ALIAS_PORT_MASK;
660 port_sys += ALIAS_PORT_BASE;
661 port_net = htons(port_sys);
664 #ifdef LIBALIAS_DEBUG
665 fprintf(stderr, "PacketAlias/GetnewPort(): ");
666 fprintf(stderr, "could not find free port\n");
672 #ifndef NO_USE_SOCKETS
674 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
678 struct sockaddr_in sock_addr;
680 LIBALIAS_LOCK_ASSERT(la);
681 if (link_type == LINK_TCP)
682 sock = socket(AF_INET, SOCK_STREAM, 0);
683 else if (link_type == LINK_UDP)
684 sock = socket(AF_INET, SOCK_DGRAM, 0);
686 #ifdef LIBALIAS_DEBUG
687 fprintf(stderr, "PacketAlias/GetSocket(): ");
688 fprintf(stderr, "incorrect link type\n");
694 #ifdef LIBALIAS_DEBUG
695 fprintf(stderr, "PacketAlias/GetSocket(): ");
696 fprintf(stderr, "socket() error %d\n", *sockfd);
700 sock_addr.sin_family = AF_INET;
701 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
702 sock_addr.sin_port = port_net;
705 (struct sockaddr *)&sock_addr,
718 /* FindNewPortGroup() returns a base port number for an available
719 range of contiguous port numbers. Note that if a port number
720 is already in use, that does not mean that it cannot be used by
721 another link concurrently. This is because FindNewPortGroup()
722 looks for unused triplets: (dest addr, dest port, alias port). */
725 FindNewPortGroup(struct libalias *la,
726 struct in_addr dst_addr,
727 struct in_addr alias_addr,
739 LIBALIAS_LOCK_ASSERT(la);
741 * Get link_type from protocol
746 link_type = LINK_UDP;
749 link_type = LINK_TCP;
757 * The aliasing port is automatically selected by one of two
760 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
762 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
764 * When the ALIAS_SAME_PORTS option is chosen, the first
765 * try will be the actual source port. If this is already
766 * in use, the remainder of the trials will be random.
768 port_sys = ntohs(src_port);
772 /* First trial and all subsequent are random. */
773 if (align == FIND_EVEN_ALIAS_BASE)
774 port_sys = random() & ALIAS_PORT_MASK_EVEN;
776 port_sys = random() & ALIAS_PORT_MASK;
778 port_sys += ALIAS_PORT_BASE;
781 /* Port number search */
782 for (i = 0; i < max_trials; i++) {
784 struct alias_link *search_result;
786 for (j = 0; j < port_count; j++)
787 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
788 dst_port, htons(port_sys + j),
792 /* Found a good range, return base */
794 return (htons(port_sys));
796 /* Find a new base to try */
797 if (align == FIND_EVEN_ALIAS_BASE)
798 port_sys = random() & ALIAS_PORT_MASK_EVEN;
800 port_sys = random() & ALIAS_PORT_MASK;
802 port_sys += ALIAS_PORT_BASE;
805 #ifdef LIBALIAS_DEBUG
806 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
807 fprintf(stderr, "could not find free port(s)\n");
814 CleanupAliasData(struct libalias *la)
816 struct alias_link *lnk;
819 LIBALIAS_LOCK_ASSERT(la);
821 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
822 lnk = LIST_FIRST(&la->linkTableOut[i]);
823 while (lnk != NULL) {
824 struct alias_link *link_next;
826 link_next = LIST_NEXT(lnk, list_out);
833 la->cleanupIndex = 0;
838 IncrementalCleanup(struct libalias *la)
841 struct alias_link *lnk;
843 LIBALIAS_LOCK_ASSERT(la);
845 lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
846 while (lnk != NULL) {
848 struct alias_link *link_next;
850 link_next = LIST_NEXT(lnk, list_out);
851 idelta = la->timeStamp - lnk->timestamp;
852 switch (lnk->link_type) {
854 if (idelta > lnk->expire_time) {
855 struct tcp_dat *tcp_aux;
857 tcp_aux = lnk->data.tcp;
858 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
859 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) {
866 if (idelta > lnk->expire_time) {
875 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
876 la->cleanupIndex = 0;
880 DeleteLink(struct alias_link *lnk)
882 struct libalias *la = lnk->la;
884 LIBALIAS_LOCK_ASSERT(la);
885 /* Don't do anything if the link is marked permanent */
886 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
890 /* Delete associated firewall hole, if any */
894 /* Free memory allocated for LSNAT server pool */
895 if (lnk->server != NULL) {
896 struct server *head, *curr, *next;
898 head = curr = lnk->server;
902 } while ((curr = next) != head);
904 /* Adjust output table pointers */
905 LIST_REMOVE(lnk, list_out);
907 /* Adjust input table pointers */
908 LIST_REMOVE(lnk, list_in);
909 #ifndef NO_USE_SOCKETS
910 /* Close socket, if one has been allocated */
911 if (lnk->sockfd != -1) {
916 /* Link-type dependent cleanup */
917 switch (lnk->link_type) {
931 case LINK_FRAGMENT_ID:
932 la->fragmentIdLinkCount--;
934 case LINK_FRAGMENT_PTR:
935 la->fragmentPtrLinkCount--;
936 if (lnk->data.frag_ptr != NULL)
937 free(lnk->data.frag_ptr);
942 la->protoLinkCount--;
949 /* Write statistics, if logging enabled */
950 if (la->packetAliasMode & PKT_ALIAS_LOG) {
956 static struct alias_link *
957 AddLink(struct libalias *la, struct in_addr src_addr,
958 struct in_addr dst_addr,
959 struct in_addr alias_addr,
962 int alias_port_param, /* if less than zero, alias */
964 { /* port will be automatically *//* chosen.
966 u_int start_point; /* zero, equal to alias port */
967 struct alias_link *lnk;
969 LIBALIAS_LOCK_ASSERT(la);
970 lnk = malloc(sizeof(struct alias_link));
972 /* Basic initialization */
974 lnk->src_addr = src_addr;
975 lnk->dst_addr = dst_addr;
976 lnk->alias_addr = alias_addr;
977 lnk->proxy_addr.s_addr = INADDR_ANY;
978 lnk->src_port = src_port;
979 lnk->dst_port = dst_port;
982 lnk->link_type = link_type;
983 #ifndef NO_USE_SOCKETS
988 lnk->timestamp = la->timeStamp;
990 /* Expiration time */
993 lnk->expire_time = ICMP_EXPIRE_TIME;
996 lnk->expire_time = UDP_EXPIRE_TIME;
999 lnk->expire_time = TCP_EXPIRE_INITIAL;
1002 lnk->flags |= LINK_PERMANENT; /* no timeout. */
1004 case LINK_FRAGMENT_ID:
1005 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1007 case LINK_FRAGMENT_PTR:
1008 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1013 lnk->expire_time = PROTO_EXPIRE_TIME;
1017 /* Determine alias flags */
1018 if (dst_addr.s_addr == INADDR_ANY)
1019 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
1021 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1023 /* Determine alias port */
1024 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1028 /* Link-type dependent initialization */
1029 switch (link_type) {
1030 struct tcp_dat *aux_tcp;
1033 la->icmpLinkCount++;
1039 aux_tcp = malloc(sizeof(struct tcp_dat));
1040 if (aux_tcp != NULL) {
1044 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1045 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1046 aux_tcp->state.index = 0;
1047 aux_tcp->state.ack_modified = 0;
1048 for (i = 0; i < N_LINK_TCP_DATA; i++)
1049 aux_tcp->ack[i].active = 0;
1050 aux_tcp->fwhole = -1;
1051 lnk->data.tcp = aux_tcp;
1053 #ifdef LIBALIAS_DEBUG
1054 fprintf(stderr, "PacketAlias/AddLink: ");
1055 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1062 la->pptpLinkCount++;
1064 case LINK_FRAGMENT_ID:
1065 la->fragmentIdLinkCount++;
1067 case LINK_FRAGMENT_PTR:
1068 la->fragmentPtrLinkCount++;
1073 la->protoLinkCount++;
1077 /* Set up pointers for output lookup table */
1078 start_point = StartPointOut(src_addr, dst_addr,
1079 src_port, dst_port, link_type);
1080 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1082 /* Set up pointers for input lookup table */
1083 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1084 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1086 #ifdef LIBALIAS_DEBUG
1087 fprintf(stderr, "PacketAlias/AddLink(): ");
1088 fprintf(stderr, "malloc() call failed.\n");
1091 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1097 static struct alias_link *
1098 ReLink(struct alias_link *old_lnk,
1099 struct in_addr src_addr,
1100 struct in_addr dst_addr,
1101 struct in_addr alias_addr,
1104 int alias_port_param, /* if less than zero, alias */
1106 { /* port will be automatically *//* chosen.
1107 * If greater than */
1108 struct alias_link *new_lnk; /* zero, equal to alias port */
1109 struct libalias *la = old_lnk->la;
1111 LIBALIAS_LOCK_ASSERT(la);
1112 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1113 src_port, dst_port, alias_port_param,
1116 if (new_lnk != NULL &&
1117 old_lnk->link_type == LINK_TCP &&
1118 old_lnk->data.tcp->fwhole > 0) {
1119 PunchFWHole(new_lnk);
1122 DeleteLink(old_lnk);
1126 static struct alias_link *
1127 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1128 struct in_addr dst_addr,
1132 int replace_partial_links)
1135 struct alias_link *lnk;
1137 LIBALIAS_LOCK_ASSERT(la);
1138 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1139 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1140 if (lnk->src_addr.s_addr == src_addr.s_addr
1141 && lnk->server == NULL
1142 && lnk->dst_addr.s_addr == dst_addr.s_addr
1143 && lnk->dst_port == dst_port
1144 && lnk->src_port == src_port
1145 && lnk->link_type == link_type) {
1146 lnk->timestamp = la->timeStamp;
1151 /* Search for partially specified links. */
1152 if (lnk == NULL && replace_partial_links) {
1153 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1154 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1157 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1158 dst_port, link_type, 0);
1161 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1162 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1167 src_addr, dst_addr, lnk->alias_addr,
1168 src_port, dst_port, lnk->alias_port,
1175 static struct alias_link *
1176 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1177 struct in_addr dst_addr,
1181 int replace_partial_links)
1183 struct alias_link *lnk;
1185 LIBALIAS_LOCK_ASSERT(la);
1186 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1187 link_type, replace_partial_links);
1191 * The following allows permanent links to be specified as
1192 * using the default source address (i.e. device interface
1193 * address) without knowing in advance what that address
1196 if (la->aliasAddress.s_addr != INADDR_ANY &&
1197 src_addr.s_addr == la->aliasAddress.s_addr) {
1198 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1199 link_type, replace_partial_links);
1206 static struct alias_link *
1207 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1208 struct in_addr alias_addr,
1212 int replace_partial_links)
1216 struct alias_link *lnk;
1217 struct alias_link *lnk_fully_specified;
1218 struct alias_link *lnk_unknown_all;
1219 struct alias_link *lnk_unknown_dst_addr;
1220 struct alias_link *lnk_unknown_dst_port;
1222 LIBALIAS_LOCK_ASSERT(la);
1223 /* Initialize pointers */
1224 lnk_fully_specified = NULL;
1225 lnk_unknown_all = NULL;
1226 lnk_unknown_dst_addr = NULL;
1227 lnk_unknown_dst_port = NULL;
1229 /* If either the dest addr or port is unknown, the search
1230 loop will have to know about this. */
1233 if (dst_addr.s_addr == INADDR_ANY)
1234 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1236 flags_in |= LINK_UNKNOWN_DEST_PORT;
1239 start_point = StartPointIn(alias_addr, alias_port, link_type);
1240 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1243 flags = flags_in | lnk->flags;
1244 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1245 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1246 && lnk->alias_port == alias_port
1247 && lnk->dst_addr.s_addr == dst_addr.s_addr
1248 && lnk->dst_port == dst_port
1249 && lnk->link_type == link_type) {
1250 lnk_fully_specified = lnk;
1253 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1254 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1255 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1256 && lnk->alias_port == alias_port
1257 && lnk->link_type == link_type) {
1258 if (lnk_unknown_all == NULL)
1259 lnk_unknown_all = lnk;
1261 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1262 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1263 && lnk->alias_port == alias_port
1264 && lnk->link_type == link_type
1265 && lnk->dst_port == dst_port) {
1266 if (lnk_unknown_dst_addr == NULL)
1267 lnk_unknown_dst_addr = lnk;
1269 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1270 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1271 && lnk->alias_port == alias_port
1272 && lnk->link_type == link_type
1273 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1274 if (lnk_unknown_dst_port == NULL)
1275 lnk_unknown_dst_port = lnk;
1282 if (lnk_fully_specified != NULL) {
1283 lnk_fully_specified->timestamp = la->timeStamp;
1284 lnk = lnk_fully_specified;
1285 } else if (lnk_unknown_dst_port != NULL)
1286 lnk = lnk_unknown_dst_port;
1287 else if (lnk_unknown_dst_addr != NULL)
1288 lnk = lnk_unknown_dst_addr;
1289 else if (lnk_unknown_all != NULL)
1290 lnk = lnk_unknown_all;
1294 if (replace_partial_links &&
1295 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1296 struct in_addr src_addr;
1299 if (lnk->server != NULL) { /* LSNAT link */
1300 src_addr = lnk->server->addr;
1301 src_port = lnk->server->port;
1302 lnk->server = lnk->server->next;
1304 src_addr = lnk->src_addr;
1305 src_port = lnk->src_port;
1309 src_addr, dst_addr, alias_addr,
1310 src_port, dst_port, alias_port,
1316 static struct alias_link *
1317 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1318 struct in_addr alias_addr,
1322 int replace_partial_links)
1324 struct alias_link *lnk;
1326 LIBALIAS_LOCK_ASSERT(la);
1327 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1328 link_type, replace_partial_links);
1332 * The following allows permanent links to be specified as
1333 * using the default aliasing address (i.e. device
1334 * interface address) without knowing in advance what that
1337 if (la->aliasAddress.s_addr != INADDR_ANY &&
1338 alias_addr.s_addr == la->aliasAddress.s_addr) {
1339 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1340 link_type, replace_partial_links);
1349 /* External routines for finding/adding links
1351 -- "external" means outside alias_db.c, but within alias*.c --
1353 FindIcmpIn(), FindIcmpOut()
1354 FindFragmentIn1(), FindFragmentIn2()
1355 AddFragmentPtrLink(), FindFragmentPtr()
1356 FindProtoIn(), FindProtoOut()
1357 FindUdpTcpIn(), FindUdpTcpOut()
1358 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1359 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1360 FindOriginalAddress(), FindAliasAddress()
1362 (prototypes in alias_local.h)
1367 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1368 struct in_addr alias_addr,
1372 struct alias_link *lnk;
1374 LIBALIAS_LOCK_ASSERT(la);
1375 lnk = FindLinkIn(la, dst_addr, alias_addr,
1376 NO_DEST_PORT, id_alias,
1378 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1379 struct in_addr target_addr;
1381 target_addr = FindOriginalAddress(la, alias_addr);
1382 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1383 id_alias, NO_DEST_PORT, id_alias,
1391 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1392 struct in_addr dst_addr,
1396 struct alias_link *lnk;
1398 LIBALIAS_LOCK_ASSERT(la);
1399 lnk = FindLinkOut(la, src_addr, dst_addr,
1402 if (lnk == NULL && create) {
1403 struct in_addr alias_addr;
1405 alias_addr = FindAliasAddress(la, src_addr);
1406 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1407 id, NO_DEST_PORT, GET_ALIAS_ID,
1415 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1416 struct in_addr alias_addr,
1419 struct alias_link *lnk;
1421 LIBALIAS_LOCK_ASSERT(la);
1422 lnk = FindLinkIn(la, dst_addr, alias_addr,
1423 NO_DEST_PORT, ip_id,
1424 LINK_FRAGMENT_ID, 0);
1427 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1428 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1436 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1438 struct in_addr alias_addr, /* is not found. */
1442 LIBALIAS_LOCK_ASSERT(la);
1443 return FindLinkIn(la, dst_addr, alias_addr,
1444 NO_DEST_PORT, ip_id,
1445 LINK_FRAGMENT_ID, 0);
1450 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1454 LIBALIAS_LOCK_ASSERT(la);
1455 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1456 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1462 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1466 LIBALIAS_LOCK_ASSERT(la);
1467 return FindLinkIn(la, dst_addr, la->nullAddress,
1468 NO_DEST_PORT, ip_id,
1469 LINK_FRAGMENT_PTR, 0);
1474 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1475 struct in_addr alias_addr,
1478 struct alias_link *lnk;
1480 LIBALIAS_LOCK_ASSERT(la);
1481 lnk = FindLinkIn(la, dst_addr, alias_addr,
1485 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1486 struct in_addr target_addr;
1488 target_addr = FindOriginalAddress(la, alias_addr);
1489 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1490 NO_SRC_PORT, NO_DEST_PORT, 0,
1498 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1499 struct in_addr dst_addr,
1502 struct alias_link *lnk;
1504 LIBALIAS_LOCK_ASSERT(la);
1505 lnk = FindLinkOut(la, src_addr, dst_addr,
1506 NO_SRC_PORT, NO_DEST_PORT,
1510 struct in_addr alias_addr;
1512 alias_addr = FindAliasAddress(la, src_addr);
1513 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1514 NO_SRC_PORT, NO_DEST_PORT, 0,
1522 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1523 struct in_addr alias_addr,
1530 struct alias_link *lnk;
1532 LIBALIAS_LOCK_ASSERT(la);
1535 link_type = LINK_UDP;
1538 link_type = LINK_TCP;
1545 lnk = FindLinkIn(la, dst_addr, alias_addr,
1546 dst_port, alias_port,
1549 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1550 struct in_addr target_addr;
1552 target_addr = FindOriginalAddress(la, alias_addr);
1553 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1554 alias_port, dst_port, alias_port,
1562 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1563 struct in_addr dst_addr,
1570 struct alias_link *lnk;
1572 LIBALIAS_LOCK_ASSERT(la);
1575 link_type = LINK_UDP;
1578 link_type = LINK_TCP;
1585 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1587 if (lnk == NULL && create) {
1588 struct in_addr alias_addr;
1590 alias_addr = FindAliasAddress(la, src_addr);
1591 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1592 src_port, dst_port, GET_ALIAS_PORT,
1600 AddPptp(struct libalias *la, struct in_addr src_addr,
1601 struct in_addr dst_addr,
1602 struct in_addr alias_addr,
1603 u_int16_t src_call_id)
1605 struct alias_link *lnk;
1607 LIBALIAS_LOCK_ASSERT(la);
1608 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1609 src_call_id, 0, GET_ALIAS_PORT,
1617 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1618 struct in_addr dst_addr,
1619 u_int16_t src_call_id)
1622 struct alias_link *lnk;
1624 LIBALIAS_LOCK_ASSERT(la);
1625 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1626 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1627 if (lnk->link_type == LINK_PPTP &&
1628 lnk->src_addr.s_addr == src_addr.s_addr &&
1629 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1630 lnk->src_port == src_call_id)
1638 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1639 struct in_addr dst_addr,
1640 u_int16_t dst_call_id)
1643 struct alias_link *lnk;
1645 LIBALIAS_LOCK_ASSERT(la);
1646 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1647 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1648 if (lnk->link_type == LINK_PPTP &&
1649 lnk->src_addr.s_addr == src_addr.s_addr &&
1650 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1651 lnk->dst_port == dst_call_id)
1659 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1660 struct in_addr alias_addr,
1661 u_int16_t dst_call_id)
1664 struct alias_link *lnk;
1666 LIBALIAS_LOCK_ASSERT(la);
1667 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1668 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1669 if (lnk->link_type == LINK_PPTP &&
1670 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1671 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1672 lnk->dst_port == dst_call_id)
1680 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1681 struct in_addr alias_addr,
1682 u_int16_t alias_call_id)
1684 struct alias_link *lnk;
1686 LIBALIAS_LOCK_ASSERT(la);
1687 lnk = FindLinkIn(la, dst_addr, alias_addr,
1688 0 /* any */ , alias_call_id,
1697 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1698 struct in_addr dst_addr,
1704 struct alias_link *lnk;
1706 LIBALIAS_LOCK_ASSERT(la);
1709 link_type = LINK_UDP;
1712 link_type = LINK_TCP;
1719 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1722 struct in_addr alias_addr;
1724 alias_addr = FindAliasAddress(la, src_addr);
1725 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1726 src_port, 0, alias_port,
1734 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1736 struct alias_link *lnk;
1738 LIBALIAS_LOCK_ASSERT(la);
1739 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1740 0, 0, LINK_ADDR, 0);
1742 la->newDefaultLink = 1;
1743 if (la->targetAddress.s_addr == INADDR_ANY)
1744 return (alias_addr);
1745 else if (la->targetAddress.s_addr == INADDR_NONE)
1746 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1747 la->aliasAddress : alias_addr;
1749 return (la->targetAddress);
1751 if (lnk->server != NULL) { /* LSNAT link */
1752 struct in_addr src_addr;
1754 src_addr = lnk->server->addr;
1755 lnk->server = lnk->server->next;
1757 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1758 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1759 la->aliasAddress : alias_addr;
1761 return (lnk->src_addr);
1767 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1769 struct alias_link *lnk;
1771 LIBALIAS_LOCK_ASSERT(la);
1772 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1773 0, 0, LINK_ADDR, 0);
1775 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1776 la->aliasAddress : original_addr;
1778 if (lnk->alias_addr.s_addr == INADDR_ANY)
1779 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1780 la->aliasAddress : original_addr;
1782 return (lnk->alias_addr);
1787 /* External routines for getting or changing link data
1788 (external to alias_db.c, but internal to alias*.c)
1790 SetFragmentData(), GetFragmentData()
1791 SetFragmentPtr(), GetFragmentPtr()
1792 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1793 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1794 GetOriginalPort(), GetAliasPort()
1795 SetAckModified(), GetAckModified()
1796 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1797 SetProtocolFlags(), GetProtocolFlags()
1803 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1805 lnk->data.frag_addr = src_addr;
1810 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1812 *src_addr = lnk->data.frag_addr;
1817 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1819 lnk->data.frag_ptr = fptr;
1824 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1826 *fptr = lnk->data.frag_ptr;
1831 SetStateIn(struct alias_link *lnk, int state)
1833 /* TCP input state */
1835 case ALIAS_TCP_STATE_DISCONNECTED:
1836 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1837 lnk->expire_time = TCP_EXPIRE_DEAD;
1839 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1841 case ALIAS_TCP_STATE_CONNECTED:
1842 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1843 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1847 panic("libalias:SetStateIn() unknown state");
1852 lnk->data.tcp->state.in = state;
1857 SetStateOut(struct alias_link *lnk, int state)
1859 /* TCP output state */
1861 case ALIAS_TCP_STATE_DISCONNECTED:
1862 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1863 lnk->expire_time = TCP_EXPIRE_DEAD;
1865 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1867 case ALIAS_TCP_STATE_CONNECTED:
1868 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1869 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1873 panic("libalias:SetStateOut() unknown state");
1878 lnk->data.tcp->state.out = state;
1883 GetStateIn(struct alias_link *lnk)
1885 /* TCP input state */
1886 return (lnk->data.tcp->state.in);
1891 GetStateOut(struct alias_link *lnk)
1893 /* TCP output state */
1894 return (lnk->data.tcp->state.out);
1899 GetOriginalAddress(struct alias_link *lnk)
1901 if (lnk->src_addr.s_addr == INADDR_ANY)
1902 return (lnk->la->aliasAddress);
1904 return (lnk->src_addr);
1909 GetDestAddress(struct alias_link *lnk)
1911 return (lnk->dst_addr);
1916 GetAliasAddress(struct alias_link *lnk)
1918 if (lnk->alias_addr.s_addr == INADDR_ANY)
1919 return (lnk->la->aliasAddress);
1921 return (lnk->alias_addr);
1926 GetDefaultAliasAddress(struct libalias *la)
1929 LIBALIAS_LOCK_ASSERT(la);
1930 return (la->aliasAddress);
1935 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1938 LIBALIAS_LOCK_ASSERT(la);
1939 la->aliasAddress = alias_addr;
1944 GetOriginalPort(struct alias_link *lnk)
1946 return (lnk->src_port);
1951 GetAliasPort(struct alias_link *lnk)
1953 return (lnk->alias_port);
1958 GetDestPort(struct alias_link *lnk)
1960 return (lnk->dst_port);
1966 SetAckModified(struct alias_link *lnk)
1968 /* Indicate that ACK numbers have been modified in a TCP connection */
1969 lnk->data.tcp->state.ack_modified = 1;
1974 GetProxyAddress(struct alias_link *lnk)
1976 return (lnk->proxy_addr);
1981 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1983 lnk->proxy_addr = addr;
1988 GetProxyPort(struct alias_link *lnk)
1990 return (lnk->proxy_port);
1995 SetProxyPort(struct alias_link *lnk, u_short port)
1997 lnk->proxy_port = port;
2002 GetAckModified(struct alias_link *lnk)
2004 /* See if ACK numbers have been modified */
2005 return (lnk->data.tcp->state.ack_modified);
2010 GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
2013 Find out how much the ACK number has been altered for an incoming
2014 TCP packet. To do this, a circular list of ACK numbers where the TCP
2015 packet size was altered is searched.
2020 int delta, ack_diff_min;
2028 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2029 struct ack_data_record x;
2031 x = lnk->data.tcp->ack[i];
2032 if (x.active == 1) {
2035 ack_diff = SeqDiff(x.ack_new, ack);
2036 if (ack_diff >= 0) {
2037 if (ack_diff_min >= 0) {
2038 if (ack_diff < ack_diff_min) {
2040 ack_diff_min = ack_diff;
2044 ack_diff_min = ack_diff;
2054 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
2057 Find out how much the sequence number has been altered for an outgoing
2058 TCP packet. To do this, a circular list of ACK numbers where the TCP
2059 packet size was altered is searched.
2064 int delta, seq_diff_min;
2072 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2073 struct ack_data_record x;
2075 x = lnk->data.tcp->ack[i];
2076 if (x.active == 1) {
2079 seq_diff = SeqDiff(x.ack_old, seq);
2080 if (seq_diff >= 0) {
2081 if (seq_diff_min >= 0) {
2082 if (seq_diff < seq_diff_min) {
2084 seq_diff_min = seq_diff;
2088 seq_diff_min = seq_diff;
2098 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
2101 When a TCP packet has been altered in length, save this
2102 information in a circular list. If enough packets have
2103 been altered, then this list will begin to overwrite itself.
2107 struct ack_data_record x;
2108 int hlen, tlen, dlen;
2113 hlen = (pip->ip_hl + tc->th_off) << 2;
2114 tlen = ntohs(pip->ip_len);
2117 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2118 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2122 i = lnk->data.tcp->state.index;
2123 lnk->data.tcp->ack[i] = x;
2126 if (i == N_LINK_TCP_DATA)
2127 lnk->data.tcp->state.index = 0;
2129 lnk->data.tcp->state.index = i;
2133 SetExpire(struct alias_link *lnk, int expire)
2136 lnk->flags &= ~LINK_PERMANENT;
2138 } else if (expire == -1) {
2139 lnk->flags |= LINK_PERMANENT;
2140 } else if (expire > 0) {
2141 lnk->expire_time = expire;
2143 #ifdef LIBALIAS_DEBUG
2144 fprintf(stderr, "PacketAlias/SetExpire(): ");
2145 fprintf(stderr, "error in expire parameter\n");
2151 ClearCheckNewLink(struct libalias *la)
2154 LIBALIAS_LOCK_ASSERT(la);
2155 la->newDefaultLink = 0;
2159 SetProtocolFlags(struct alias_link *lnk, int pflags)
2162 lnk->pflags = pflags;;
2166 GetProtocolFlags(struct alias_link *lnk)
2169 return (lnk->pflags);
2173 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2175 struct libalias *la = lnk->la;
2177 LIBALIAS_LOCK_ASSERT(la);
2178 la->deleteAllLinks = 1;
2179 lnk = ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2180 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2181 la->deleteAllLinks = 0;
2185 /* Miscellaneous Functions
2188 InitPacketAliasLog()
2189 UninitPacketAliasLog()
2193 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2194 is called to find and remove timed-out aliasing links. Logic exists
2195 to sweep through the entire table and linked list structure
2198 (prototype in alias_local.h)
2202 HouseKeeping(struct libalias *la)
2210 LIBALIAS_LOCK_ASSERT(la);
2212 * Save system time (seconds) in global variable timeStamp for use
2213 * by other functions. This is done so as not to unnecessarily
2214 * waste timeline by making system calls.
2217 la->timeStamp = time_uptime;
2219 gettimeofday(&tv, &tz);
2220 la->timeStamp = tv.tv_sec;
2223 /* Compute number of spokes (output table link chains) to cover */
2224 n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual;
2225 n100 *= la->timeStamp - la->lastCleanupTime;
2226 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2230 /* Handle different cases */
2231 if (n > ALIAS_CLEANUP_MAX_SPOKES) {
2232 n = ALIAS_CLEANUP_MAX_SPOKES;
2233 la->lastCleanupTime = la->timeStamp;
2234 la->houseKeepingResidual = 0;
2236 for (i = 0; i < n; i++)
2237 IncrementalCleanup(la);
2239 la->lastCleanupTime = la->timeStamp;
2240 la->houseKeepingResidual = n100 - 100 * n;
2242 for (i = 0; i < n; i++)
2243 IncrementalCleanup(la);
2245 #ifdef LIBALIAS_DEBUG
2246 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2247 fprintf(stderr, "something unexpected in time values\n");
2249 la->lastCleanupTime = la->timeStamp;
2250 la->houseKeepingResidual = 0;
2254 /* Init the log file and enable logging */
2256 InitPacketAliasLog(struct libalias *la)
2259 LIBALIAS_LOCK_ASSERT(la);
2260 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2262 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2265 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2266 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2269 return (ENOMEM); /* log initialization failed */
2270 la->packetAliasMode |= PKT_ALIAS_LOG;
2276 /* Close the log-file and disable logging. */
2278 UninitPacketAliasLog(struct libalias *la)
2281 LIBALIAS_LOCK_ASSERT(la);
2286 fclose(la->logDesc);
2290 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2293 /* Outside world interfaces
2295 -- "outside world" means other than alias*.c routines --
2297 PacketAliasRedirectPort()
2298 PacketAliasAddServer()
2299 PacketAliasRedirectProto()
2300 PacketAliasRedirectAddr()
2301 PacketAliasRedirectDynamic()
2302 PacketAliasRedirectDelete()
2303 PacketAliasSetAddress()
2306 PacketAliasSetMode()
2308 (prototypes in alias.h)
2311 /* Redirection from a specific public addr:port to a
2312 private addr:port */
2314 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2315 struct in_addr dst_addr, u_short dst_port,
2316 struct in_addr alias_addr, u_short alias_port,
2320 struct alias_link *lnk;
2325 link_type = LINK_UDP;
2328 link_type = LINK_TCP;
2331 #ifdef LIBALIAS_DEBUG
2332 fprintf(stderr, "PacketAliasRedirectPort(): ");
2333 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2339 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2340 src_port, dst_port, alias_port,
2344 lnk->flags |= LINK_PERMANENT;
2346 #ifdef LIBALIAS_DEBUG
2348 fprintf(stderr, "PacketAliasRedirectPort(): "
2349 "call to AddLink() failed\n");
2354 LIBALIAS_UNLOCK(la);
2358 /* Add server to the pool of servers */
2360 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2362 struct server *server;
2368 server = malloc(sizeof(struct server));
2370 if (server != NULL) {
2371 struct server *head;
2373 server->addr = addr;
2374 server->port = port;
2378 server->next = server;
2382 for (s = head; s->next != head; s = s->next);
2384 server->next = head;
2386 lnk->server = server;
2391 LIBALIAS_UNLOCK(la);
2395 /* Redirect packets of a given IP protocol from a specific
2396 public address to a private address */
2398 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2399 struct in_addr dst_addr,
2400 struct in_addr alias_addr,
2403 struct alias_link *lnk;
2406 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2407 NO_SRC_PORT, NO_DEST_PORT, 0,
2411 lnk->flags |= LINK_PERMANENT;
2413 #ifdef LIBALIAS_DEBUG
2415 fprintf(stderr, "PacketAliasRedirectProto(): "
2416 "call to AddLink() failed\n");
2420 LIBALIAS_UNLOCK(la);
2424 /* Static address translation */
2426 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2427 struct in_addr alias_addr)
2429 struct alias_link *lnk;
2432 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2437 lnk->flags |= LINK_PERMANENT;
2439 #ifdef LIBALIAS_DEBUG
2441 fprintf(stderr, "PacketAliasRedirectAddr(): "
2442 "call to AddLink() failed\n");
2446 LIBALIAS_UNLOCK(la);
2451 /* Mark the aliasing link dynamic */
2453 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2460 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2463 lnk->flags &= ~LINK_PERMANENT;
2466 LIBALIAS_UNLOCK(la);
2472 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2474 /* This is a dangerous function to put in the API,
2475 because an invalid pointer can crash the program. */
2478 la->deleteAllLinks = 1;
2480 la->deleteAllLinks = 0;
2481 LIBALIAS_UNLOCK(la);
2486 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2490 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2491 && la->aliasAddress.s_addr != addr.s_addr)
2492 CleanupAliasData(la);
2494 la->aliasAddress = addr;
2495 LIBALIAS_UNLOCK(la);
2500 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2504 la->targetAddress = target_addr;
2505 LIBALIAS_UNLOCK(la);
2512 while (!LIST_EMPTY(&instancehead))
2513 LibAliasUninit(LIST_FIRST(&instancehead));
2517 LibAliasInit(struct libalias *la)
2526 la = calloc(sizeof *la, 1);
2530 #ifndef _KERNEL /* kernel cleans up on module unload */
2531 if (LIST_EMPTY(&instancehead))
2534 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2537 la->timeStamp = time_uptime;
2538 la->lastCleanupTime = time_uptime;
2540 gettimeofday(&tv, &tz);
2541 la->timeStamp = tv.tv_sec;
2542 la->lastCleanupTime = tv.tv_sec;
2544 la->houseKeepingResidual = 0;
2546 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2547 LIST_INIT(&la->linkTableOut[i]);
2548 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2549 LIST_INIT(&la->linkTableIn[i]);
2550 LIBALIAS_LOCK_INIT(la);
2554 la->deleteAllLinks = 1;
2555 CleanupAliasData(la);
2556 la->deleteAllLinks = 0;
2559 la->aliasAddress.s_addr = INADDR_ANY;
2560 la->targetAddress.s_addr = INADDR_ANY;
2562 la->icmpLinkCount = 0;
2563 la->udpLinkCount = 0;
2564 la->tcpLinkCount = 0;
2565 la->pptpLinkCount = 0;
2566 la->protoLinkCount = 0;
2567 la->fragmentIdLinkCount = 0;
2568 la->fragmentPtrLinkCount = 0;
2571 la->cleanupIndex = 0;
2573 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2574 #ifndef NO_USE_SOCKETS
2575 | PKT_ALIAS_USE_SOCKETS
2577 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2579 la->fireWallFD = -1;
2582 LibAliasRefreshModules();
2584 LIBALIAS_UNLOCK(la);
2589 LibAliasUninit(struct libalias *la)
2593 la->deleteAllLinks = 1;
2594 CleanupAliasData(la);
2595 la->deleteAllLinks = 0;
2596 UninitPacketAliasLog(la);
2600 LIST_REMOVE(la, instancelist);
2601 LIBALIAS_UNLOCK(la);
2602 LIBALIAS_LOCK_DESTROY(la);
2606 /* Change mode for some operations */
2609 struct libalias *la,
2610 unsigned int flags, /* Which state to bring flags to */
2611 unsigned int mask /* Mask of which flags to affect (use 0 to
2612 * do a probe for flag values) */
2618 /* Enable logging? */
2619 if (flags & mask & PKT_ALIAS_LOG) {
2621 if (InitPacketAliasLog(la) == ENOMEM)
2624 /* _Disable_ logging? */
2625 if (~flags & mask & PKT_ALIAS_LOG) {
2626 UninitPacketAliasLog(la);
2629 /* Start punching holes in the firewall? */
2630 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2633 /* Stop punching holes in the firewall? */
2634 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2639 /* Other flags can be set/cleared without special action */
2640 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2641 res = la->packetAliasMode;
2643 LIBALIAS_UNLOCK(la);
2649 LibAliasCheckNewLink(struct libalias *la)
2654 res = la->newDefaultLink;
2655 LIBALIAS_UNLOCK(la);
2663 Code to support firewall punching. This shouldn't really be in this
2664 file, but making variables global is evil too.
2667 /* Firewall include files */
2669 #include <netinet/ip_fw.h>
2674 * helper function, updates the pointer to cmd with the length
2675 * of the current command, and also cleans up the first word of
2676 * the new command in case it has been clobbered before.
2679 next_cmd(ipfw_insn * cmd)
2682 bzero(cmd, sizeof(*cmd));
2687 * A function to fill simple commands of size 1.
2688 * Existing flags are preserved.
2691 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2692 int flags, u_int16_t arg)
2694 cmd->opcode = opcode;
2695 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2697 return next_cmd(cmd);
2701 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2703 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2705 cmd->addr.s_addr = addr;
2706 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2710 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2712 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2714 cmd->ports[0] = cmd->ports[1] = port;
2715 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2719 fill_rule(void *buf, int bufsize, int rulenum,
2720 enum ipfw_opcodes action, int proto,
2721 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2723 struct ip_fw *rule = (struct ip_fw *)buf;
2724 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2726 bzero(buf, bufsize);
2727 rule->rulenum = rulenum;
2729 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2730 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2731 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2732 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2733 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2735 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2736 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2738 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2740 return ((char *)cmd - (char *)buf);
2743 static void ClearAllFWHoles(struct libalias *la);
2746 #define fw_setfield(la, field, num) \
2748 (field)[(num) - la->fireWallBaseNum] = 1; \
2749 } /*lint -save -e717 */ while(0)/* lint -restore */
2751 #define fw_clrfield(la, field, num) \
2753 (field)[(num) - la->fireWallBaseNum] = 0; \
2754 } /*lint -save -e717 */ while(0)/* lint -restore */
2756 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2759 InitPunchFW(struct libalias *la)
2762 LIBALIAS_LOCK_ASSERT(la);
2763 la->fireWallField = malloc(la->fireWallNumNums);
2764 if (la->fireWallField) {
2765 memset(la->fireWallField, 0, la->fireWallNumNums);
2766 if (la->fireWallFD < 0) {
2767 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2769 ClearAllFWHoles(la);
2770 la->fireWallActiveNum = la->fireWallBaseNum;
2775 UninitPunchFW(struct libalias *la)
2778 LIBALIAS_LOCK_ASSERT(la);
2779 ClearAllFWHoles(la);
2780 if (la->fireWallFD >= 0)
2781 close(la->fireWallFD);
2782 la->fireWallFD = -1;
2783 if (la->fireWallField)
2784 free(la->fireWallField);
2785 la->fireWallField = NULL;
2786 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2789 /* Make a certain link go through the firewall */
2791 PunchFWHole(struct alias_link *lnk)
2793 struct libalias *la;
2794 int r; /* Result code */
2795 struct ip_fw rule; /* On-the-fly built rule */
2796 int fwhole; /* Where to punch hole */
2798 LIBALIAS_LOCK_ASSERT(la);
2801 /* Don't do anything unless we are asked to */
2802 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2803 la->fireWallFD < 0 ||
2804 lnk->link_type != LINK_TCP)
2807 memset(&rule, 0, sizeof rule);
2811 /* Find empty slot */
2812 for (fwhole = la->fireWallActiveNum;
2813 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2814 fw_tstfield(la, la->fireWallField, fwhole);
2816 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2817 for (fwhole = la->fireWallBaseNum;
2818 fwhole < la->fireWallActiveNum &&
2819 fw_tstfield(la, la->fireWallField, fwhole);
2821 if (fwhole == la->fireWallActiveNum) {
2822 /* No rule point empty - we can't punch more holes. */
2823 la->fireWallActiveNum = la->fireWallBaseNum;
2824 #ifdef LIBALIAS_DEBUG
2825 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2830 /* Start next search at next position */
2831 la->fireWallActiveNum = fwhole + 1;
2834 * generate two rules of the form
2836 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2837 * accept tcp from DAddr DPort to OAddr OPort
2839 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2840 u_int32_t rulebuf[255];
2843 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2844 O_ACCEPT, IPPROTO_TCP,
2845 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2846 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2847 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2849 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2851 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2852 O_ACCEPT, IPPROTO_TCP,
2853 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2854 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2855 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2857 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2860 /* Indicate hole applied */
2861 lnk->data.tcp->fwhole = fwhole;
2862 fw_setfield(la, la->fireWallField, fwhole);
2865 /* Remove a hole in a firewall associated with a particular alias
2866 lnk. Calling this too often is harmless. */
2868 ClearFWHole(struct alias_link *lnk)
2870 struct libalias *la;
2872 LIBALIAS_LOCK_ASSERT(la);
2874 if (lnk->link_type == LINK_TCP) {
2875 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2882 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2883 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2884 &fwhole, sizeof fwhole));
2885 fw_clrfield(la, la->fireWallField, fwhole);
2886 lnk->data.tcp->fwhole = -1;
2890 /* Clear out the entire range dedicated to firewall holes. */
2892 ClearAllFWHoles(struct libalias *la)
2894 struct ip_fw rule; /* On-the-fly built rule */
2897 LIBALIAS_LOCK_ASSERT(la);
2898 if (la->fireWallFD < 0)
2901 memset(&rule, 0, sizeof rule);
2902 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2905 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2907 /* XXX: third arg correct here ? /phk */
2908 memset(la->fireWallField, 0, la->fireWallNumNums);
2914 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2919 la->fireWallBaseNum = base;
2920 la->fireWallNumNums = num;
2922 LIBALIAS_UNLOCK(la);
2926 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2930 la->skinnyPort = port;
2931 LIBALIAS_UNLOCK(la);