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.
112 /* System include files */
118 #include <sys/socket.h>
119 #include <sys/time.h>
120 #include <sys/types.h>
122 /* BSD network include files */
123 #include <netinet/in_systm.h>
124 #include <netinet/in.h>
125 #include <netinet/ip.h>
126 #include <netinet/tcp.h>
127 #include <arpa/inet.h>
130 #include "alias_local.h"
135 Constants (note: constants are also defined
136 near relevant functions or structs)
139 /* Sizes of input and output link tables */
140 #define LINK_TABLE_OUT_SIZE 101
141 #define LINK_TABLE_IN_SIZE 4001
143 /* Parameters used for cleanup of expired links */
144 #define ALIAS_CLEANUP_INTERVAL_SECS 60
145 #define ALIAS_CLEANUP_MAX_SPOKES 30
147 /* Timeouts (in seconds) for different link types */
148 #define ICMP_EXPIRE_TIME 60
149 #define UDP_EXPIRE_TIME 60
150 #define FRAGMENT_ID_EXPIRE_TIME 10
151 #define FRAGMENT_PTR_EXPIRE_TIME 30
153 /* TCP link expire time for different cases */
154 /* When the link has been used and closed - minimal grace time to
155 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
156 #ifndef TCP_EXPIRE_DEAD
157 # define TCP_EXPIRE_DEAD 10
160 /* When the link has been used and closed on one side - the other side
161 is allowed to still send data */
162 #ifndef TCP_EXPIRE_SINGLEDEAD
163 # define TCP_EXPIRE_SINGLEDEAD 90
166 /* When the link isn't yet up */
167 #ifndef TCP_EXPIRE_INITIAL
168 # define TCP_EXPIRE_INITIAL 300
171 /* When the link is up */
172 #ifndef TCP_EXPIRE_CONNECTED
173 # define TCP_EXPIRE_CONNECTED 86400
177 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
178 These constants can be anything except zero, which indicates an
179 unknown port number. */
181 #define NO_DEST_PORT 1
182 #define NO_SRC_PORT 1
188 The fundamental data structure used in this program is
189 "struct alias_link". Whenever a TCP connection is made,
190 a UDP datagram is sent out, or an ICMP echo request is made,
191 a link record is made (if it has not already been created).
192 The link record is identified by the source address/port
193 and the destination address/port. In the case of an ICMP
194 echo request, the source port is treated as being equivalent
195 with the 16-bit id number of the ICMP packet.
197 The link record also can store some auxiliary data. For
198 TCP connections that have had sequence and acknowledgment
199 modifications, data space is available to track these changes.
200 A state field is used to keep track in changes to the tcp
201 connection state. Id numbers of fragments can also be
202 stored in the auxiliary space. Pointers to unresolved
203 framgents can also be stored.
205 The link records support two independent chainings. Lookup
206 tables for input and out tables hold the initial pointers
207 the link chains. On input, the lookup table indexes on alias
208 port and link type. On output, the lookup table indexes on
209 source addreess, destination address, source port, destination
213 struct ack_data_record /* used to save changes to ack/seq numbers */
221 struct tcp_state /* Information about tcp connection */
223 int in; /* State for outside -> inside */
224 int out; /* State for inside -> outside */
225 int index; /* Index to ack data array */
226 int ack_modified; /* Indicates whether ack and seq numbers */
230 #define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes
231 saved for a modified TCP stream */
234 struct tcp_state state;
235 struct ack_data_record ack[N_LINK_TCP_DATA];
236 int fwhole; /* Which firewall record is used for this hole? */
239 struct alias_link /* Main data structure */
241 struct in_addr src_addr; /* Address and port information */
242 struct in_addr dst_addr;
243 struct in_addr alias_addr;
244 struct in_addr proxy_addr;
250 int link_type; /* Type of link: tcp, udp, icmp, frag */
252 /* values for link_type */
256 #define LINK_FRAGMENT_ID 4
257 #define LINK_FRAGMENT_PTR 5
260 int flags; /* indicates special characteristics */
263 #define LINK_UNKNOWN_DEST_PORT 0x01
264 #define LINK_UNKNOWN_DEST_ADDR 0x02
265 #define LINK_PERMANENT 0x04
266 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
267 #define LINK_UNFIREWALLED 0x08
269 int timestamp; /* Time link was last accessed */
270 int expire_time; /* Expire time for link */
272 int sockfd; /* socket descriptor */
274 u_int start_point_out; /* Index number in output lookup table */
275 u_int start_point_in;
276 struct alias_link *next_out; /* Linked list pointers for input and */
277 struct alias_link *last_out; /* output tables */
278 struct alias_link *next_in; /* . */
279 struct alias_link *last_in; /* . */
281 union /* Auxiliary data */
284 struct in_addr frag_addr;
295 The global variables listed here are only accessed from
296 within alias_db.c and so are prefixed with the static
300 int packetAliasMode; /* Mode flags */
301 /* - documented in alias.h */
303 static struct in_addr aliasAddress; /* Address written onto source */
304 /* field of IP packet. */
306 static struct in_addr targetAddress; /* IP address incoming packets */
307 /* are sent to if no aliasing */
308 /* link already exists */
310 static struct in_addr nullAddress; /* Used as a dummy parameter for */
311 /* some function calls */
312 static struct alias_link *
313 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */
314 /* chains of link records. Each */
315 static struct alias_link * /* link record is doubly indexed */
316 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */
319 static int icmpLinkCount; /* Link statistics */
320 static int udpLinkCount;
321 static int tcpLinkCount;
322 static int fragmentIdLinkCount;
323 static int fragmentPtrLinkCount;
324 static int sockCount;
326 static int cleanupIndex; /* Index to chain of link table */
327 /* being inspected for old links */
329 static int timeStamp; /* System time in seconds for */
332 static int lastCleanupTime; /* Last time IncrementalCleanup() */
335 static int houseKeepingResidual; /* used by HouseKeeping() */
337 static int deleteAllLinks; /* If equal to zero, DeleteLink() */
338 /* will not remove permanent links */
340 static FILE *monitorFile; /* File descriptor for link */
341 /* statistics monitoring file */
343 static int newDefaultLink; /* Indicates if a new aliasing */
344 /* link has been created after a */
345 /* call to PacketAliasIn/Out(). */
348 static int fireWallFD = -1; /* File descriptor to be able to */
349 /* control firewall. Opened by */
350 /* PacketAliasSetMode on first */
351 /* setting the PKT_ALIAS_PUNCH_FW */
355 static int pptpAliasFlag; /* Indicates if PPTP aliasing is */
357 static struct in_addr pptpAliasAddr; /* Address of source of PPTP */
366 /* Internal utility routines (used only in alias_db.c)
368 Lookup table starting points:
369 StartPointIn() -- link table initial search point for
371 StartPointOut() -- port table initial search point for
375 SeqDiff() -- difference between two TCP sequences
376 ShowAliasStats() -- send alias statistics to a monitor file
380 /* Local prototypes */
381 static u_int StartPointIn(struct in_addr, u_short, int);
383 static u_int StartPointOut(struct in_addr, struct in_addr,
384 u_short, u_short, int);
386 static int SeqDiff(u_long, u_long);
388 static void ShowAliasStats(void);
391 /* Firewall control */
392 static void InitPunchFW(void);
393 static void UninitPunchFW(void);
394 static void ClearFWHole(struct alias_link *link);
397 /* Log file control */
398 static void InitPacketAliasLog(void);
399 static void UninitPacketAliasLog(void);
402 StartPointIn(struct in_addr alias_addr,
408 n = alias_addr.s_addr;
411 return(n % LINK_TABLE_IN_SIZE);
416 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
417 u_short src_port, u_short dst_port, int link_type)
422 n += dst_addr.s_addr;
427 return(n % LINK_TABLE_OUT_SIZE);
432 SeqDiff(u_long x, u_long y)
434 /* Return the difference between two TCP sequence numbers */
437 This function is encapsulated in case there are any unusual
438 arithmetic conditions that need to be considered.
441 return (ntohl(y) - ntohl(x));
448 /* Used for debugging */
452 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d",
457 fragmentPtrLinkCount);
459 fprintf(monitorFile, " / tot=%d (sock=%d)\n",
460 icmpLinkCount + udpLinkCount
462 + fragmentIdLinkCount
463 + fragmentPtrLinkCount,
474 /* Internal routines for finding, deleting and adding links
477 GetNewPort() -- find and reserve new alias port number
478 GetSocket() -- try to allocate a socket for a given port
480 Link creation and deletion:
481 CleanupAliasData() - remove all link chains from lookup table
482 IncrementalCleanup() - look for stale links in a single chain
483 DeleteLink() - remove link
485 ReLink() - change link
488 FindLinkOut() - find link for outgoing packets
489 FindLinkIn() - find link for incoming packets
492 /* Local prototypes */
493 static int GetNewPort(struct alias_link *, int);
495 static u_short GetSocket(u_short, int *, int);
497 static void CleanupAliasData(void);
499 static void IncrementalCleanup(void);
501 static void DeleteLink(struct alias_link *);
503 static struct alias_link *
504 AddLink(struct in_addr, struct in_addr, struct in_addr,
505 u_short, u_short, int, int);
507 static struct alias_link *
508 ReLink(struct alias_link *,
509 struct in_addr, struct in_addr, struct in_addr,
510 u_short, u_short, int, int);
512 static struct alias_link *
513 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int);
515 static struct alias_link *
516 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
519 #define ALIAS_PORT_BASE 0x08000
520 #define ALIAS_PORT_MASK 0x07fff
521 #define GET_NEW_PORT_MAX_ATTEMPTS 20
523 #define GET_ALIAS_PORT -1
524 #define GET_ALIAS_ID GET_ALIAS_PORT
526 /* GetNewPort() allocates port numbers. Note that if a port number
527 is already in use, that does not mean that it cannot be used by
528 another link concurrently. This is because GetNewPort() looks for
529 unused triplets: (dest addr, dest port, alias port). */
532 GetNewPort(struct alias_link *link, int alias_port_param)
540 Description of alias_port_param for GetNewPort(). When
541 this parameter is zero or positive, it precisely specifies
542 the port number. GetNewPort() will return this number
543 without check that it is in use.
545 Whis this parameter is -1, it indicates to get a randomly
546 selected port number.
549 if (alias_port_param == GET_ALIAS_PORT)
552 * The aliasing port is automatically selected
553 * by one of two methods below:
555 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
557 if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
560 * When the ALIAS_SAME_PORTS option is
561 * chosen, the first try will be the
562 * actual source port. If this is already
563 * in use, the remainder of the trials
566 port_net = link->src_port;
567 port_sys = ntohs(port_net);
571 /* First trial and all subsequent are random. */
572 port_sys = random() & ALIAS_PORT_MASK;
573 port_sys += ALIAS_PORT_BASE;
574 port_net = htons(port_sys);
577 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
579 link->alias_port = (u_short) alias_port_param;
585 fprintf(stderr, "PacketAlias/GetNewPort(): ");
586 fprintf(stderr, "input parameter error\n");
592 /* Port number search */
593 for (i=0; i<max_trials; i++)
596 struct alias_link *search_result;
598 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
599 link->dst_port, port_net,
602 if (search_result == NULL)
604 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
605 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
612 if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS)
613 && (link->flags & LINK_PARTIALLY_SPECIFIED))
615 if (GetSocket(port_net, &link->sockfd, link->link_type))
617 link->alias_port = port_net;
623 link->alias_port = port_net;
628 port_sys = random() & ALIAS_PORT_MASK;
629 port_sys += ALIAS_PORT_BASE;
630 port_net = htons(port_sys);
634 fprintf(stderr, "PacketAlias/GetnewPort(): ");
635 fprintf(stderr, "could not find free port\n");
643 GetSocket(u_short port_net, int *sockfd, int link_type)
647 struct sockaddr_in sock_addr;
649 if (link_type == LINK_TCP)
650 sock = socket(AF_INET, SOCK_STREAM, 0);
651 else if (link_type == LINK_UDP)
652 sock = socket(AF_INET, SOCK_DGRAM, 0);
656 fprintf(stderr, "PacketAlias/GetSocket(): ");
657 fprintf(stderr, "incorrect link type\n");
665 fprintf(stderr, "PacketAlias/GetSocket(): ");
666 fprintf(stderr, "socket() error %d\n", *sockfd);
671 sock_addr.sin_family = AF_INET;
672 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
673 sock_addr.sin_port = port_net;
676 (struct sockaddr *) &sock_addr,
693 CleanupAliasData(void)
695 struct alias_link *link;
699 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
701 link = linkTableOut[i];
704 struct alias_link *link_next;
705 link_next = link->next_out;
717 IncrementalCleanup(void)
720 struct alias_link *link;
723 link = linkTableOut[cleanupIndex++];
727 struct alias_link *link_next;
729 link_next = link->next_out;
730 idelta = timeStamp - link->timestamp;
731 switch (link->link_type)
735 case LINK_FRAGMENT_ID:
736 case LINK_FRAGMENT_PTR:
737 if (idelta > link->expire_time)
744 if (idelta > link->expire_time)
746 struct tcp_dat *tcp_aux;
748 tcp_aux = link->data.tcp;
749 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
750 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
761 if (cleanupIndex == LINK_TABLE_OUT_SIZE)
766 DeleteLink(struct alias_link *link)
768 struct alias_link *link_last;
769 struct alias_link *link_next;
771 /* Don't do anything if the link is marked permanent */
772 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
776 /* Delete associatied firewall hole, if any */
780 /* Adjust output table pointers */
781 link_last = link->last_out;
782 link_next = link->next_out;
784 if (link_last != NULL)
785 link_last->next_out = link_next;
787 linkTableOut[link->start_point_out] = link_next;
789 if (link_next != NULL)
790 link_next->last_out = link_last;
792 /* Adjust input table pointers */
793 link_last = link->last_in;
794 link_next = link->next_in;
796 if (link_last != NULL)
797 link_last->next_in = link_next;
799 linkTableIn[link->start_point_in] = link_next;
801 if (link_next != NULL)
802 link_next->last_in = link_last;
804 /* Close socket, if one has been allocated */
805 if (link->sockfd != -1)
811 /* Link-type dependent cleanup */
812 switch(link->link_type)
822 if (link->data.tcp != NULL)
823 free(link->data.tcp);
825 case LINK_FRAGMENT_ID:
826 fragmentIdLinkCount--;
828 case LINK_FRAGMENT_PTR:
829 fragmentPtrLinkCount--;
830 if (link->data.frag_ptr != NULL)
831 free(link->data.frag_ptr);
838 /* Write statistics, if logging enabled */
839 if (packetAliasMode & PKT_ALIAS_LOG)
846 static struct alias_link *
847 AddLink(struct in_addr src_addr,
848 struct in_addr dst_addr,
849 struct in_addr alias_addr,
852 int alias_port_param, /* if less than zero, alias */
853 int link_type) /* port will be automatically */
854 { /* chosen. If greater than */
855 u_int start_point; /* zero, equal to alias port */
856 struct alias_link *link;
857 struct alias_link *first_link;
859 link = malloc(sizeof(struct alias_link));
862 /* If either the aliasing address or source address are
863 equal to the default device address (equal to the
864 global variable aliasAddress), then set the alias
865 address field of the link record to zero */
867 if (src_addr.s_addr == aliasAddress.s_addr)
870 if (alias_addr.s_addr == aliasAddress.s_addr)
871 alias_addr.s_addr = 0;
873 /* Basic initialization */
874 link->src_addr = src_addr;
875 link->dst_addr = dst_addr;
876 link->alias_addr = alias_addr;
877 link->proxy_addr.s_addr = 0;
878 link->src_port = src_port;
879 link->dst_port = dst_port;
880 link->proxy_port = 0;
881 link->link_type = link_type;
884 link->timestamp = timeStamp;
886 /* Expiration time */
890 link->expire_time = ICMP_EXPIRE_TIME;
893 link->expire_time = UDP_EXPIRE_TIME;
896 link->expire_time = TCP_EXPIRE_INITIAL;
898 case LINK_FRAGMENT_ID:
899 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
901 case LINK_FRAGMENT_PTR:
902 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
906 /* Determine alias flags */
907 if (dst_addr.s_addr == 0)
908 link->flags |= LINK_UNKNOWN_DEST_ADDR;
910 link->flags |= LINK_UNKNOWN_DEST_PORT;
912 /* Determine alias port */
913 if (GetNewPort(link, alias_port_param) != 0)
919 /* Set up pointers for output lookup table */
920 start_point = StartPointOut(src_addr, dst_addr,
921 src_port, dst_port, link_type);
922 first_link = linkTableOut[start_point];
924 link->last_out = NULL;
925 link->next_out = first_link;
926 link->start_point_out = start_point;
928 if (first_link != NULL)
929 first_link->last_out = link;
931 linkTableOut[start_point] = link;
933 /* Set up pointers for input lookup table */
934 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
935 first_link = linkTableIn[start_point];
937 link->last_in = NULL;
938 link->next_in = first_link;
939 link->start_point_in = start_point;
941 if (first_link != NULL)
942 first_link->last_in = link;
944 linkTableIn[start_point] = link;
946 /* Link-type dependent initialization */
949 struct tcp_dat *aux_tcp;
958 aux_tcp = malloc(sizeof(struct tcp_dat));
959 link->data.tcp = aux_tcp;
965 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
966 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
967 aux_tcp->state.index = 0;
968 aux_tcp->state.ack_modified = 0;
969 for (i=0; i<N_LINK_TCP_DATA; i++)
970 aux_tcp->ack[i].active = 0;
971 aux_tcp->fwhole = -1;
976 fprintf(stderr, "PacketAlias/AddLink: ");
977 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
981 case LINK_FRAGMENT_ID:
982 fragmentIdLinkCount++;
984 case LINK_FRAGMENT_PTR:
985 fragmentPtrLinkCount++;
992 fprintf(stderr, "PacketAlias/AddLink(): ");
993 fprintf(stderr, "malloc() call failed.\n");
997 if (packetAliasMode & PKT_ALIAS_LOG)
1005 static struct alias_link *
1006 ReLink(struct alias_link *old_link,
1007 struct in_addr src_addr,
1008 struct in_addr dst_addr,
1009 struct in_addr alias_addr,
1012 int alias_port_param, /* if less than zero, alias */
1013 int link_type) /* port will be automatically */
1014 { /* chosen. If greater than */
1015 struct alias_link *new_link; /* zero, equal to alias port */
1017 new_link = AddLink(src_addr, dst_addr, alias_addr,
1018 src_port, dst_port, alias_port_param,
1021 if (new_link != NULL &&
1022 old_link->link_type == LINK_TCP &&
1023 old_link->data.tcp &&
1024 old_link->data.tcp->fwhole > 0) {
1025 PunchFWHole(new_link);
1028 DeleteLink(old_link);
1032 static struct alias_link *
1033 FindLinkOut(struct in_addr src_addr,
1034 struct in_addr dst_addr,
1040 struct alias_link *link;
1042 if (src_addr.s_addr == aliasAddress.s_addr)
1043 src_addr.s_addr = 0;
1045 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1046 link = linkTableOut[i];
1047 while (link != NULL)
1049 if (link->src_addr.s_addr == src_addr.s_addr
1050 && link->dst_addr.s_addr == dst_addr.s_addr
1051 && link->dst_port == dst_port
1052 && link->src_port == src_port
1053 && link->link_type == link_type)
1055 link->timestamp = timeStamp;
1058 link = link->next_out;
1061 /* Search for partially specified links. */
1066 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type);
1068 else if (dst_addr.s_addr != 0)
1070 link = FindLinkOut(src_addr, nullAddress, src_port, 0, link_type);
1079 FindLinkIn(struct in_addr dst_addr,
1080 struct in_addr alias_addr,
1084 int replace_partial_links)
1088 struct alias_link *link;
1089 struct alias_link *link_fully_specified;
1090 struct alias_link *link_unknown_all;
1091 struct alias_link *link_unknown_dst_addr;
1092 struct alias_link *link_unknown_dst_port;
1094 /* Initialize pointers */
1095 link_fully_specified = NULL;
1096 link_unknown_all = NULL;
1097 link_unknown_dst_addr = NULL;
1098 link_unknown_dst_port = NULL;
1100 /* If either the dest addr or port is unknown, the search
1101 loop will have to know about this. */
1104 if (dst_addr.s_addr == 0)
1105 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1107 flags_in |= LINK_UNKNOWN_DEST_PORT;
1109 /* The following allows permanent links to be
1110 be specified as using the default aliasing address
1111 (i.e. device interface address) without knowing
1112 in advance what that address is. */
1114 if (alias_addr.s_addr == aliasAddress.s_addr)
1115 alias_addr.s_addr = 0;
1118 start_point = StartPointIn(alias_addr, alias_port, link_type);
1119 link = linkTableIn[start_point];
1120 while (link != NULL)
1124 flags = flags_in | link->flags;
1125 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1127 if (link->alias_addr.s_addr == alias_addr.s_addr
1128 && link->alias_port == alias_port
1129 && link->dst_addr.s_addr == dst_addr.s_addr
1130 && link->dst_port == dst_port
1131 && link->link_type == link_type)
1133 link_fully_specified = link;
1137 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1138 && (flags & LINK_UNKNOWN_DEST_PORT))
1140 if (link->alias_addr.s_addr == alias_addr.s_addr
1141 && link->alias_port == alias_port
1142 && link->link_type == link_type)
1144 if (link_unknown_all == NULL)
1145 link_unknown_all = link;
1148 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1150 if (link->alias_addr.s_addr == alias_addr.s_addr
1151 && link->alias_port == alias_port
1152 && link->link_type == link_type
1153 && link->dst_port == dst_port)
1155 if (link_unknown_dst_addr == NULL)
1156 link_unknown_dst_addr = link;
1159 else if (flags & LINK_UNKNOWN_DEST_PORT)
1161 if (link->alias_addr.s_addr == alias_addr.s_addr
1162 && link->alias_port == alias_port
1163 && link->link_type == link_type
1164 && link->dst_addr.s_addr == dst_addr.s_addr)
1166 if (link_unknown_dst_port == NULL)
1167 link_unknown_dst_port = link;
1170 link = link->next_in;
1175 if (link_fully_specified != NULL)
1177 link_fully_specified->timestamp = timeStamp;
1178 return link_fully_specified;
1180 else if (link_unknown_dst_port != NULL)
1182 return replace_partial_links
1183 ? ReLink(link_unknown_dst_port,
1184 link_unknown_dst_port->src_addr, dst_addr, alias_addr,
1185 link_unknown_dst_port->src_port, dst_port, alias_port,
1187 : link_unknown_dst_port;
1189 else if (link_unknown_dst_addr != NULL)
1191 return replace_partial_links
1192 ? ReLink(link_unknown_dst_addr,
1193 link_unknown_dst_addr->src_addr, dst_addr, alias_addr,
1194 link_unknown_dst_addr->src_port, dst_port, alias_port,
1196 : link_unknown_dst_addr;
1198 else if (link_unknown_all != NULL)
1200 return replace_partial_links
1201 ? ReLink(link_unknown_all,
1202 link_unknown_all->src_addr, dst_addr, alias_addr,
1203 link_unknown_all->src_port, dst_port, alias_port,
1216 /* External routines for finding/adding links
1218 -- "external" means outside alias_db.c, but within alias*.c --
1220 FindIcmpIn(), FindIcmpOut()
1221 FindFragmentIn1(), FindFragmentIn2()
1222 AddFragmentPtrLink(), FindFragmentPtr()
1223 FindUdpTcpIn(), FindUdpTcpOut()
1224 FindOriginalAddress(), FindAliasAddress()
1226 (prototypes in alias_local.h)
1231 FindIcmpIn(struct in_addr dst_addr,
1232 struct in_addr alias_addr,
1235 return FindLinkIn(dst_addr, alias_addr,
1236 NO_DEST_PORT, id_alias,
1242 FindIcmpOut(struct in_addr src_addr,
1243 struct in_addr dst_addr,
1246 struct alias_link * link;
1248 link = FindLinkOut(src_addr, dst_addr,
1253 struct in_addr alias_addr;
1255 alias_addr = FindAliasAddress(src_addr);
1256 link = AddLink(src_addr, dst_addr, alias_addr,
1257 id, NO_DEST_PORT, GET_ALIAS_ID,
1266 FindFragmentIn1(struct in_addr dst_addr,
1267 struct in_addr alias_addr,
1270 struct alias_link *link;
1272 link = FindLinkIn(dst_addr, alias_addr,
1273 NO_DEST_PORT, ip_id,
1274 LINK_FRAGMENT_ID, 0);
1278 link = AddLink(nullAddress, dst_addr, alias_addr,
1279 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1288 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1289 struct in_addr alias_addr, /* is not found. */
1292 return FindLinkIn(dst_addr, alias_addr,
1293 NO_DEST_PORT, ip_id,
1294 LINK_FRAGMENT_ID, 0);
1299 AddFragmentPtrLink(struct in_addr dst_addr,
1302 return AddLink(nullAddress, dst_addr, nullAddress,
1303 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1309 FindFragmentPtr(struct in_addr dst_addr,
1312 return FindLinkIn(dst_addr, nullAddress,
1313 NO_DEST_PORT, ip_id,
1314 LINK_FRAGMENT_PTR, 0);
1319 FindUdpTcpIn(struct in_addr dst_addr,
1320 struct in_addr alias_addr,
1326 struct alias_link *link;
1331 link_type = LINK_UDP;
1334 link_type = LINK_TCP;
1341 link = FindLinkIn(dst_addr, alias_addr,
1342 dst_port, alias_port,
1345 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING)
1346 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)
1349 struct in_addr target_addr;
1351 target_addr = FindOriginalAddress(alias_addr);
1352 link = AddLink(target_addr, dst_addr, alias_addr,
1353 alias_port, dst_port, alias_port,
1362 FindUdpTcpOut(struct in_addr src_addr,
1363 struct in_addr dst_addr,
1369 struct alias_link *link;
1374 link_type = LINK_UDP;
1377 link_type = LINK_TCP;
1384 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type);
1388 struct in_addr alias_addr;
1390 alias_addr = FindAliasAddress(src_addr);
1391 link = AddLink(src_addr, dst_addr, alias_addr,
1392 src_port, dst_port, GET_ALIAS_PORT,
1401 FindOriginalAddress(struct in_addr alias_addr)
1403 struct alias_link *link;
1405 link = FindLinkIn(nullAddress, alias_addr,
1406 0, 0, LINK_ADDR, 0);
1410 if (targetAddress.s_addr != 0)
1411 return targetAddress;
1417 if (link->src_addr.s_addr == 0)
1418 return aliasAddress;
1420 return link->src_addr;
1426 FindAliasAddress(struct in_addr original_addr)
1428 struct alias_link *link;
1430 link = FindLinkOut(original_addr, nullAddress,
1434 return aliasAddress;
1438 if (link->alias_addr.s_addr == 0)
1439 return aliasAddress;
1441 return link->alias_addr;
1446 /* External routines for getting or changing link data
1447 (external to alias_db.c, but internal to alias*.c)
1449 SetFragmentData(), GetFragmentData()
1450 SetFragmentPtr(), GetFragmentPtr()
1451 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1452 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1453 GetOriginalPort(), GetAliasPort()
1454 SetAckModified(), GetAckModified()
1455 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1460 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1462 link->data.frag_addr = src_addr;
1467 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1469 *src_addr = link->data.frag_addr;
1474 SetFragmentPtr(struct alias_link *link, char *fptr)
1476 link->data.frag_ptr = fptr;
1481 GetFragmentPtr(struct alias_link *link, char **fptr)
1483 *fptr = link->data.frag_ptr;
1488 SetStateIn(struct alias_link *link, int state)
1490 /* TCP input state */
1492 case ALIAS_TCP_STATE_DISCONNECTED:
1493 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) {
1494 link->expire_time = TCP_EXPIRE_DEAD;
1496 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1498 link->data.tcp->state.in = state;
1500 case ALIAS_TCP_STATE_CONNECTED:
1501 link->expire_time = TCP_EXPIRE_CONNECTED;
1503 case ALIAS_TCP_STATE_NOT_CONNECTED:
1504 link->data.tcp->state.in = state;
1513 SetStateOut(struct alias_link *link, int state)
1515 /* TCP output state */
1517 case ALIAS_TCP_STATE_DISCONNECTED:
1518 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) {
1519 link->expire_time = TCP_EXPIRE_DEAD;
1521 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1523 link->data.tcp->state.out = state;
1525 case ALIAS_TCP_STATE_CONNECTED:
1526 link->expire_time = TCP_EXPIRE_CONNECTED;
1528 case ALIAS_TCP_STATE_NOT_CONNECTED:
1529 link->data.tcp->state.out = state;
1538 GetStateIn(struct alias_link *link)
1540 /* TCP input state */
1541 return link->data.tcp->state.in;
1546 GetStateOut(struct alias_link *link)
1548 /* TCP output state */
1549 return link->data.tcp->state.out;
1554 GetOriginalAddress(struct alias_link *link)
1556 if (link->src_addr.s_addr == 0)
1557 return aliasAddress;
1559 return(link->src_addr);
1564 GetDestAddress(struct alias_link *link)
1566 return(link->dst_addr);
1571 GetAliasAddress(struct alias_link *link)
1573 if (link->alias_addr.s_addr == 0)
1574 return aliasAddress;
1576 return link->alias_addr;
1581 GetDefaultAliasAddress()
1583 return aliasAddress;
1588 SetDefaultAliasAddress(struct in_addr alias_addr)
1590 aliasAddress = alias_addr;
1595 GetOriginalPort(struct alias_link *link)
1597 return(link->src_port);
1602 GetAliasPort(struct alias_link *link)
1604 return(link->alias_port);
1608 GetDestPort(struct alias_link *link)
1610 return(link->dst_port);
1614 SetAckModified(struct alias_link *link)
1616 /* Indicate that ack numbers have been modified in a TCP connection */
1617 link->data.tcp->state.ack_modified = 1;
1622 GetProxyAddress(struct alias_link *link)
1624 return link->proxy_addr;
1629 SetProxyAddress(struct alias_link *link, struct in_addr addr)
1631 link->proxy_addr = addr;
1636 GetProxyPort(struct alias_link *link)
1638 return link->proxy_port;
1643 SetProxyPort(struct alias_link *link, u_short port)
1645 link->proxy_port = port;
1650 GetAckModified(struct alias_link *link)
1652 /* See if ack numbers have been modified */
1653 return link->data.tcp->state.ack_modified;
1658 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1661 Find out how much the ack number has been altered for an incoming
1662 TCP packet. To do this, a circular list is ack numbers where the TCP
1663 packet size was altered is searched.
1668 int delta, ack_diff_min;
1671 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1676 for (i=0; i<N_LINK_TCP_DATA; i++)
1678 struct ack_data_record x;
1680 x = link->data.tcp->ack[i];
1685 ack_diff = SeqDiff(x.ack_new, ack);
1688 if (ack_diff_min >= 0)
1690 if (ack_diff < ack_diff_min)
1693 ack_diff_min = ack_diff;
1699 ack_diff_min = ack_diff;
1709 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1712 Find out how much the seq number has been altered for an outgoing
1713 TCP packet. To do this, a circular list is ack numbers where the TCP
1714 packet size was altered is searched.
1719 int delta, seq_diff_min;
1722 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1727 for (i=0; i<N_LINK_TCP_DATA; i++)
1729 struct ack_data_record x;
1731 x = link->data.tcp->ack[i];
1736 seq_diff = SeqDiff(x.ack_old, seq);
1739 if (seq_diff_min >= 0)
1741 if (seq_diff < seq_diff_min)
1744 seq_diff_min = seq_diff;
1750 seq_diff_min = seq_diff;
1760 AddSeq(struct ip *pip, struct alias_link *link, int delta)
1763 When a TCP packet has been altered in length, save this
1764 information in a circular list. If enough packets have
1765 been altered, then this list will begin to overwrite itself.
1769 struct ack_data_record x;
1770 int hlen, tlen, dlen;
1773 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1775 hlen = (pip->ip_hl + tc->th_off) << 2;
1776 tlen = ntohs(pip->ip_len);
1779 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1780 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1784 i = link->data.tcp->state.index;
1785 link->data.tcp->ack[i] = x;
1788 if (i == N_LINK_TCP_DATA)
1789 link->data.tcp->state.index = 0;
1791 link->data.tcp->state.index = i;
1795 SetExpire(struct alias_link *link, int expire)
1799 link->flags &= ~LINK_PERMANENT;
1802 else if (expire == -1)
1804 link->flags |= LINK_PERMANENT;
1806 else if (expire > 0)
1808 link->expire_time = expire;
1813 fprintf(stderr, "PacketAlias/SetExpire(): ");
1814 fprintf(stderr, "error in expire parameter\n");
1820 ClearCheckNewLink(void)
1826 /* Miscellaneous Functions
1829 InitPacketAliasLog()
1830 UninitPacketAliasLog()
1834 Whenever an outgoing or incoming packet is handled, HouseKeeping()
1835 is called to find and remove timed-out aliasing links. Logic exists
1836 to sweep through the entire table and linked list structure
1839 (prototype in alias_local.h)
1850 * Save system time (seconds) in global variable timeStamp for
1851 * use by other functions. This is done so as not to unnecessarily
1852 * waste timeline by making system calls.
1854 gettimeofday(&tv, &tz);
1855 timeStamp = tv.tv_sec;
1857 /* Compute number of spokes (output table link chains) to cover */
1858 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1859 n100 *= timeStamp - lastCleanupTime;
1860 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1864 /* Handle different cases */
1865 if (n > ALIAS_CLEANUP_MAX_SPOKES)
1867 n = ALIAS_CLEANUP_MAX_SPOKES;
1868 lastCleanupTime = timeStamp;
1869 houseKeepingResidual = 0;
1872 IncrementalCleanup();
1876 lastCleanupTime = timeStamp;
1877 houseKeepingResidual = n100 - 100*n;
1880 IncrementalCleanup();
1885 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1886 fprintf(stderr, "something unexpected in time values\n");
1888 lastCleanupTime = timeStamp;
1889 houseKeepingResidual = 0;
1894 /* Init the log file and enable logging */
1896 InitPacketAliasLog(void)
1898 if ((~packetAliasMode & PKT_ALIAS_LOG)
1899 && (monitorFile = fopen("/var/log/alias.log", "w")))
1901 packetAliasMode |= PKT_ALIAS_LOG;
1902 fprintf(monitorFile,
1903 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1908 /* Close the log-file and disable logging. */
1910 UninitPacketAliasLog(void)
1913 fclose(monitorFile);
1916 packetAliasMode &= ~PKT_ALIAS_LOG;
1924 /* Outside world interfaces
1926 -- "outside world" means other than alias*.c routines --
1928 PacketAliasRedirectPort()
1929 PacketAliasRedirectAddr()
1930 PacketAliasRedirectDelete()
1931 PacketAliasSetAddress()
1934 PacketAliasSetMode()
1936 (prototypes in alias.h)
1939 /* Redirection from a specific public addr:port to a
1940 a private addr:port */
1942 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
1943 struct in_addr dst_addr, u_short dst_port,
1944 struct in_addr alias_addr, u_short alias_port,
1948 struct alias_link *link;
1953 link_type = LINK_UDP;
1956 link_type = LINK_TCP;
1960 fprintf(stderr, "PacketAliasRedirectPort(): ");
1961 fprintf(stderr, "only TCP and UDP protocols allowed\n");
1966 link = AddLink(src_addr, dst_addr, alias_addr,
1967 src_port, dst_port, alias_port,
1972 link->flags |= LINK_PERMANENT;
1977 fprintf(stderr, "PacketAliasRedirectPort(): "
1978 "call to AddLink() failed\n");
1985 /* Translate PPTP packets to a machine on the inside
1988 PacketAliasPptp(struct in_addr src_addr)
1991 pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */
1992 pptpAliasFlag = src_addr.s_addr != INADDR_NONE;
1997 int GetPptpAlias (struct in_addr* alias_addr)
2000 *alias_addr = pptpAliasAddr;
2002 return pptpAliasFlag;
2005 /* Static address translation */
2007 PacketAliasRedirectAddr(struct in_addr src_addr,
2008 struct in_addr alias_addr)
2010 struct alias_link *link;
2012 link = AddLink(src_addr, nullAddress, alias_addr,
2018 link->flags |= LINK_PERMANENT;
2023 fprintf(stderr, "PacketAliasRedirectAddr(): "
2024 "call to AddLink() failed\n");
2033 PacketAliasRedirectDelete(struct alias_link *link)
2035 /* This is a dangerous function to put in the API,
2036 because an invalid pointer can crash the program. */
2045 PacketAliasSetAddress(struct in_addr addr)
2047 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2048 && aliasAddress.s_addr != addr.s_addr)
2051 aliasAddress = addr;
2056 PacketAliasSetTarget(struct in_addr target_addr)
2058 targetAddress = target_addr;
2063 PacketAliasInit(void)
2068 static int firstCall = 1;
2072 gettimeofday(&tv, &tz);
2073 timeStamp = tv.tv_sec;
2074 lastCleanupTime = tv.tv_sec;
2075 houseKeepingResidual = 0;
2077 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2078 linkTableOut[i] = NULL;
2079 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2080 linkTableIn[i] = NULL;
2082 atexit(PacketAliasUninit);
2092 aliasAddress.s_addr = 0;
2093 targetAddress.s_addr = 0;
2098 fragmentIdLinkCount = 0;
2099 fragmentPtrLinkCount = 0;
2104 packetAliasMode = PKT_ALIAS_SAME_PORTS
2105 | PKT_ALIAS_USE_SOCKETS
2106 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2112 PacketAliasUninit(void) {
2116 UninitPacketAliasLog();
2123 /* Change mode for some operations */
2126 unsigned int flags, /* Which state to bring flags to */
2127 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2128 probe for flag values) */
2131 /* Enable logging? */
2132 if (flags & mask & PKT_ALIAS_LOG)
2134 InitPacketAliasLog(); /* Do the enable */
2136 /* _Disable_ logging? */
2137 if (~flags & mask & PKT_ALIAS_LOG) {
2138 UninitPacketAliasLog();
2142 /* Start punching holes in the firewall? */
2143 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2146 /* Stop punching holes in the firewall? */
2147 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2152 /* Other flags can be set/cleared without special action */
2153 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2154 return packetAliasMode;
2159 PacketAliasCheckNewLink(void)
2161 return newDefaultLink;
2168 Code to support firewall punching. This shouldn't really be in this
2169 file, but making variables global is evil too.
2172 /* Firewall include files */
2173 #include <sys/queue.h>
2175 #include <netinet/ip_fw.h>
2179 static void ClearAllFWHoles(void);
2181 static int fireWallBaseNum; /* The first firewall entry free for our use */
2182 static int fireWallNumNums; /* How many entries can we use? */
2183 static int fireWallActiveNum; /* Which entry did we last use? */
2184 static char *fireWallField; /* bool array for entries */
2186 #define fw_setfield(field, num) \
2189 } /*lint -save -e717 */ while(0) /*lint -restore */
2190 #define fw_clrfield(field, num) \
2193 } /*lint -save -e717 */ while(0) /*lint -restore */
2194 #define fw_tstfield(field, num) ((field)[num])
2197 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2198 fireWallBaseNum = base;
2199 fireWallNumNums = num;
2204 fireWallField = malloc(fireWallNumNums);
2205 if (fireWallField) {
2206 memset(fireWallField, 0, fireWallNumNums);
2207 if (fireWallFD < 0) {
2208 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2211 fireWallActiveNum = fireWallBaseNum;
2216 UninitPunchFW(void) {
2218 if (fireWallFD >= 0)
2222 free(fireWallField);
2223 fireWallField = NULL;
2224 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2227 /* Make a certain link go through the firewall */
2229 PunchFWHole(struct alias_link *link) {
2230 int r; /* Result code */
2231 struct ip_fw rule; /* On-the-fly built rule */
2232 int fwhole; /* Where to punch hole */
2234 /* Don't do anything unless we are asked to */
2235 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2237 link->link_type != LINK_TCP ||
2241 memset(&rule, 0, sizeof rule);
2245 /* Find empty slot */
2246 for (fwhole = fireWallActiveNum;
2247 fwhole < fireWallBaseNum + fireWallNumNums &&
2248 fw_tstfield(fireWallField, fwhole);
2251 if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2252 fw_tstfield(fireWallField, fwhole)) {
2253 for (fwhole = fireWallBaseNum;
2254 fwhole < fireWallActiveNum &&
2255 fw_tstfield(fireWallField, fwhole);
2258 if (fwhole == fireWallActiveNum) {
2259 /* No rule point empty - we can't punch more holes. */
2260 fireWallActiveNum = fireWallBaseNum;
2262 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2267 /* Start next search at next position */
2268 fireWallActiveNum = fwhole+1;
2270 /* Build generic part of the two rules */
2271 rule.fw_number = fwhole;
2272 rule.fw_nports = 1; /* Number of source ports; dest ports follow */
2273 rule.fw_flg = IP_FW_F_ACCEPT;
2274 rule.fw_prot = IPPROTO_TCP;
2275 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2276 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2278 /* Build and apply specific part of the rules */
2279 rule.fw_src = GetOriginalAddress(link);
2280 rule.fw_dst = GetDestAddress(link);
2281 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2282 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2284 /* Skip non-bound links - XXX should not be strictly necessary,
2285 but seems to leave hole if not done. Leak of non-bound links?
2286 (Code should be left even if the problem is fixed - it is a
2287 clear optimization) */
2288 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2289 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2292 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2294 rule.fw_src = GetDestAddress(link);
2295 rule.fw_dst = GetOriginalAddress(link);
2296 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2297 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2298 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2301 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2304 /* Indicate hole applied */
2305 link->data.tcp->fwhole = fwhole;
2306 fw_setfield(fireWallField, fwhole);
2309 /* Remove a hole in a firewall associated with a particular alias
2310 link. Calling this too often is harmless. */
2312 ClearFWHole(struct alias_link *link) {
2313 if (link->link_type == LINK_TCP && link->data.tcp) {
2314 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2320 memset(&rule, 0, sizeof rule);
2321 rule.fw_number = fwhole;
2322 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2324 fw_clrfield(fireWallField, fwhole);
2325 link->data.tcp->fwhole = -1;
2329 /* Clear out the entire range dedicated to firewall holes. */
2331 ClearAllFWHoles(void) {
2332 struct ip_fw rule; /* On-the-fly built rule */
2338 memset(&rule, 0, sizeof rule);
2339 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2341 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2344 memset(fireWallField, 0, fireWallNumNums);