1 /* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*-
2 Alias_db.c encapsulates all data structures used for storing
3 packet aliasing data. Other parts of the aliasing software
4 access data through functions provided in this file.
6 Data storage is based on the notion of a "link", which is
7 established for ICMP echo/reply packets, UDP datagrams and
8 TCP stream connections. A link stores the original source
9 and destination addresses. For UDP and TCP, it also stores
10 source and destination port numbers, as well as an alias
11 port number. Links are also used to store information about
14 There is a facility for sweeping through and deleting old
15 links as new packets are sent through. A simple timeout is
16 used for ICMP and UDP links. TCP links are left alone unless
17 there is an incomplete connection, in which case the link
18 can be deleted after a certain amount of time.
21 This software is placed into the public domain with no restrictions
24 Initial version: August, 1996 (cjm)
26 Version 1.4: September 16, 1996 (cjm)
27 Facility for handling incoming links added.
29 Version 1.6: September 18, 1996 (cjm)
30 ICMP data handling simplified.
32 Version 1.7: January 9, 1997 (cjm)
33 Fragment handling simplified.
34 Saves pointers for unresolved fragments.
35 Permits links for unspecied remote ports
36 or unspecified remote addresses.
37 Fixed bug which did not properly zero port
38 table entries after a link was deleted.
39 Cleaned up some obsolete comments.
41 Version 1.8: January 14, 1997 (cjm)
42 Fixed data type error in StartPoint().
43 (This error did not exist prior to v1.7
44 and was discovered and fixed by Ari Suutari)
46 Version 1.9: February 1, 1997
47 Optionally, connections initiated from packet aliasing host
48 machine will will not have their port number aliased unless it
49 conflicts with an aliasing port already being used. (cjm)
51 All options earlier being #ifdef'ed now are available through
52 a new interface, SetPacketAliasMode(). This allow run time
53 control (which is now available in PPP+pktAlias through the
54 'alias' keyword). (ee)
56 Added ability to create an alias port without
57 either destination address or port specified.
58 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
60 Removed K&R style function headers
61 and general cleanup. (ee)
63 Added packetAliasMode to replace compiler #defines's (ee)
65 Allocates sockets for partially specified
66 ports if ALIAS_USE_SOCKETS defined. (cjm)
68 Version 2.0: March, 1997
69 SetAliasAddress() will now clean up alias links
70 if the aliasing address is changed. (cjm)
72 PacketAliasPermanentLink() function added to support permanent
73 links. (J. Fortes suggested the need for this.)
76 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
78 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
81 These permament links allow for incoming connections to
82 machines on the local network. They can be given with a
83 user-chosen amount of specificity, with increasing specificity
84 meaning more security. (cjm)
86 Quite a bit of rework to the basic engine. The portTable[]
87 array, which kept track of which ports were in use was replaced
88 by a table/linked list structure. (cjm)
90 SetExpire() function added. (cjm)
92 DeleteLink() no longer frees memory association with a pointer
93 to a fragment (this bug was first recognized by E. Eklund in
96 Version 2.1: May, 1997 (cjm)
97 Packet aliasing engine reworked so that it can handle
98 multiple external addresses rather than just a single
101 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
102 added to the API. The first function is a more generalized
103 version of PacketAliasPermanentLink(). The second function
104 implements static network address translation.
106 See HISTORY file for additional revisions.
110 /* System include files */
115 #include <sys/errno.h>
116 #include <sys/socket.h>
117 #include <sys/time.h>
118 #include <sys/types.h>
120 /* BSD network include files */
121 #include <netinet/in_systm.h>
122 #include <netinet/in.h>
123 #include <netinet/ip.h>
124 #include <netinet/tcp.h>
125 #include <arpa/inet.h>
128 #include "alias_local.h"
133 Constants (note: constants are also defined
134 near relevant functions or structs)
137 /* Sizes of input and output link tables */
138 #define LINK_TABLE_OUT_SIZE 101
139 #define LINK_TABLE_IN_SIZE 4001
141 /* Parameters used for cleanup of expired links */
142 #define ALIAS_CLEANUP_INTERVAL_SECS 60
143 #define ALIAS_CLEANUP_MAX_SPOKES 30
145 /* Timouts (in seconds) for different link types) */
146 #define ICMP_EXPIRE_TIME 60
147 #define UDP_EXPIRE_TIME 60
148 #define FRAGMENT_ID_EXPIRE_TIME 10
149 #define FRAGMENT_PTR_EXPIRE_TIME 30
151 /* TCP link expire time for different cases */
152 /* When the link has been used and closed - minimal grace time to
153 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
154 #ifndef TCP_EXPIRE_DEAD
155 # define TCP_EXPIRE_DEAD 10
158 /* When the link has been used and closed on one side - the other side
159 is allowed to still send data */
160 #ifndef TCP_EXPIRE_SINGLEDEAD
161 # define TCP_EXPIRE_SINGLEDEAD 90
164 /* When the link isn't yet up */
165 #ifndef TCP_EXPIRE_INITIAL
166 # define TCP_EXPIRE_INITIAL 300
169 /* When the link is up */
170 #ifndef TCP_EXPIRE_CONNECTED
171 # define TCP_EXPIRE_CONNECTED 86400
175 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
176 These constants can be anything except zero, which indicates an
177 unknown port numbea. */
179 #define NO_DEST_PORT 1
180 #define NO_SRC_PORT 1
186 The fundamental data structure used in this program is
187 "struct alias_link". Whenever a TCP connection is made,
188 a UDP datagram is sent out, or an ICMP echo request is made,
189 a link record is made (if it has not already been created).
190 The link record is identified by the source address/port
191 and the destination address/port. In the case of an ICMP
192 echo request, the source port is treated as being equivalent
193 with the 16-bit id number of the ICMP packet.
195 The link record also can store some auxiliary data. For
196 TCP connections that have had sequence and acknowledgment
197 modifications, data space is available to track these changes.
198 A state field is used to keep track in changes to the tcp
199 connection state. Id numbers of fragments can also be
200 stored in the auxiliary space. Pointers to unresolved
201 framgents can also be stored.
203 The link records support two independent chainings. Lookup
204 tables for input and out tables hold the initial pointers
205 the link chains. On input, the lookup table indexes on alias
206 port and link type. On output, the lookup table indexes on
207 source addreess, destination address, source port, destination
211 struct ack_data_record /* used to save changes to ack/seq numbers */
219 struct tcp_state /* Information about tcp connection */
221 int in; /* State for outside -> inside */
222 int out; /* State for inside -> outside */
223 int index; /* Index to ack data array */
224 int ack_modified; /* Indicates whether ack and seq numbers */
228 #define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes
229 saved for a modified TCP stream */
232 struct tcp_state state;
233 struct ack_data_record ack[N_LINK_TCP_DATA];
234 int fwhole; /* Which firewall record is used for this hole? */
237 struct alias_link /* Main data structure */
239 struct in_addr src_addr; /* Address and port information */
240 struct in_addr dst_addr; /* . */
241 struct in_addr alias_addr; /* . */
242 u_short src_port; /* . */
243 u_short dst_port; /* . */
244 u_short alias_port; /* . */
246 int link_type; /* Type of link: tcp, udp, icmp, frag */
248 /* values for link_type */
252 #define LINK_FRAGMENT_ID 4
253 #define LINK_FRAGMENT_PTR 5
256 int flags; /* indicates special characteristics */
259 #define LINK_UNKNOWN_DEST_PORT 0x01
260 #define LINK_UNKNOWN_DEST_ADDR 0x02
261 #define LINK_PERMANENT 0x04
262 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
263 #define LINK_UNFIREWALLED 0x08
265 int timestamp; /* Time link was last accessed */
266 int expire_time; /* Expire time for link */
268 int sockfd; /* socket descriptor */
270 u_int start_point_out; /* Index number in output lookup table */
271 u_int start_point_in;
272 struct alias_link *next_out; /* Linked list pointers for input and */
273 struct alias_link *last_out; /* output tables */
274 struct alias_link *next_in; /* . */
275 struct alias_link *last_in; /* . */
277 union /* Auxiliary data */
280 struct in_addr frag_addr;
291 The global variables listed here are only accessed from
292 within alias_db.c and so are prefixed with the static
296 int packetAliasMode; /* Mode flags */
297 /* - documented in alias.h */
299 static struct in_addr aliasAddress; /* Address written onto source */
300 /* field of IP packet. */
302 static struct in_addr targetAddress; /* IP address incoming packets */
303 /* are sent to if no aliasing */
304 /* link already exists */
306 static struct in_addr nullAddress; /* Used as a dummy parameter for */
307 /* some function calls */
308 static struct alias_link *
309 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */
310 /* chains of link records. Each */
311 static struct alias_link * /* link record is doubly indexed */
312 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */
315 static int icmpLinkCount; /* Link statistics */
316 static int udpLinkCount;
317 static int tcpLinkCount;
318 static int fragmentIdLinkCount;
319 static int fragmentPtrLinkCount;
320 static int sockCount;
322 static int cleanupIndex; /* Index to chain of link table */
323 /* being inspected for old links */
325 static int timeStamp; /* System time in seconds for */
328 static int lastCleanupTime; /* Last time IncrementalCleanup() */
331 static int houseKeepingResidual; /* used by HouseKeeping() */
333 static int deleteAllLinks; /* If equal to zero, DeleteLink() */
334 /* will not remove permanent links */
336 static FILE *monitorFile; /* File descriptor for link */
337 /* statistics monitoring file */
339 static int newDefaultLink; /* Indicates if a new aliasing */
340 /* link has been created after a */
341 /* call to PacketAliasIn/Out(). */
344 static int fireWallFD = -1; /* File descriptor to be able to */
345 /* control firewall. Opened by */
346 /* PacketAliasSetMode on first */
347 /* setting the PKT_ALIAS_PUNCH_FW */
356 /* Internal utility routines (used only in alias_db.c)
358 Lookup table starting points:
359 StartPointIn() -- link table initial search point for
361 StartPointOut() -- port table initial search point for
365 SeqDiff() -- difference between two TCP sequences
366 ShowAliasStats() -- send alias statistics to a monitor file
370 /* Local prototypes */
371 static u_int StartPointIn(struct in_addr, u_short, int);
373 static u_int StartPointOut(struct in_addr, struct in_addr,
374 u_short, u_short, int);
376 static int SeqDiff(u_long, u_long);
378 static void ShowAliasStats(void);
381 /* Firewall control */
382 static void InitPunchFW(void);
383 static void UninitPunchFW(void);
384 static void ClearFWHole(struct alias_link *link);
387 /* Log file control */
388 static void InitPacketAliasLog(void);
389 static void UninitPacketAliasLog(void);
392 StartPointIn(struct in_addr alias_addr,
398 n = alias_addr.s_addr;
401 return(n % LINK_TABLE_IN_SIZE);
406 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
407 u_short src_port, u_short dst_port, int link_type)
412 n += dst_addr.s_addr;
417 return(n % LINK_TABLE_OUT_SIZE);
422 SeqDiff(u_long x, u_long y)
424 /* Return the difference between two TCP sequence numbers */
427 This function is encapsulated in case there are any unusual
428 arithmetic conditions that need to be considered.
431 return (ntohl(y) - ntohl(x));
438 /* Used for debugging */
442 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d",
447 fragmentPtrLinkCount);
449 fprintf(monitorFile, " / tot=%d (sock=%d)\n",
450 icmpLinkCount + udpLinkCount
452 + fragmentIdLinkCount
453 + fragmentPtrLinkCount,
464 /* Internal routines for finding, deleting and adding links
467 GetNewPort() -- find and reserve new alias port number
468 GetSocket() -- try to allocate a socket for a given port
470 Link creation and deletion:
471 CleanupAliasData() - remove all link chains from lookup table
472 IncrementalCleanup() - look for stale links in a single chain
473 DeleteLink() - remove link
475 ReLink() - change link
478 FindLinkOut() - find link for outgoing packets
479 FindLinkIn() - find link for incoming packets
482 /* Local prototypes */
483 static int GetNewPort(struct alias_link *, int);
485 static u_short GetSocket(u_short, int *, int);
487 static void CleanupAliasData(void);
489 static void IncrementalCleanup(void);
491 static void DeleteLink(struct alias_link *);
493 static struct alias_link *
494 AddLink(struct in_addr, struct in_addr, struct in_addr,
495 u_short, u_short, int, int);
497 static struct alias_link *
498 ReLink(struct alias_link *,
499 struct in_addr, struct in_addr, struct in_addr,
500 u_short, u_short, int, int);
502 static struct alias_link *
503 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int);
505 static struct alias_link *
506 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
509 #define ALIAS_PORT_BASE 0x08000
510 #define ALIAS_PORT_MASK 0x07fff
511 #define GET_NEW_PORT_MAX_ATTEMPTS 20
513 #define GET_ALIAS_PORT -1
514 #define GET_ALIAS_ID GET_ALIAS_PORT
516 /* GetNewPort() allocates port numbers. Note that if a port number
517 is already in use, that does not mean that it cannot be used by
518 another link concurrently. This is because GetNewPort() looks for
519 unused triplets: (dest addr, dest port, alias port). */
522 GetNewPort(struct alias_link *link, int alias_port_param)
530 Description of alias_port_param for GetNewPort(). When
531 this parameter is zero or positive, it precisely specifies
532 the port number. GetNewPort() will return this number
533 without check that it is in use.
535 Whis this parameter is -1, it indicates to get a randomly
536 selected port number.
539 if (alias_port_param == GET_ALIAS_PORT)
542 * The aliasing port is automatically selected
543 * by one of two methods below:
545 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
547 if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
550 * When the ALIAS_SAME_PORTS option is
551 * chosen, the first try will be the
552 * actual source port. If this is already
553 * in use, the remainder of the trials
556 port_net = link->src_port;
557 port_sys = ntohs(port_net);
561 /* First trial and all subsequent are random. */
562 port_sys = random() & ALIAS_PORT_MASK;
563 port_sys += ALIAS_PORT_BASE;
564 port_net = htons(port_sys);
567 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
569 link->alias_port = (u_short) alias_port_param;
574 fprintf(stderr, "PacketAlias/GetNewPort(): ");
575 fprintf(stderr, "input parameter error\n");
580 /* Port number search */
581 for (i=0; i<max_trials; i++)
584 struct alias_link *search_result;
586 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
587 link->dst_port, port_net,
590 if (search_result == NULL)
592 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
593 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
600 if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS)
601 && (link->flags & LINK_PARTIALLY_SPECIFIED))
603 if (GetSocket(port_net, &link->sockfd, link->link_type))
605 link->alias_port = port_net;
611 link->alias_port = port_net;
616 port_sys = random() & ALIAS_PORT_MASK;
617 port_sys += ALIAS_PORT_BASE;
618 port_net = htons(port_sys);
621 fprintf(stderr, "PacketAlias/GetnewPort(): ");
622 fprintf(stderr, "could not find free port\n");
629 GetSocket(u_short port_net, int *sockfd, int link_type)
633 struct sockaddr_in sock_addr;
635 if (link_type == LINK_TCP)
636 sock = socket(AF_INET, SOCK_STREAM, 0);
637 else if (link_type == LINK_UDP)
638 sock = socket(AF_INET, SOCK_DGRAM, 0);
641 fprintf(stderr, "PacketAlias/GetSocket(): ");
642 fprintf(stderr, "incorrect link type\n");
648 fprintf(stderr, "PacketAlias/GetSocket(): ");
649 fprintf(stderr, "socket() error %d\n", *sockfd);
653 sock_addr.sin_family = AF_INET;
654 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
655 sock_addr.sin_port = port_net;
658 (struct sockaddr *) &sock_addr,
675 CleanupAliasData(void)
677 struct alias_link *link;
681 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
683 link = linkTableOut[i];
686 struct alias_link *link_next;
687 link_next = link->next_out;
699 IncrementalCleanup(void)
702 struct alias_link *link;
705 link = linkTableOut[cleanupIndex++];
709 struct alias_link *link_next;
711 link_next = link->next_out;
712 idelta = timeStamp - link->timestamp;
713 switch (link->link_type)
717 case LINK_FRAGMENT_ID:
718 case LINK_FRAGMENT_PTR:
719 if (idelta > link->expire_time)
726 if (idelta > link->expire_time)
728 struct tcp_dat *tcp_aux;
730 tcp_aux = link->data.tcp;
731 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
732 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
743 if (cleanupIndex == LINK_TABLE_OUT_SIZE)
748 DeleteLink(struct alias_link *link)
750 struct alias_link *link_last;
751 struct alias_link *link_next;
753 /* Don't do anything if the link is marked permanent */
754 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
758 /* Delete associatied firewall hole, if any */
762 /* Adjust output table pointers */
763 link_last = link->last_out;
764 link_next = link->next_out;
766 if (link_last != NULL)
767 link_last->next_out = link_next;
769 linkTableOut[link->start_point_out] = link_next;
771 if (link_next != NULL)
772 link_next->last_out = link_last;
774 /* Adjust input table pointers */
775 link_last = link->last_in;
776 link_next = link->next_in;
778 if (link_last != NULL)
779 link_last->next_in = link_next;
781 linkTableIn[link->start_point_in] = link_next;
783 if (link_next != NULL)
784 link_next->last_in = link_last;
786 /* Close socket, if one has been allocated */
787 if (link->sockfd != -1)
793 /* Link-type dependent cleanup */
794 switch(link->link_type)
804 if (link->data.tcp != NULL)
805 free(link->data.tcp);
807 case LINK_FRAGMENT_ID:
808 fragmentIdLinkCount--;
810 case LINK_FRAGMENT_PTR:
811 fragmentPtrLinkCount--;
812 if (link->data.frag_ptr != NULL)
813 free(link->data.frag_ptr);
820 /* Write statistics, if logging enabled */
821 if (packetAliasMode & PKT_ALIAS_LOG)
828 static struct alias_link *
829 AddLink(struct in_addr src_addr,
830 struct in_addr dst_addr,
831 struct in_addr alias_addr,
834 int alias_port_param, /* if less than zero, alias */
835 int link_type) /* port will be automatically */
836 { /* chosen. If greater than */
837 u_int start_point; /* zero, equal to alias port */
838 struct alias_link *link;
839 struct alias_link *first_link;
841 link = malloc(sizeof(struct alias_link));
844 /* If either the aliasing address or source address are
845 equal to the default device address (equal to the
846 global variable aliasAddress), then set the alias
847 address field of the link record to zero */
849 if (src_addr.s_addr == aliasAddress.s_addr)
852 if (alias_addr.s_addr == aliasAddress.s_addr)
853 alias_addr.s_addr = 0;
855 /* Basic initialization */
856 link->src_addr = src_addr;
857 link->dst_addr = dst_addr;
858 link->src_port = src_port;
859 link->alias_addr = alias_addr;
860 link->dst_port = dst_port;
861 link->link_type = link_type;
864 link->timestamp = timeStamp;
866 /* Expiration time */
870 link->expire_time = ICMP_EXPIRE_TIME;
873 link->expire_time = UDP_EXPIRE_TIME;
876 link->expire_time = TCP_EXPIRE_INITIAL;
878 case LINK_FRAGMENT_ID:
879 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
881 case LINK_FRAGMENT_PTR:
882 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
886 /* Determine alias flags */
887 if (dst_addr.s_addr == 0)
888 link->flags |= LINK_UNKNOWN_DEST_ADDR;
890 link->flags |= LINK_UNKNOWN_DEST_PORT;
892 /* Determine alias port */
893 if (GetNewPort(link, alias_port_param) != 0)
899 /* Set up pointers for output lookup table */
900 start_point = StartPointOut(src_addr, dst_addr,
901 src_port, dst_port, link_type);
902 first_link = linkTableOut[start_point];
904 link->last_out = NULL;
905 link->next_out = first_link;
906 link->start_point_out = start_point;
908 if (first_link != NULL)
909 first_link->last_out = link;
911 linkTableOut[start_point] = link;
913 /* Set up pointers for input lookup table */
914 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
915 first_link = linkTableIn[start_point];
917 link->last_in = NULL;
918 link->next_in = first_link;
919 link->start_point_in = start_point;
921 if (first_link != NULL)
922 first_link->last_in = link;
924 linkTableIn[start_point] = link;
926 /* Link-type dependent initialization */
929 struct tcp_dat *aux_tcp;
938 aux_tcp = malloc(sizeof(struct tcp_dat));
939 link->data.tcp = aux_tcp;
945 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
946 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
947 aux_tcp->state.index = 0;
948 aux_tcp->state.ack_modified = 0;
949 for (i=0; i<N_LINK_TCP_DATA; i++)
950 aux_tcp->ack[i].active = 0;
951 aux_tcp->fwhole = -1;
955 fprintf(stderr, "PacketAlias/AddLink: ");
956 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
959 case LINK_FRAGMENT_ID:
960 fragmentIdLinkCount++;
962 case LINK_FRAGMENT_PTR:
963 fragmentPtrLinkCount++;
969 fprintf(stderr, "PacketAlias/AddLink(): ");
970 fprintf(stderr, "malloc() call failed.\n");
973 if (packetAliasMode & PKT_ALIAS_LOG)
981 static struct alias_link *
982 ReLink(struct alias_link *old_link,
983 struct in_addr src_addr,
984 struct in_addr dst_addr,
985 struct in_addr alias_addr,
988 int alias_port_param, /* if less than zero, alias */
989 int link_type) /* port will be automatically */
990 { /* chosen. If greater than */
991 struct alias_link *new_link; /* zero, equal to alias port */
993 new_link = AddLink(src_addr, dst_addr, alias_addr,
994 src_port, dst_port, alias_port_param,
997 if (new_link != NULL &&
998 old_link->link_type == LINK_TCP &&
999 old_link->data.tcp &&
1000 old_link->data.tcp->fwhole > 0) {
1001 PunchFWHole(new_link);
1004 DeleteLink(old_link);
1008 static struct alias_link *
1009 FindLinkOut(struct in_addr src_addr,
1010 struct in_addr dst_addr,
1016 struct alias_link *link;
1018 if (src_addr.s_addr == aliasAddress.s_addr)
1019 src_addr.s_addr = 0;
1021 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1022 link = linkTableOut[i];
1023 while (link != NULL)
1025 if (link->src_addr.s_addr == src_addr.s_addr
1026 && link->dst_addr.s_addr == dst_addr.s_addr
1027 && link->dst_port == dst_port
1028 && link->src_port == src_port
1029 && link->link_type == link_type)
1031 link->timestamp = timeStamp;
1034 link = link->next_out;
1042 FindLinkIn(struct in_addr dst_addr,
1043 struct in_addr alias_addr,
1047 int replace_partial_links)
1051 struct alias_link *link;
1052 struct alias_link *link_fully_specified;
1053 struct alias_link *link_unknown_all;
1054 struct alias_link *link_unknown_dst_addr;
1055 struct alias_link *link_unknown_dst_port;
1057 /* Initialize pointers */
1058 link_fully_specified = NULL;
1059 link_unknown_all = NULL;
1060 link_unknown_dst_addr = NULL;
1061 link_unknown_dst_port = NULL;
1063 /* If either the dest addr or port is unknown, the search
1064 loop will have to know about this. */
1067 if (dst_addr.s_addr == 0)
1068 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1070 flags_in |= LINK_UNKNOWN_DEST_PORT;
1072 /* The following allows permanent links to be
1073 be specified as using the default aliasing address
1074 (i.e. device interface address) without knowing
1075 in advance what that address is. */
1077 if (alias_addr.s_addr == aliasAddress.s_addr)
1078 alias_addr.s_addr = 0;
1081 start_point = StartPointIn(alias_addr, alias_port, link_type);
1082 link = linkTableIn[start_point];
1083 while (link != NULL)
1087 flags = flags_in | link->flags;
1088 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1090 if (link->alias_addr.s_addr == alias_addr.s_addr
1091 && link->alias_port == alias_port
1092 && link->dst_addr.s_addr == dst_addr.s_addr
1093 && link->dst_port == dst_port
1094 && link->link_type == link_type)
1096 link_fully_specified = link;
1100 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1101 && (flags & LINK_UNKNOWN_DEST_PORT))
1103 if (link->alias_addr.s_addr == alias_addr.s_addr
1104 && link->alias_port == alias_port
1105 && link->link_type == link_type)
1107 if (link_unknown_all == NULL)
1108 link_unknown_all = link;
1111 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1113 if (link->alias_addr.s_addr == alias_addr.s_addr
1114 && link->alias_port == alias_port
1115 && link->link_type == link_type
1116 && link->dst_port == dst_port)
1118 if (link_unknown_dst_addr == NULL)
1119 link_unknown_dst_addr = link;
1122 else if (flags & LINK_UNKNOWN_DEST_PORT)
1124 if (link->alias_addr.s_addr == alias_addr.s_addr
1125 && link->alias_port == alias_port
1126 && link->link_type == link_type
1127 && link->dst_addr.s_addr == dst_addr.s_addr)
1129 if (link_unknown_dst_port == NULL)
1130 link_unknown_dst_port = link;
1133 link = link->next_in;
1138 if (link_fully_specified != NULL)
1140 return link_fully_specified;
1142 else if (link_unknown_dst_port != NULL)
1144 return replace_partial_links
1145 ? ReLink(link_unknown_dst_port,
1146 link_unknown_dst_port->src_addr, dst_addr, alias_addr,
1147 link_unknown_dst_port->src_port, dst_port, alias_port,
1149 : link_unknown_dst_port;
1151 else if (link_unknown_dst_addr != NULL)
1153 return replace_partial_links
1154 ? ReLink(link_unknown_dst_addr,
1155 link_unknown_dst_addr->src_addr, dst_addr, alias_addr,
1156 link_unknown_dst_addr->src_port, dst_port, alias_port,
1158 : link_unknown_dst_addr;
1160 else if (link_unknown_all != NULL)
1162 return replace_partial_links
1163 ? ReLink(link_unknown_all,
1164 link_unknown_all->src_addr, dst_addr, alias_addr,
1165 link_unknown_all->src_port, dst_port, alias_port,
1178 /* External routines for finding/adding links
1180 -- "external" means outside alias_db.c, but within alias*.c --
1182 FindIcmpIn(), FindIcmpOut()
1183 FindFragmentIn1(), FindFragmentIn2()
1184 AddFragmentPtrLink(), FindFragmentPtr()
1185 FindUdpTcpIn(), FindUdpTcpOut()
1186 FindOriginalAddress(), FindAliasAddress()
1188 (prototypes in alias_local.h)
1193 FindIcmpIn(struct in_addr dst_addr,
1194 struct in_addr alias_addr,
1197 return FindLinkIn(dst_addr, alias_addr,
1198 NO_DEST_PORT, id_alias,
1204 FindIcmpOut(struct in_addr src_addr,
1205 struct in_addr dst_addr,
1208 struct alias_link * link;
1210 link = FindLinkOut(src_addr, dst_addr,
1215 struct in_addr alias_addr;
1217 alias_addr = FindAliasAddress(src_addr);
1218 link = AddLink(src_addr, dst_addr, alias_addr,
1219 id, NO_DEST_PORT, GET_ALIAS_ID,
1228 FindFragmentIn1(struct in_addr dst_addr,
1229 struct in_addr alias_addr,
1232 struct alias_link *link;
1234 link = FindLinkIn(dst_addr, alias_addr,
1235 NO_DEST_PORT, ip_id,
1236 LINK_FRAGMENT_ID, 0);
1240 link = AddLink(nullAddress, dst_addr, alias_addr,
1241 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1250 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1251 struct in_addr alias_addr, /* is not found. */
1254 return FindLinkIn(dst_addr, alias_addr,
1255 NO_DEST_PORT, ip_id,
1256 LINK_FRAGMENT_ID, 0);
1261 AddFragmentPtrLink(struct in_addr dst_addr,
1264 return AddLink(nullAddress, dst_addr, nullAddress,
1265 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1271 FindFragmentPtr(struct in_addr dst_addr,
1274 return FindLinkIn(dst_addr, nullAddress,
1275 NO_DEST_PORT, ip_id,
1276 LINK_FRAGMENT_PTR, 0);
1281 FindUdpTcpIn(struct in_addr dst_addr,
1282 struct in_addr alias_addr,
1288 struct alias_link *link;
1293 link_type = LINK_UDP;
1296 link_type = LINK_TCP;
1303 link = FindLinkIn(dst_addr, alias_addr,
1304 dst_port, alias_port,
1307 if ( !(packetAliasMode & PKT_ALIAS_DENY_INCOMING) && link == NULL)
1309 struct in_addr target_addr;
1311 target_addr = FindOriginalAddress(alias_addr);
1312 link = AddLink(target_addr, dst_addr, alias_addr,
1313 alias_port, dst_port, alias_port,
1322 FindUdpTcpOut(struct in_addr src_addr,
1323 struct in_addr dst_addr,
1329 struct alias_link *link;
1334 link_type = LINK_UDP;
1337 link_type = LINK_TCP;
1344 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type);
1348 struct in_addr alias_addr;
1350 alias_addr = FindAliasAddress(src_addr);
1351 link = AddLink(src_addr, dst_addr, alias_addr,
1352 src_port, dst_port, GET_ALIAS_PORT,
1361 FindOriginalAddress(struct in_addr alias_addr)
1363 struct alias_link *link;
1365 link = FindLinkIn(nullAddress, alias_addr,
1366 0, 0, LINK_ADDR, 0);
1370 if (targetAddress.s_addr != 0)
1371 return targetAddress;
1377 if (link->src_addr.s_addr == 0)
1378 return aliasAddress;
1380 return link->src_addr;
1386 FindAliasAddress(struct in_addr original_addr)
1388 struct alias_link *link;
1390 link = FindLinkOut(original_addr, nullAddress,
1394 return aliasAddress;
1398 if (link->alias_addr.s_addr == 0)
1399 return aliasAddress;
1401 return link->alias_addr;
1406 /* External routines for getting or changing link data
1407 (external to alias_db.c, but internal to alias*.c)
1409 SetFragmentData(), GetFragmentData()
1410 SetFragmentPtr(), GetFragmentPtr()
1411 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1412 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1413 GetOriginalPort(), GetAliasPort()
1414 SetAckModified(), GetAckModified()
1415 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1420 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1422 link->data.frag_addr = src_addr;
1427 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1429 *src_addr = link->data.frag_addr;
1434 SetFragmentPtr(struct alias_link *link, char *fptr)
1436 link->data.frag_ptr = fptr;
1441 GetFragmentPtr(struct alias_link *link, char **fptr)
1443 *fptr = link->data.frag_ptr;
1448 SetStateIn(struct alias_link *link, int state)
1450 /* TCP input state */
1452 case ALIAS_TCP_STATE_DISCONNECTED:
1453 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) {
1454 link->expire_time = TCP_EXPIRE_DEAD;
1456 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1458 link->data.tcp->state.in = state;
1460 case ALIAS_TCP_STATE_CONNECTED:
1461 link->expire_time = TCP_EXPIRE_CONNECTED;
1463 case ALIAS_TCP_STATE_NOT_CONNECTED:
1464 link->data.tcp->state.in = state;
1473 SetStateOut(struct alias_link *link, int state)
1475 /* TCP output state */
1477 case ALIAS_TCP_STATE_DISCONNECTED:
1478 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) {
1479 link->expire_time = TCP_EXPIRE_DEAD;
1481 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1483 link->data.tcp->state.out = state;
1485 case ALIAS_TCP_STATE_CONNECTED:
1486 link->expire_time = TCP_EXPIRE_CONNECTED;
1488 case ALIAS_TCP_STATE_NOT_CONNECTED:
1489 link->data.tcp->state.out = state;
1498 GetStateIn(struct alias_link *link)
1500 /* TCP input state */
1501 return link->data.tcp->state.in;
1506 GetStateOut(struct alias_link *link)
1508 /* TCP output state */
1509 return link->data.tcp->state.out;
1514 GetOriginalAddress(struct alias_link *link)
1516 if (link->src_addr.s_addr == 0)
1517 return aliasAddress;
1519 return(link->src_addr);
1524 GetDestAddress(struct alias_link *link)
1526 return(link->dst_addr);
1531 GetAliasAddress(struct alias_link *link)
1533 if (link->alias_addr.s_addr == 0)
1534 return aliasAddress;
1536 return link->alias_addr;
1541 GetDefaultAliasAddress()
1543 return aliasAddress;
1548 SetDefaultAliasAddress(struct in_addr alias_addr)
1550 aliasAddress = alias_addr;
1555 GetOriginalPort(struct alias_link *link)
1557 return(link->src_port);
1562 GetAliasPort(struct alias_link *link)
1564 return(link->alias_port);
1568 GetDestPort(struct alias_link *link)
1570 return(link->dst_port);
1574 SetAckModified(struct alias_link *link)
1576 /* Indicate that ack numbers have been modified in a TCP connection */
1577 link->data.tcp->state.ack_modified = 1;
1582 GetAckModified(struct alias_link *link)
1584 /* See if ack numbers have been modified */
1585 return link->data.tcp->state.ack_modified;
1590 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1593 Find out how much the ack number has been altered for an incoming
1594 TCP packet. To do this, a circular list is ack numbers where the TCP
1595 packet size was altered is searched.
1600 int delta, ack_diff_min;
1603 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1608 for (i=0; i<N_LINK_TCP_DATA; i++)
1610 struct ack_data_record x;
1612 x = link->data.tcp->ack[i];
1617 ack_diff = SeqDiff(x.ack_new, ack);
1620 if (ack_diff_min >= 0)
1622 if (ack_diff < ack_diff_min)
1625 ack_diff_min = ack_diff;
1631 ack_diff_min = ack_diff;
1641 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1644 Find out how much the seq number has been altered for an outgoing
1645 TCP packet. To do this, a circular list is ack numbers where the TCP
1646 packet size was altered is searched.
1651 int delta, seq_diff_min;
1654 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1659 for (i=0; i<N_LINK_TCP_DATA; i++)
1661 struct ack_data_record x;
1663 x = link->data.tcp->ack[i];
1668 seq_diff = SeqDiff(x.ack_old, seq);
1671 if (seq_diff_min >= 0)
1673 if (seq_diff < seq_diff_min)
1676 seq_diff_min = seq_diff;
1682 seq_diff_min = seq_diff;
1692 AddSeq(struct ip *pip, struct alias_link *link, int delta)
1695 When a TCP packet has been altered in length, save this
1696 information in a circular list. If enough packets have
1697 been altered, then this list will begin to overwrite itself.
1701 struct ack_data_record x;
1702 int hlen, tlen, dlen;
1705 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1707 hlen = (pip->ip_hl + tc->th_off) << 2;
1708 tlen = ntohs(pip->ip_len);
1711 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1712 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1716 i = link->data.tcp->state.index;
1717 link->data.tcp->ack[i] = x;
1720 if (i == N_LINK_TCP_DATA)
1721 link->data.tcp->state.index = 0;
1723 link->data.tcp->state.index = i;
1727 SetExpire(struct alias_link *link, int expire)
1731 link->flags &= ~LINK_PERMANENT;
1734 else if (expire == -1)
1736 link->flags |= LINK_PERMANENT;
1738 else if (expire > 0)
1740 link->expire_time = expire;
1744 fprintf(stderr, "PacketAlias/SetExpire(): ");
1745 fprintf(stderr, "error in expire parameter\n");
1750 ClearCheckNewLink(void)
1756 /* Miscellaneous Functions
1759 InitPacketAliasLog()
1760 UninitPacketAliasLog()
1764 Whenever an outgoing or incoming packet is handled, HouseKeeping()
1765 is called to find and remove timed-out aliasing links. Logic exists
1766 to sweep through the entire table and linked list structure
1769 (prototype in alias_local.h)
1780 * Save system time (seconds) in global variable timeStamp for
1781 * use by other functions. This is done so as not to unnecessarily
1782 * waste timeline by making system calls.
1784 gettimeofday(&tv, &tz);
1785 timeStamp = tv.tv_sec;
1787 /* Compute number of spokes (output table link chains) to cover */
1788 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1789 n100 *= timeStamp - lastCleanupTime;
1790 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1794 /* Handle different cases */
1795 if (n > ALIAS_CLEANUP_MAX_SPOKES)
1797 n = ALIAS_CLEANUP_MAX_SPOKES;
1798 lastCleanupTime = timeStamp;
1799 houseKeepingResidual = 0;
1802 IncrementalCleanup();
1806 lastCleanupTime = timeStamp;
1807 houseKeepingResidual = n100 - 100*n;
1810 IncrementalCleanup();
1814 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1815 fprintf(stderr, "something unexpected in time values\n");
1816 lastCleanupTime = timeStamp;
1817 houseKeepingResidual = 0;
1822 /* Init the log file and enable logging */
1824 InitPacketAliasLog(void)
1826 if ((~packetAliasMode & PKT_ALIAS_LOG)
1827 && (monitorFile = fopen("/var/log/alias.log", "w")))
1829 packetAliasMode |= PKT_ALIAS_LOG;
1830 fprintf(monitorFile,
1831 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1836 /* Close the log-file and disable logging. */
1838 UninitPacketAliasLog(void)
1841 fclose(monitorFile);
1844 packetAliasMode &= ~PKT_ALIAS_LOG;
1852 /* Outside world interfaces
1854 -- "outside world" means other than alias*.c routines --
1856 PacketAliasRedirectPort()
1857 PacketAliasRedirectAddr()
1858 PacketAliasRedirectDelete()
1859 PacketAliasSetAddress()
1862 PacketAliasSetMode()
1864 (prototypes in alias.h)
1867 /* Redirection from a specific public addr:port to a
1868 a private addr:port */
1870 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
1871 struct in_addr dst_addr, u_short dst_port,
1872 struct in_addr alias_addr, u_short alias_port,
1876 struct alias_link *link;
1881 link_type = LINK_UDP;
1884 link_type = LINK_TCP;
1887 fprintf(stderr, "PacketAliasRedirectPort(): ");
1888 fprintf(stderr, "only TCP and UDP protocols allowed\n");
1892 link = AddLink(src_addr, dst_addr, alias_addr,
1893 src_port, dst_port, alias_port,
1898 link->flags |= LINK_PERMANENT;
1902 fprintf(stderr, "PacketAliasRedirectPort(): "
1903 "call to AddLink() failed\n");
1910 /* Static address translation */
1912 PacketAliasRedirectAddr(struct in_addr src_addr,
1913 struct in_addr alias_addr)
1915 struct alias_link *link;
1917 link = AddLink(src_addr, nullAddress, alias_addr,
1923 link->flags |= LINK_PERMANENT;
1927 fprintf(stderr, "PacketAliasRedirectAddr(): "
1928 "call to AddLink() failed\n");
1936 PacketAliasRedirectDelete(struct alias_link *link)
1938 /* This is a dangerous function to put in the API,
1939 because an invalid pointer can crash the program. */
1948 PacketAliasSetAddress(struct in_addr addr)
1950 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
1951 && aliasAddress.s_addr != addr.s_addr)
1954 aliasAddress = addr;
1959 PacketAliasSetTarget(struct in_addr target_addr)
1961 targetAddress = target_addr;
1966 PacketAliasInit(void)
1971 static int firstCall = 1;
1975 gettimeofday(&tv, &tz);
1976 timeStamp = tv.tv_sec;
1977 lastCleanupTime = tv.tv_sec;
1978 houseKeepingResidual = 0;
1980 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
1981 linkTableOut[i] = NULL;
1982 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
1983 linkTableIn[i] = NULL;
1985 atexit(PacketAliasUninit);
1995 aliasAddress.s_addr = 0;
1996 targetAddress.s_addr = 0;
2001 fragmentIdLinkCount = 0;
2002 fragmentPtrLinkCount = 0;
2007 packetAliasMode = PKT_ALIAS_SAME_PORTS
2008 | PKT_ALIAS_USE_SOCKETS
2009 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2013 PacketAliasUninit(void) {
2017 UninitPacketAliasLog();
2024 /* Change mode for some operations */
2027 unsigned int flags, /* Which state to bring flags to */
2028 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2029 probe for flag values) */
2032 /* Enable logging? */
2033 if (flags & mask & PKT_ALIAS_LOG)
2035 InitPacketAliasLog(); /* Do the enable */
2037 /* _Disable_ logging? */
2038 if (~flags & mask & PKT_ALIAS_LOG) {
2039 UninitPacketAliasLog();
2043 /* Start punching holes in the firewall? */
2044 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2047 /* Stop punching holes in the firewall? */
2048 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2053 /* Other flags can be set/cleared without special action */
2054 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2055 return packetAliasMode;
2060 PacketAliasCheckNewLink(void)
2062 return newDefaultLink;
2069 Code to support firewall punching. This shouldn't really be in this
2070 file, but making variables global is evil too.
2073 /* Firewall include files */
2074 #include <sys/queue.h>
2076 #include <netinet/ip_fw.h>
2080 static void ClearAllFWHoles(void);
2082 static int fireWallBaseNum; /* The first firewall entry free for our use */
2083 static int fireWallNumNums; /* How many entries can we use? */
2084 static int fireWallActiveNum; /* Which entry did we last use? */
2085 static char *fireWallField; /* bool array for entries */
2087 #define fw_setfield(field, num) \
2090 } /*lint -save -e717 */ while(0) /*lint -restore */
2091 #define fw_clrfield(field, num) \
2094 } /*lint -save -e717 */ while(0) /*lint -restore */
2095 #define fw_tstfield(field, num) ((field)[num])
2098 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2099 fireWallBaseNum = base;
2100 fireWallNumNums = num;
2105 fireWallField = malloc(fireWallNumNums);
2106 if (fireWallField) {
2107 memset(fireWallField, 0, fireWallNumNums);
2108 if (fireWallFD < 0) {
2109 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2112 fireWallActiveNum = fireWallBaseNum;
2117 UninitPunchFW(void) {
2119 if (fireWallFD >= 0)
2123 free(fireWallField);
2124 fireWallField = NULL;
2125 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2128 /* Make a certain link go through the firewall */
2130 PunchFWHole(struct alias_link *link) {
2131 int r; /* Result code */
2132 struct ip_fw rule; /* On-the-fly built rule */
2133 int fwhole; /* Where to punch hole */
2135 /* Don't do anything unless we are asked to */
2136 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2138 link->link_type != LINK_TCP ||
2142 memset(&rule, 0, sizeof rule);
2146 /* Find empty slot */
2147 for (fwhole = fireWallActiveNum;
2148 fwhole < fireWallBaseNum + fireWallNumNums &&
2149 fw_tstfield(fireWallField, fwhole);
2152 if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2153 fw_tstfield(fireWallField, fwhole)) {
2154 for (fwhole = fireWallBaseNum;
2155 fwhole < fireWallActiveNum &&
2156 fw_tstfield(fireWallField, fwhole);
2159 if (fwhole == fireWallActiveNum) {
2160 /* No rule point empty - we can't punch more holes. */
2161 fireWallActiveNum = fireWallBaseNum;
2162 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2166 /* Start next search at next position */
2167 fireWallActiveNum = fwhole+1;
2169 /* Build generic part of the two rules */
2170 rule.fw_number = fwhole;
2171 rule.fw_nports = 1; /* Number of source ports; dest ports follow */
2172 rule.fw_flg = IP_FW_F_ACCEPT;
2173 rule.fw_prot = IPPROTO_TCP;
2174 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2175 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2177 /* Build and apply specific part of the rules */
2178 rule.fw_src = GetOriginalAddress(link);
2179 rule.fw_dst = GetDestAddress(link);
2180 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2181 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2183 /* Skip non-bound links - XXX should not be strictly necessary,
2184 but seems to leave hole if not done. Leak of non-bound links?
2185 (Code should be left even if the problem is fixed - it is a
2186 clear optimization) */
2187 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2188 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2190 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2191 rule.fw_src = GetDestAddress(link);
2192 rule.fw_dst = GetOriginalAddress(link);
2193 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2194 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2195 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2197 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2199 /* Indicate hole applied */
2200 link->data.tcp->fwhole = fwhole;
2201 fw_setfield(fireWallField, fwhole);
2204 /* Remove a hole in a firewall associated with a particular alias
2205 link. Calling this too often is harmless. */
2207 ClearFWHole(struct alias_link *link) {
2208 if (link->link_type == LINK_TCP && link->data.tcp) {
2209 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2215 memset(&rule, 0, sizeof rule);
2216 rule.fw_number = fwhole;
2217 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2219 fw_clrfield(fireWallField, fwhole);
2220 link->data.tcp->fwhole = -1;
2224 /* Clear out the entire range dedicated to firewall holes. */
2226 ClearAllFWHoles(void) {
2227 struct ip_fw rule; /* On-the-fly built rule */
2233 memset(&rule, 0, sizeof rule);
2234 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2236 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2239 memset(fireWallField, 0, fireWallNumNums);