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, 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 /* Basic initialization */
863 link->src_addr = src_addr;
864 link->dst_addr = dst_addr;
865 link->alias_addr = alias_addr;
866 link->proxy_addr.s_addr = 0;
867 link->src_port = src_port;
868 link->dst_port = dst_port;
869 link->proxy_port = 0;
870 link->link_type = link_type;
873 link->timestamp = timeStamp;
875 /* Expiration time */
879 link->expire_time = ICMP_EXPIRE_TIME;
882 link->expire_time = UDP_EXPIRE_TIME;
885 link->expire_time = TCP_EXPIRE_INITIAL;
887 case LINK_FRAGMENT_ID:
888 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
890 case LINK_FRAGMENT_PTR:
891 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
895 /* Determine alias flags */
896 if (dst_addr.s_addr == 0)
897 link->flags |= LINK_UNKNOWN_DEST_ADDR;
899 link->flags |= LINK_UNKNOWN_DEST_PORT;
901 /* Determine alias port */
902 if (GetNewPort(link, alias_port_param) != 0)
908 /* Set up pointers for output lookup table */
909 start_point = StartPointOut(src_addr, dst_addr,
910 src_port, dst_port, link_type);
911 first_link = linkTableOut[start_point];
913 link->last_out = NULL;
914 link->next_out = first_link;
915 link->start_point_out = start_point;
917 if (first_link != NULL)
918 first_link->last_out = link;
920 linkTableOut[start_point] = link;
922 /* Set up pointers for input lookup table */
923 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
924 first_link = linkTableIn[start_point];
926 link->last_in = NULL;
927 link->next_in = first_link;
928 link->start_point_in = start_point;
930 if (first_link != NULL)
931 first_link->last_in = link;
933 linkTableIn[start_point] = link;
935 /* Link-type dependent initialization */
938 struct tcp_dat *aux_tcp;
947 aux_tcp = malloc(sizeof(struct tcp_dat));
948 link->data.tcp = aux_tcp;
954 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
955 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
956 aux_tcp->state.index = 0;
957 aux_tcp->state.ack_modified = 0;
958 for (i=0; i<N_LINK_TCP_DATA; i++)
959 aux_tcp->ack[i].active = 0;
960 aux_tcp->fwhole = -1;
965 fprintf(stderr, "PacketAlias/AddLink: ");
966 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
970 case LINK_FRAGMENT_ID:
971 fragmentIdLinkCount++;
973 case LINK_FRAGMENT_PTR:
974 fragmentPtrLinkCount++;
981 fprintf(stderr, "PacketAlias/AddLink(): ");
982 fprintf(stderr, "malloc() call failed.\n");
986 if (packetAliasMode & PKT_ALIAS_LOG)
994 static struct alias_link *
995 ReLink(struct alias_link *old_link,
996 struct in_addr src_addr,
997 struct in_addr dst_addr,
998 struct in_addr alias_addr,
1001 int alias_port_param, /* if less than zero, alias */
1002 int link_type) /* port will be automatically */
1003 { /* chosen. If greater than */
1004 struct alias_link *new_link; /* zero, equal to alias port */
1006 new_link = AddLink(src_addr, dst_addr, alias_addr,
1007 src_port, dst_port, alias_port_param,
1010 if (new_link != NULL &&
1011 old_link->link_type == LINK_TCP &&
1012 old_link->data.tcp &&
1013 old_link->data.tcp->fwhole > 0) {
1014 PunchFWHole(new_link);
1017 DeleteLink(old_link);
1021 static struct alias_link *
1022 _FindLinkOut(struct in_addr src_addr,
1023 struct in_addr dst_addr,
1027 int replace_partial_links)
1030 struct alias_link *link;
1032 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1033 link = linkTableOut[i];
1034 while (link != NULL)
1036 if (link->src_addr.s_addr == src_addr.s_addr
1037 && link->dst_addr.s_addr == dst_addr.s_addr
1038 && link->dst_port == dst_port
1039 && link->src_port == src_port
1040 && link->link_type == link_type)
1042 link->timestamp = timeStamp;
1045 link = link->next_out;
1048 /* Search for partially specified links. */
1053 link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1055 if (link != NULL && replace_partial_links)
1058 src_addr, dst_addr, link->alias_addr,
1059 src_port, dst_port, link->alias_port,
1063 else if (dst_addr.s_addr != 0)
1065 link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1073 static struct alias_link *
1074 FindLinkOut(struct in_addr src_addr,
1075 struct in_addr dst_addr,
1079 int replace_partial_links)
1081 struct alias_link *link;
1083 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1084 link_type, replace_partial_links);
1088 /* The following allows permanent links to be
1089 specified as using the default source address
1090 (i.e. device interface address) without knowing
1091 in advance what that address is. */
1092 if (aliasAddress.s_addr != 0 &&
1093 src_addr.s_addr == aliasAddress.s_addr)
1095 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1096 link_type, replace_partial_links);
1105 _FindLinkIn(struct in_addr dst_addr,
1106 struct in_addr alias_addr,
1110 int replace_partial_links)
1114 struct alias_link *link;
1115 struct alias_link *link_fully_specified;
1116 struct alias_link *link_unknown_all;
1117 struct alias_link *link_unknown_dst_addr;
1118 struct alias_link *link_unknown_dst_port;
1120 /* Initialize pointers */
1121 link_fully_specified = NULL;
1122 link_unknown_all = NULL;
1123 link_unknown_dst_addr = NULL;
1124 link_unknown_dst_port = NULL;
1126 /* If either the dest addr or port is unknown, the search
1127 loop will have to know about this. */
1130 if (dst_addr.s_addr == 0)
1131 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1133 flags_in |= LINK_UNKNOWN_DEST_PORT;
1136 start_point = StartPointIn(alias_addr, alias_port, link_type);
1137 link = linkTableIn[start_point];
1138 while (link != NULL)
1142 flags = flags_in | link->flags;
1143 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1145 if (link->alias_addr.s_addr == alias_addr.s_addr
1146 && link->alias_port == alias_port
1147 && link->dst_addr.s_addr == dst_addr.s_addr
1148 && link->dst_port == dst_port
1149 && link->link_type == link_type)
1151 link_fully_specified = link;
1155 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1156 && (flags & LINK_UNKNOWN_DEST_PORT))
1158 if (link->alias_addr.s_addr == alias_addr.s_addr
1159 && link->alias_port == alias_port
1160 && link->link_type == link_type)
1162 if (link_unknown_all == NULL)
1163 link_unknown_all = link;
1166 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1168 if (link->alias_addr.s_addr == alias_addr.s_addr
1169 && link->alias_port == alias_port
1170 && link->link_type == link_type
1171 && link->dst_port == dst_port)
1173 if (link_unknown_dst_addr == NULL)
1174 link_unknown_dst_addr = link;
1177 else if (flags & LINK_UNKNOWN_DEST_PORT)
1179 if (link->alias_addr.s_addr == alias_addr.s_addr
1180 && link->alias_port == alias_port
1181 && link->link_type == link_type
1182 && link->dst_addr.s_addr == dst_addr.s_addr)
1184 if (link_unknown_dst_port == NULL)
1185 link_unknown_dst_port = link;
1188 link = link->next_in;
1193 if (link_fully_specified != NULL)
1195 link_fully_specified->timestamp = timeStamp;
1196 return link_fully_specified;
1198 else if (link_unknown_dst_port != NULL)
1200 return replace_partial_links
1201 ? ReLink(link_unknown_dst_port,
1202 link_unknown_dst_port->src_addr, dst_addr, alias_addr,
1203 link_unknown_dst_port->src_port, dst_port, alias_port,
1205 : link_unknown_dst_port;
1207 else if (link_unknown_dst_addr != NULL)
1209 return replace_partial_links
1210 ? ReLink(link_unknown_dst_addr,
1211 link_unknown_dst_addr->src_addr, dst_addr, alias_addr,
1212 link_unknown_dst_addr->src_port, dst_port, alias_port,
1214 : link_unknown_dst_addr;
1216 else if (link_unknown_all != NULL)
1218 return replace_partial_links
1219 ? ReLink(link_unknown_all,
1220 link_unknown_all->src_addr, dst_addr, alias_addr,
1221 link_unknown_all->src_port, dst_port, alias_port,
1232 FindLinkIn(struct in_addr dst_addr,
1233 struct in_addr alias_addr,
1237 int replace_partial_links)
1239 struct alias_link *link;
1241 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1242 link_type, replace_partial_links);
1246 /* The following allows permanent links to be
1247 specified as using the default aliasing address
1248 (i.e. device interface address) without knowing
1249 in advance what that address is. */
1250 if (aliasAddress.s_addr != 0 &&
1251 alias_addr.s_addr == aliasAddress.s_addr)
1253 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1254 link_type, replace_partial_links);
1264 /* External routines for finding/adding links
1266 -- "external" means outside alias_db.c, but within alias*.c --
1268 FindIcmpIn(), FindIcmpOut()
1269 FindFragmentIn1(), FindFragmentIn2()
1270 AddFragmentPtrLink(), FindFragmentPtr()
1271 FindUdpTcpIn(), FindUdpTcpOut()
1272 FindOriginalAddress(), FindAliasAddress()
1274 (prototypes in alias_local.h)
1279 FindIcmpIn(struct in_addr dst_addr,
1280 struct in_addr alias_addr,
1283 return FindLinkIn(dst_addr, alias_addr,
1284 NO_DEST_PORT, id_alias,
1290 FindIcmpOut(struct in_addr src_addr,
1291 struct in_addr dst_addr,
1294 struct alias_link * link;
1296 link = FindLinkOut(src_addr, dst_addr,
1301 struct in_addr alias_addr;
1303 alias_addr = FindAliasAddress(src_addr);
1304 link = AddLink(src_addr, dst_addr, alias_addr,
1305 id, NO_DEST_PORT, GET_ALIAS_ID,
1314 FindFragmentIn1(struct in_addr dst_addr,
1315 struct in_addr alias_addr,
1318 struct alias_link *link;
1320 link = FindLinkIn(dst_addr, alias_addr,
1321 NO_DEST_PORT, ip_id,
1322 LINK_FRAGMENT_ID, 0);
1326 link = AddLink(nullAddress, dst_addr, alias_addr,
1327 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1336 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1337 struct in_addr alias_addr, /* is not found. */
1340 return FindLinkIn(dst_addr, alias_addr,
1341 NO_DEST_PORT, ip_id,
1342 LINK_FRAGMENT_ID, 0);
1347 AddFragmentPtrLink(struct in_addr dst_addr,
1350 return AddLink(nullAddress, dst_addr, nullAddress,
1351 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1357 FindFragmentPtr(struct in_addr dst_addr,
1360 return FindLinkIn(dst_addr, nullAddress,
1361 NO_DEST_PORT, ip_id,
1362 LINK_FRAGMENT_PTR, 0);
1367 FindUdpTcpIn(struct in_addr dst_addr,
1368 struct in_addr alias_addr,
1374 struct alias_link *link;
1379 link_type = LINK_UDP;
1382 link_type = LINK_TCP;
1389 link = FindLinkIn(dst_addr, alias_addr,
1390 dst_port, alias_port,
1393 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING)
1394 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)
1397 struct in_addr target_addr;
1399 target_addr = FindOriginalAddress(alias_addr);
1400 link = AddLink(target_addr, dst_addr, alias_addr,
1401 alias_port, dst_port, alias_port,
1410 FindUdpTcpOut(struct in_addr src_addr,
1411 struct in_addr dst_addr,
1417 struct alias_link *link;
1422 link_type = LINK_UDP;
1425 link_type = LINK_TCP;
1432 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1);
1436 struct in_addr alias_addr;
1438 alias_addr = FindAliasAddress(src_addr);
1439 link = AddLink(src_addr, dst_addr, alias_addr,
1440 src_port, dst_port, GET_ALIAS_PORT,
1449 FindOriginalAddress(struct in_addr alias_addr)
1451 struct alias_link *link;
1453 link = FindLinkIn(nullAddress, alias_addr,
1454 0, 0, LINK_ADDR, 0);
1458 if (targetAddress.s_addr != 0)
1459 return targetAddress;
1465 if (link->src_addr.s_addr == 0)
1466 return aliasAddress;
1468 return link->src_addr;
1474 FindAliasAddress(struct in_addr original_addr)
1476 struct alias_link *link;
1478 link = FindLinkOut(original_addr, nullAddress,
1479 0, 0, LINK_ADDR, 0);
1482 return aliasAddress;
1486 if (link->alias_addr.s_addr == 0)
1487 return aliasAddress;
1489 return link->alias_addr;
1494 /* External routines for getting or changing link data
1495 (external to alias_db.c, but internal to alias*.c)
1497 SetFragmentData(), GetFragmentData()
1498 SetFragmentPtr(), GetFragmentPtr()
1499 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1500 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1501 GetOriginalPort(), GetAliasPort()
1502 SetAckModified(), GetAckModified()
1503 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1508 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1510 link->data.frag_addr = src_addr;
1515 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1517 *src_addr = link->data.frag_addr;
1522 SetFragmentPtr(struct alias_link *link, char *fptr)
1524 link->data.frag_ptr = fptr;
1529 GetFragmentPtr(struct alias_link *link, char **fptr)
1531 *fptr = link->data.frag_ptr;
1536 SetStateIn(struct alias_link *link, int state)
1538 /* TCP input state */
1540 case ALIAS_TCP_STATE_DISCONNECTED:
1541 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) {
1542 link->expire_time = TCP_EXPIRE_DEAD;
1544 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1546 link->data.tcp->state.in = state;
1548 case ALIAS_TCP_STATE_CONNECTED:
1549 link->expire_time = TCP_EXPIRE_CONNECTED;
1551 case ALIAS_TCP_STATE_NOT_CONNECTED:
1552 link->data.tcp->state.in = state;
1561 SetStateOut(struct alias_link *link, int state)
1563 /* TCP output state */
1565 case ALIAS_TCP_STATE_DISCONNECTED:
1566 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) {
1567 link->expire_time = TCP_EXPIRE_DEAD;
1569 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1571 link->data.tcp->state.out = state;
1573 case ALIAS_TCP_STATE_CONNECTED:
1574 link->expire_time = TCP_EXPIRE_CONNECTED;
1576 case ALIAS_TCP_STATE_NOT_CONNECTED:
1577 link->data.tcp->state.out = state;
1586 GetStateIn(struct alias_link *link)
1588 /* TCP input state */
1589 return link->data.tcp->state.in;
1594 GetStateOut(struct alias_link *link)
1596 /* TCP output state */
1597 return link->data.tcp->state.out;
1602 GetOriginalAddress(struct alias_link *link)
1604 if (link->src_addr.s_addr == 0)
1605 return aliasAddress;
1607 return(link->src_addr);
1612 GetDestAddress(struct alias_link *link)
1614 return(link->dst_addr);
1619 GetAliasAddress(struct alias_link *link)
1621 if (link->alias_addr.s_addr == 0)
1622 return aliasAddress;
1624 return link->alias_addr;
1629 GetDefaultAliasAddress()
1631 return aliasAddress;
1636 SetDefaultAliasAddress(struct in_addr alias_addr)
1638 aliasAddress = alias_addr;
1643 GetOriginalPort(struct alias_link *link)
1645 return(link->src_port);
1650 GetAliasPort(struct alias_link *link)
1652 return(link->alias_port);
1656 GetDestPort(struct alias_link *link)
1658 return(link->dst_port);
1662 SetAckModified(struct alias_link *link)
1664 /* Indicate that ack numbers have been modified in a TCP connection */
1665 link->data.tcp->state.ack_modified = 1;
1670 GetProxyAddress(struct alias_link *link)
1672 return link->proxy_addr;
1677 SetProxyAddress(struct alias_link *link, struct in_addr addr)
1679 link->proxy_addr = addr;
1684 GetProxyPort(struct alias_link *link)
1686 return link->proxy_port;
1691 SetProxyPort(struct alias_link *link, u_short port)
1693 link->proxy_port = port;
1698 GetAckModified(struct alias_link *link)
1700 /* See if ack numbers have been modified */
1701 return link->data.tcp->state.ack_modified;
1706 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1709 Find out how much the ack number has been altered for an incoming
1710 TCP packet. To do this, a circular list is ack numbers where the TCP
1711 packet size was altered is searched.
1716 int delta, ack_diff_min;
1719 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1724 for (i=0; i<N_LINK_TCP_DATA; i++)
1726 struct ack_data_record x;
1728 x = link->data.tcp->ack[i];
1733 ack_diff = SeqDiff(x.ack_new, ack);
1736 if (ack_diff_min >= 0)
1738 if (ack_diff < ack_diff_min)
1741 ack_diff_min = ack_diff;
1747 ack_diff_min = ack_diff;
1757 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1760 Find out how much the seq number has been altered for an outgoing
1761 TCP packet. To do this, a circular list is ack numbers where the TCP
1762 packet size was altered is searched.
1767 int delta, seq_diff_min;
1770 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1775 for (i=0; i<N_LINK_TCP_DATA; i++)
1777 struct ack_data_record x;
1779 x = link->data.tcp->ack[i];
1784 seq_diff = SeqDiff(x.ack_old, seq);
1787 if (seq_diff_min >= 0)
1789 if (seq_diff < seq_diff_min)
1792 seq_diff_min = seq_diff;
1798 seq_diff_min = seq_diff;
1808 AddSeq(struct ip *pip, struct alias_link *link, int delta)
1811 When a TCP packet has been altered in length, save this
1812 information in a circular list. If enough packets have
1813 been altered, then this list will begin to overwrite itself.
1817 struct ack_data_record x;
1818 int hlen, tlen, dlen;
1821 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1823 hlen = (pip->ip_hl + tc->th_off) << 2;
1824 tlen = ntohs(pip->ip_len);
1827 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1828 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1832 i = link->data.tcp->state.index;
1833 link->data.tcp->ack[i] = x;
1836 if (i == N_LINK_TCP_DATA)
1837 link->data.tcp->state.index = 0;
1839 link->data.tcp->state.index = i;
1843 SetExpire(struct alias_link *link, int expire)
1847 link->flags &= ~LINK_PERMANENT;
1850 else if (expire == -1)
1852 link->flags |= LINK_PERMANENT;
1854 else if (expire > 0)
1856 link->expire_time = expire;
1861 fprintf(stderr, "PacketAlias/SetExpire(): ");
1862 fprintf(stderr, "error in expire parameter\n");
1868 ClearCheckNewLink(void)
1874 /* Miscellaneous Functions
1877 InitPacketAliasLog()
1878 UninitPacketAliasLog()
1882 Whenever an outgoing or incoming packet is handled, HouseKeeping()
1883 is called to find and remove timed-out aliasing links. Logic exists
1884 to sweep through the entire table and linked list structure
1887 (prototype in alias_local.h)
1898 * Save system time (seconds) in global variable timeStamp for
1899 * use by other functions. This is done so as not to unnecessarily
1900 * waste timeline by making system calls.
1902 gettimeofday(&tv, &tz);
1903 timeStamp = tv.tv_sec;
1905 /* Compute number of spokes (output table link chains) to cover */
1906 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1907 n100 *= timeStamp - lastCleanupTime;
1908 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1912 /* Handle different cases */
1913 if (n > ALIAS_CLEANUP_MAX_SPOKES)
1915 n = ALIAS_CLEANUP_MAX_SPOKES;
1916 lastCleanupTime = timeStamp;
1917 houseKeepingResidual = 0;
1920 IncrementalCleanup();
1924 lastCleanupTime = timeStamp;
1925 houseKeepingResidual = n100 - 100*n;
1928 IncrementalCleanup();
1933 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1934 fprintf(stderr, "something unexpected in time values\n");
1936 lastCleanupTime = timeStamp;
1937 houseKeepingResidual = 0;
1942 /* Init the log file and enable logging */
1944 InitPacketAliasLog(void)
1946 if ((~packetAliasMode & PKT_ALIAS_LOG)
1947 && (monitorFile = fopen("/var/log/alias.log", "w")))
1949 packetAliasMode |= PKT_ALIAS_LOG;
1950 fprintf(monitorFile,
1951 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1956 /* Close the log-file and disable logging. */
1958 UninitPacketAliasLog(void)
1961 fclose(monitorFile);
1964 packetAliasMode &= ~PKT_ALIAS_LOG;
1972 /* Outside world interfaces
1974 -- "outside world" means other than alias*.c routines --
1976 PacketAliasRedirectPort()
1977 PacketAliasRedirectAddr()
1978 PacketAliasRedirectDelete()
1979 PacketAliasSetAddress()
1982 PacketAliasSetMode()
1984 (prototypes in alias.h)
1987 /* Redirection from a specific public addr:port to a
1988 a private addr:port */
1990 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
1991 struct in_addr dst_addr, u_short dst_port,
1992 struct in_addr alias_addr, u_short alias_port,
1996 struct alias_link *link;
2001 link_type = LINK_UDP;
2004 link_type = LINK_TCP;
2008 fprintf(stderr, "PacketAliasRedirectPort(): ");
2009 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2014 link = AddLink(src_addr, dst_addr, alias_addr,
2015 src_port, dst_port, alias_port,
2020 link->flags |= LINK_PERMANENT;
2025 fprintf(stderr, "PacketAliasRedirectPort(): "
2026 "call to AddLink() failed\n");
2033 /* Translate PPTP packets to a machine on the inside
2036 PacketAliasPptp(struct in_addr src_addr)
2039 pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */
2040 pptpAliasFlag = src_addr.s_addr != INADDR_NONE;
2045 int GetPptpAlias (struct in_addr* alias_addr)
2048 *alias_addr = pptpAliasAddr;
2050 return pptpAliasFlag;
2053 /* Static address translation */
2055 PacketAliasRedirectAddr(struct in_addr src_addr,
2056 struct in_addr alias_addr)
2058 struct alias_link *link;
2060 link = AddLink(src_addr, nullAddress, alias_addr,
2066 link->flags |= LINK_PERMANENT;
2071 fprintf(stderr, "PacketAliasRedirectAddr(): "
2072 "call to AddLink() failed\n");
2081 PacketAliasRedirectDelete(struct alias_link *link)
2083 /* This is a dangerous function to put in the API,
2084 because an invalid pointer can crash the program. */
2093 PacketAliasSetAddress(struct in_addr addr)
2095 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2096 && aliasAddress.s_addr != addr.s_addr)
2099 aliasAddress = addr;
2104 PacketAliasSetTarget(struct in_addr target_addr)
2106 targetAddress = target_addr;
2111 PacketAliasInit(void)
2116 static int firstCall = 1;
2120 gettimeofday(&tv, &tz);
2121 timeStamp = tv.tv_sec;
2122 lastCleanupTime = tv.tv_sec;
2123 houseKeepingResidual = 0;
2125 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2126 linkTableOut[i] = NULL;
2127 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2128 linkTableIn[i] = NULL;
2130 atexit(PacketAliasUninit);
2140 aliasAddress.s_addr = 0;
2141 targetAddress.s_addr = 0;
2146 fragmentIdLinkCount = 0;
2147 fragmentPtrLinkCount = 0;
2152 packetAliasMode = PKT_ALIAS_SAME_PORTS
2153 | PKT_ALIAS_USE_SOCKETS
2154 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2160 PacketAliasUninit(void) {
2164 UninitPacketAliasLog();
2171 /* Change mode for some operations */
2174 unsigned int flags, /* Which state to bring flags to */
2175 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2176 probe for flag values) */
2179 /* Enable logging? */
2180 if (flags & mask & PKT_ALIAS_LOG)
2182 InitPacketAliasLog(); /* Do the enable */
2184 /* _Disable_ logging? */
2185 if (~flags & mask & PKT_ALIAS_LOG) {
2186 UninitPacketAliasLog();
2190 /* Start punching holes in the firewall? */
2191 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2194 /* Stop punching holes in the firewall? */
2195 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2200 /* Other flags can be set/cleared without special action */
2201 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2202 return packetAliasMode;
2207 PacketAliasCheckNewLink(void)
2209 return newDefaultLink;
2216 Code to support firewall punching. This shouldn't really be in this
2217 file, but making variables global is evil too.
2220 /* Firewall include files */
2221 #include <sys/queue.h>
2223 #include <netinet/ip_fw.h>
2227 static void ClearAllFWHoles(void);
2229 static int fireWallBaseNum; /* The first firewall entry free for our use */
2230 static int fireWallNumNums; /* How many entries can we use? */
2231 static int fireWallActiveNum; /* Which entry did we last use? */
2232 static char *fireWallField; /* bool array for entries */
2234 #define fw_setfield(field, num) \
2237 } /*lint -save -e717 */ while(0) /*lint -restore */
2238 #define fw_clrfield(field, num) \
2241 } /*lint -save -e717 */ while(0) /*lint -restore */
2242 #define fw_tstfield(field, num) ((field)[num])
2245 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2246 fireWallBaseNum = base;
2247 fireWallNumNums = num;
2252 fireWallField = malloc(fireWallNumNums);
2253 if (fireWallField) {
2254 memset(fireWallField, 0, fireWallNumNums);
2255 if (fireWallFD < 0) {
2256 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2259 fireWallActiveNum = fireWallBaseNum;
2264 UninitPunchFW(void) {
2266 if (fireWallFD >= 0)
2270 free(fireWallField);
2271 fireWallField = NULL;
2272 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2275 /* Make a certain link go through the firewall */
2277 PunchFWHole(struct alias_link *link) {
2278 int r; /* Result code */
2279 struct ip_fw rule; /* On-the-fly built rule */
2280 int fwhole; /* Where to punch hole */
2282 /* Don't do anything unless we are asked to */
2283 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2285 link->link_type != LINK_TCP ||
2289 memset(&rule, 0, sizeof rule);
2293 /* Find empty slot */
2294 for (fwhole = fireWallActiveNum;
2295 fwhole < fireWallBaseNum + fireWallNumNums &&
2296 fw_tstfield(fireWallField, fwhole);
2299 if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2300 fw_tstfield(fireWallField, fwhole)) {
2301 for (fwhole = fireWallBaseNum;
2302 fwhole < fireWallActiveNum &&
2303 fw_tstfield(fireWallField, fwhole);
2306 if (fwhole == fireWallActiveNum) {
2307 /* No rule point empty - we can't punch more holes. */
2308 fireWallActiveNum = fireWallBaseNum;
2310 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2315 /* Start next search at next position */
2316 fireWallActiveNum = fwhole+1;
2318 /* Build generic part of the two rules */
2319 rule.fw_number = fwhole;
2320 rule.fw_nports = 1; /* Number of source ports; dest ports follow */
2321 rule.fw_flg = IP_FW_F_ACCEPT;
2322 rule.fw_prot = IPPROTO_TCP;
2323 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2324 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2326 /* Build and apply specific part of the rules */
2327 rule.fw_src = GetOriginalAddress(link);
2328 rule.fw_dst = GetDestAddress(link);
2329 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2330 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2332 /* Skip non-bound links - XXX should not be strictly necessary,
2333 but seems to leave hole if not done. Leak of non-bound links?
2334 (Code should be left even if the problem is fixed - it is a
2335 clear optimization) */
2336 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2337 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2340 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2342 rule.fw_src = GetDestAddress(link);
2343 rule.fw_dst = GetOriginalAddress(link);
2344 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2345 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2346 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2349 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2352 /* Indicate hole applied */
2353 link->data.tcp->fwhole = fwhole;
2354 fw_setfield(fireWallField, fwhole);
2357 /* Remove a hole in a firewall associated with a particular alias
2358 link. Calling this too often is harmless. */
2360 ClearFWHole(struct alias_link *link) {
2361 if (link->link_type == LINK_TCP && link->data.tcp) {
2362 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2368 memset(&rule, 0, sizeof rule);
2369 rule.fw_number = fwhole;
2370 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2372 fw_clrfield(fireWallField, fwhole);
2373 link->data.tcp->fwhole = -1;
2377 /* Clear out the entire range dedicated to firewall holes. */
2379 ClearAllFWHoles(void) {
2380 struct ip_fw rule; /* On-the-fly built rule */
2386 memset(&rule, 0, sizeof rule);
2387 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2389 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2392 memset(fireWallField, 0, fireWallNumNums);