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 number. */
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 struct in_addr proxy_addr;
248 int link_type; /* Type of link: tcp, udp, icmp, frag */
250 /* values for link_type */
254 #define LINK_FRAGMENT_ID 4
255 #define LINK_FRAGMENT_PTR 5
258 int flags; /* indicates special characteristics */
261 #define LINK_UNKNOWN_DEST_PORT 0x01
262 #define LINK_UNKNOWN_DEST_ADDR 0x02
263 #define LINK_PERMANENT 0x04
264 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
265 #define LINK_UNFIREWALLED 0x08
267 int timestamp; /* Time link was last accessed */
268 int expire_time; /* Expire time for link */
270 int sockfd; /* socket descriptor */
272 u_int start_point_out; /* Index number in output lookup table */
273 u_int start_point_in;
274 struct alias_link *next_out; /* Linked list pointers for input and */
275 struct alias_link *last_out; /* output tables */
276 struct alias_link *next_in; /* . */
277 struct alias_link *last_in; /* . */
279 union /* Auxiliary data */
282 struct in_addr frag_addr;
293 The global variables listed here are only accessed from
294 within alias_db.c and so are prefixed with the static
298 int packetAliasMode; /* Mode flags */
299 /* - documented in alias.h */
301 static struct in_addr aliasAddress; /* Address written onto source */
302 /* field of IP packet. */
304 static struct in_addr targetAddress; /* IP address incoming packets */
305 /* are sent to if no aliasing */
306 /* link already exists */
308 static struct in_addr nullAddress; /* Used as a dummy parameter for */
309 /* some function calls */
310 static struct alias_link *
311 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */
312 /* chains of link records. Each */
313 static struct alias_link * /* link record is doubly indexed */
314 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */
317 static int icmpLinkCount; /* Link statistics */
318 static int udpLinkCount;
319 static int tcpLinkCount;
320 static int fragmentIdLinkCount;
321 static int fragmentPtrLinkCount;
322 static int sockCount;
324 static int cleanupIndex; /* Index to chain of link table */
325 /* being inspected for old links */
327 static int timeStamp; /* System time in seconds for */
330 static int lastCleanupTime; /* Last time IncrementalCleanup() */
333 static int houseKeepingResidual; /* used by HouseKeeping() */
335 static int deleteAllLinks; /* If equal to zero, DeleteLink() */
336 /* will not remove permanent links */
338 static FILE *monitorFile; /* File descriptor for link */
339 /* statistics monitoring file */
341 static int newDefaultLink; /* Indicates if a new aliasing */
342 /* link has been created after a */
343 /* call to PacketAliasIn/Out(). */
346 static int fireWallFD = -1; /* File descriptor to be able to */
347 /* control firewall. Opened by */
348 /* PacketAliasSetMode on first */
349 /* setting the PKT_ALIAS_PUNCH_FW */
353 static int pptpAliasFlag; /* Indicates if PPTP aliasing is */
355 static struct in_addr pptpAliasAddr; /* Address of source of PPTP */
364 /* Internal utility routines (used only in alias_db.c)
366 Lookup table starting points:
367 StartPointIn() -- link table initial search point for
369 StartPointOut() -- port table initial search point for
373 SeqDiff() -- difference between two TCP sequences
374 ShowAliasStats() -- send alias statistics to a monitor file
378 /* Local prototypes */
379 static u_int StartPointIn(struct in_addr, u_short, int);
381 static u_int StartPointOut(struct in_addr, struct in_addr,
382 u_short, u_short, int);
384 static int SeqDiff(u_long, u_long);
386 static void ShowAliasStats(void);
389 /* Firewall control */
390 static void InitPunchFW(void);
391 static void UninitPunchFW(void);
392 static void ClearFWHole(struct alias_link *link);
395 /* Log file control */
396 static void InitPacketAliasLog(void);
397 static void UninitPacketAliasLog(void);
400 StartPointIn(struct in_addr alias_addr,
406 n = alias_addr.s_addr;
409 return(n % LINK_TABLE_IN_SIZE);
414 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
415 u_short src_port, u_short dst_port, int link_type)
420 n += dst_addr.s_addr;
425 return(n % LINK_TABLE_OUT_SIZE);
430 SeqDiff(u_long x, u_long y)
432 /* Return the difference between two TCP sequence numbers */
435 This function is encapsulated in case there are any unusual
436 arithmetic conditions that need to be considered.
439 return (ntohl(y) - ntohl(x));
446 /* Used for debugging */
450 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d",
455 fragmentPtrLinkCount);
457 fprintf(monitorFile, " / tot=%d (sock=%d)\n",
458 icmpLinkCount + udpLinkCount
460 + fragmentIdLinkCount
461 + fragmentPtrLinkCount,
472 /* Internal routines for finding, deleting and adding links
475 GetNewPort() -- find and reserve new alias port number
476 GetSocket() -- try to allocate a socket for a given port
478 Link creation and deletion:
479 CleanupAliasData() - remove all link chains from lookup table
480 IncrementalCleanup() - look for stale links in a single chain
481 DeleteLink() - remove link
483 ReLink() - change link
486 FindLinkOut() - find link for outgoing packets
487 FindLinkIn() - find link for incoming packets
490 /* Local prototypes */
491 static int GetNewPort(struct alias_link *, int);
493 static u_short GetSocket(u_short, int *, int);
495 static void CleanupAliasData(void);
497 static void IncrementalCleanup(void);
499 static void DeleteLink(struct alias_link *);
501 static struct alias_link *
502 AddLink(struct in_addr, struct in_addr, struct in_addr,
503 u_short, u_short, int, int);
505 static struct alias_link *
506 ReLink(struct alias_link *,
507 struct in_addr, struct in_addr, struct in_addr,
508 u_short, u_short, int, int);
510 static struct alias_link *
511 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int);
513 static struct alias_link *
514 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
517 #define ALIAS_PORT_BASE 0x08000
518 #define ALIAS_PORT_MASK 0x07fff
519 #define GET_NEW_PORT_MAX_ATTEMPTS 20
521 #define GET_ALIAS_PORT -1
522 #define GET_ALIAS_ID GET_ALIAS_PORT
524 /* GetNewPort() allocates port numbers. Note that if a port number
525 is already in use, that does not mean that it cannot be used by
526 another link concurrently. This is because GetNewPort() looks for
527 unused triplets: (dest addr, dest port, alias port). */
530 GetNewPort(struct alias_link *link, int alias_port_param)
538 Description of alias_port_param for GetNewPort(). When
539 this parameter is zero or positive, it precisely specifies
540 the port number. GetNewPort() will return this number
541 without check that it is in use.
543 Whis this parameter is -1, it indicates to get a randomly
544 selected port number.
547 if (alias_port_param == GET_ALIAS_PORT)
550 * The aliasing port is automatically selected
551 * by one of two methods below:
553 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
555 if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
558 * When the ALIAS_SAME_PORTS option is
559 * chosen, the first try will be the
560 * actual source port. If this is already
561 * in use, the remainder of the trials
564 port_net = link->src_port;
565 port_sys = ntohs(port_net);
569 /* First trial and all subsequent are random. */
570 port_sys = random() & ALIAS_PORT_MASK;
571 port_sys += ALIAS_PORT_BASE;
572 port_net = htons(port_sys);
575 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
577 link->alias_port = (u_short) alias_port_param;
583 fprintf(stderr, "PacketAlias/GetNewPort(): ");
584 fprintf(stderr, "input parameter error\n");
590 /* Port number search */
591 for (i=0; i<max_trials; i++)
594 struct alias_link *search_result;
596 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
597 link->dst_port, port_net,
600 if (search_result == NULL)
602 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
603 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
610 if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS)
611 && (link->flags & LINK_PARTIALLY_SPECIFIED))
613 if (GetSocket(port_net, &link->sockfd, link->link_type))
615 link->alias_port = port_net;
621 link->alias_port = port_net;
626 port_sys = random() & ALIAS_PORT_MASK;
627 port_sys += ALIAS_PORT_BASE;
628 port_net = htons(port_sys);
632 fprintf(stderr, "PacketAlias/GetnewPort(): ");
633 fprintf(stderr, "could not find free port\n");
641 GetSocket(u_short port_net, int *sockfd, int link_type)
645 struct sockaddr_in sock_addr;
647 if (link_type == LINK_TCP)
648 sock = socket(AF_INET, SOCK_STREAM, 0);
649 else if (link_type == LINK_UDP)
650 sock = socket(AF_INET, SOCK_DGRAM, 0);
654 fprintf(stderr, "PacketAlias/GetSocket(): ");
655 fprintf(stderr, "incorrect link type\n");
663 fprintf(stderr, "PacketAlias/GetSocket(): ");
664 fprintf(stderr, "socket() error %d\n", *sockfd);
669 sock_addr.sin_family = AF_INET;
670 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
671 sock_addr.sin_port = port_net;
674 (struct sockaddr *) &sock_addr,
691 CleanupAliasData(void)
693 struct alias_link *link;
697 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
699 link = linkTableOut[i];
702 struct alias_link *link_next;
703 link_next = link->next_out;
715 IncrementalCleanup(void)
718 struct alias_link *link;
721 link = linkTableOut[cleanupIndex++];
725 struct alias_link *link_next;
727 link_next = link->next_out;
728 idelta = timeStamp - link->timestamp;
729 switch (link->link_type)
733 case LINK_FRAGMENT_ID:
734 case LINK_FRAGMENT_PTR:
735 if (idelta > link->expire_time)
742 if (idelta > link->expire_time)
744 struct tcp_dat *tcp_aux;
746 tcp_aux = link->data.tcp;
747 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
748 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
759 if (cleanupIndex == LINK_TABLE_OUT_SIZE)
764 DeleteLink(struct alias_link *link)
766 struct alias_link *link_last;
767 struct alias_link *link_next;
769 /* Don't do anything if the link is marked permanent */
770 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
774 /* Delete associatied firewall hole, if any */
778 /* Adjust output table pointers */
779 link_last = link->last_out;
780 link_next = link->next_out;
782 if (link_last != NULL)
783 link_last->next_out = link_next;
785 linkTableOut[link->start_point_out] = link_next;
787 if (link_next != NULL)
788 link_next->last_out = link_last;
790 /* Adjust input table pointers */
791 link_last = link->last_in;
792 link_next = link->next_in;
794 if (link_last != NULL)
795 link_last->next_in = link_next;
797 linkTableIn[link->start_point_in] = link_next;
799 if (link_next != NULL)
800 link_next->last_in = link_last;
802 /* Close socket, if one has been allocated */
803 if (link->sockfd != -1)
809 /* Link-type dependent cleanup */
810 switch(link->link_type)
820 if (link->data.tcp != NULL)
821 free(link->data.tcp);
823 case LINK_FRAGMENT_ID:
824 fragmentIdLinkCount--;
826 case LINK_FRAGMENT_PTR:
827 fragmentPtrLinkCount--;
828 if (link->data.frag_ptr != NULL)
829 free(link->data.frag_ptr);
836 /* Write statistics, if logging enabled */
837 if (packetAliasMode & PKT_ALIAS_LOG)
844 static struct alias_link *
845 AddLink(struct in_addr src_addr,
846 struct in_addr dst_addr,
847 struct in_addr alias_addr,
850 int alias_port_param, /* if less than zero, alias */
851 int link_type) /* port will be automatically */
852 { /* chosen. If greater than */
853 u_int start_point; /* zero, equal to alias port */
854 struct alias_link *link;
855 struct alias_link *first_link;
857 link = malloc(sizeof(struct alias_link));
860 /* If either the aliasing address or source address are
861 equal to the default device address (equal to the
862 global variable aliasAddress), then set the alias
863 address field of the link record to zero */
865 if (src_addr.s_addr == aliasAddress.s_addr)
868 if (alias_addr.s_addr == aliasAddress.s_addr)
869 alias_addr.s_addr = 0;
871 /* Basic initialization */
872 link->src_addr = src_addr;
873 link->dst_addr = dst_addr;
874 link->alias_addr = alias_addr;
875 link->proxy_addr.s_addr = 0;
876 link->src_port = src_port;
877 link->dst_port = dst_port;
878 link->proxy_port = 0;
879 link->link_type = link_type;
882 link->timestamp = timeStamp;
884 /* Expiration time */
888 link->expire_time = ICMP_EXPIRE_TIME;
891 link->expire_time = UDP_EXPIRE_TIME;
894 link->expire_time = TCP_EXPIRE_INITIAL;
896 case LINK_FRAGMENT_ID:
897 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
899 case LINK_FRAGMENT_PTR:
900 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
904 /* Determine alias flags */
905 if (dst_addr.s_addr == 0)
906 link->flags |= LINK_UNKNOWN_DEST_ADDR;
908 link->flags |= LINK_UNKNOWN_DEST_PORT;
910 /* Determine alias port */
911 if (GetNewPort(link, alias_port_param) != 0)
917 /* Set up pointers for output lookup table */
918 start_point = StartPointOut(src_addr, dst_addr,
919 src_port, dst_port, link_type);
920 first_link = linkTableOut[start_point];
922 link->last_out = NULL;
923 link->next_out = first_link;
924 link->start_point_out = start_point;
926 if (first_link != NULL)
927 first_link->last_out = link;
929 linkTableOut[start_point] = link;
931 /* Set up pointers for input lookup table */
932 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
933 first_link = linkTableIn[start_point];
935 link->last_in = NULL;
936 link->next_in = first_link;
937 link->start_point_in = start_point;
939 if (first_link != NULL)
940 first_link->last_in = link;
942 linkTableIn[start_point] = link;
944 /* Link-type dependent initialization */
947 struct tcp_dat *aux_tcp;
956 aux_tcp = malloc(sizeof(struct tcp_dat));
957 link->data.tcp = aux_tcp;
963 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
964 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
965 aux_tcp->state.index = 0;
966 aux_tcp->state.ack_modified = 0;
967 for (i=0; i<N_LINK_TCP_DATA; i++)
968 aux_tcp->ack[i].active = 0;
969 aux_tcp->fwhole = -1;
974 fprintf(stderr, "PacketAlias/AddLink: ");
975 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
979 case LINK_FRAGMENT_ID:
980 fragmentIdLinkCount++;
982 case LINK_FRAGMENT_PTR:
983 fragmentPtrLinkCount++;
990 fprintf(stderr, "PacketAlias/AddLink(): ");
991 fprintf(stderr, "malloc() call failed.\n");
995 if (packetAliasMode & PKT_ALIAS_LOG)
1003 static struct alias_link *
1004 ReLink(struct alias_link *old_link,
1005 struct in_addr src_addr,
1006 struct in_addr dst_addr,
1007 struct in_addr alias_addr,
1010 int alias_port_param, /* if less than zero, alias */
1011 int link_type) /* port will be automatically */
1012 { /* chosen. If greater than */
1013 struct alias_link *new_link; /* zero, equal to alias port */
1015 new_link = AddLink(src_addr, dst_addr, alias_addr,
1016 src_port, dst_port, alias_port_param,
1019 if (new_link != NULL &&
1020 old_link->link_type == LINK_TCP &&
1021 old_link->data.tcp &&
1022 old_link->data.tcp->fwhole > 0) {
1023 PunchFWHole(new_link);
1026 DeleteLink(old_link);
1030 static struct alias_link *
1031 FindLinkOut(struct in_addr src_addr,
1032 struct in_addr dst_addr,
1038 struct alias_link *link;
1040 if (src_addr.s_addr == aliasAddress.s_addr)
1041 src_addr.s_addr = 0;
1043 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1044 link = linkTableOut[i];
1045 while (link != NULL)
1047 if (link->src_addr.s_addr == src_addr.s_addr
1048 && link->dst_addr.s_addr == dst_addr.s_addr
1049 && link->dst_port == dst_port
1050 && link->src_port == src_port
1051 && link->link_type == link_type)
1053 link->timestamp = timeStamp;
1056 link = link->next_out;
1064 FindLinkIn(struct in_addr dst_addr,
1065 struct in_addr alias_addr,
1069 int replace_partial_links)
1073 struct alias_link *link;
1074 struct alias_link *link_fully_specified;
1075 struct alias_link *link_unknown_all;
1076 struct alias_link *link_unknown_dst_addr;
1077 struct alias_link *link_unknown_dst_port;
1079 /* Initialize pointers */
1080 link_fully_specified = NULL;
1081 link_unknown_all = NULL;
1082 link_unknown_dst_addr = NULL;
1083 link_unknown_dst_port = NULL;
1085 /* If either the dest addr or port is unknown, the search
1086 loop will have to know about this. */
1089 if (dst_addr.s_addr == 0)
1090 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1092 flags_in |= LINK_UNKNOWN_DEST_PORT;
1094 /* The following allows permanent links to be
1095 be specified as using the default aliasing address
1096 (i.e. device interface address) without knowing
1097 in advance what that address is. */
1099 if (alias_addr.s_addr == aliasAddress.s_addr)
1100 alias_addr.s_addr = 0;
1103 start_point = StartPointIn(alias_addr, alias_port, link_type);
1104 link = linkTableIn[start_point];
1105 while (link != NULL)
1109 flags = flags_in | link->flags;
1110 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1112 if (link->alias_addr.s_addr == alias_addr.s_addr
1113 && link->alias_port == alias_port
1114 && link->dst_addr.s_addr == dst_addr.s_addr
1115 && link->dst_port == dst_port
1116 && link->link_type == link_type)
1118 link_fully_specified = link;
1122 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1123 && (flags & LINK_UNKNOWN_DEST_PORT))
1125 if (link->alias_addr.s_addr == alias_addr.s_addr
1126 && link->alias_port == alias_port
1127 && link->link_type == link_type)
1129 if (link_unknown_all == NULL)
1130 link_unknown_all = link;
1133 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1135 if (link->alias_addr.s_addr == alias_addr.s_addr
1136 && link->alias_port == alias_port
1137 && link->link_type == link_type
1138 && link->dst_port == dst_port)
1140 if (link_unknown_dst_addr == NULL)
1141 link_unknown_dst_addr = link;
1144 else if (flags & LINK_UNKNOWN_DEST_PORT)
1146 if (link->alias_addr.s_addr == alias_addr.s_addr
1147 && link->alias_port == alias_port
1148 && link->link_type == link_type
1149 && link->dst_addr.s_addr == dst_addr.s_addr)
1151 if (link_unknown_dst_port == NULL)
1152 link_unknown_dst_port = link;
1155 link = link->next_in;
1160 if (link_fully_specified != NULL)
1162 return link_fully_specified;
1164 else if (link_unknown_dst_port != NULL)
1166 return replace_partial_links
1167 ? ReLink(link_unknown_dst_port,
1168 link_unknown_dst_port->src_addr, dst_addr, alias_addr,
1169 link_unknown_dst_port->src_port, dst_port, alias_port,
1171 : link_unknown_dst_port;
1173 else if (link_unknown_dst_addr != NULL)
1175 return replace_partial_links
1176 ? ReLink(link_unknown_dst_addr,
1177 link_unknown_dst_addr->src_addr, dst_addr, alias_addr,
1178 link_unknown_dst_addr->src_port, dst_port, alias_port,
1180 : link_unknown_dst_addr;
1182 else if (link_unknown_all != NULL)
1184 return replace_partial_links
1185 ? ReLink(link_unknown_all,
1186 link_unknown_all->src_addr, dst_addr, alias_addr,
1187 link_unknown_all->src_port, dst_port, alias_port,
1200 /* External routines for finding/adding links
1202 -- "external" means outside alias_db.c, but within alias*.c --
1204 FindIcmpIn(), FindIcmpOut()
1205 FindFragmentIn1(), FindFragmentIn2()
1206 AddFragmentPtrLink(), FindFragmentPtr()
1207 FindUdpTcpIn(), FindUdpTcpOut()
1208 FindOriginalAddress(), FindAliasAddress()
1210 (prototypes in alias_local.h)
1215 FindIcmpIn(struct in_addr dst_addr,
1216 struct in_addr alias_addr,
1219 return FindLinkIn(dst_addr, alias_addr,
1220 NO_DEST_PORT, id_alias,
1226 FindIcmpOut(struct in_addr src_addr,
1227 struct in_addr dst_addr,
1230 struct alias_link * link;
1232 link = FindLinkOut(src_addr, dst_addr,
1237 struct in_addr alias_addr;
1239 alias_addr = FindAliasAddress(src_addr);
1240 link = AddLink(src_addr, dst_addr, alias_addr,
1241 id, NO_DEST_PORT, GET_ALIAS_ID,
1250 FindFragmentIn1(struct in_addr dst_addr,
1251 struct in_addr alias_addr,
1254 struct alias_link *link;
1256 link = FindLinkIn(dst_addr, alias_addr,
1257 NO_DEST_PORT, ip_id,
1258 LINK_FRAGMENT_ID, 0);
1262 link = AddLink(nullAddress, dst_addr, alias_addr,
1263 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1272 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1273 struct in_addr alias_addr, /* is not found. */
1276 return FindLinkIn(dst_addr, alias_addr,
1277 NO_DEST_PORT, ip_id,
1278 LINK_FRAGMENT_ID, 0);
1283 AddFragmentPtrLink(struct in_addr dst_addr,
1286 return AddLink(nullAddress, dst_addr, nullAddress,
1287 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1293 FindFragmentPtr(struct in_addr dst_addr,
1296 return FindLinkIn(dst_addr, nullAddress,
1297 NO_DEST_PORT, ip_id,
1298 LINK_FRAGMENT_PTR, 0);
1303 FindUdpTcpIn(struct in_addr dst_addr,
1304 struct in_addr alias_addr,
1310 struct alias_link *link;
1315 link_type = LINK_UDP;
1318 link_type = LINK_TCP;
1325 link = FindLinkIn(dst_addr, alias_addr,
1326 dst_port, alias_port,
1329 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING)
1330 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)
1333 struct in_addr target_addr;
1335 target_addr = FindOriginalAddress(alias_addr);
1336 link = AddLink(target_addr, dst_addr, alias_addr,
1337 alias_port, dst_port, alias_port,
1346 FindUdpTcpOut(struct in_addr src_addr,
1347 struct in_addr dst_addr,
1353 struct alias_link *link;
1358 link_type = LINK_UDP;
1361 link_type = LINK_TCP;
1368 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type);
1372 struct in_addr alias_addr;
1374 alias_addr = FindAliasAddress(src_addr);
1375 link = AddLink(src_addr, dst_addr, alias_addr,
1376 src_port, dst_port, GET_ALIAS_PORT,
1385 FindOriginalAddress(struct in_addr alias_addr)
1387 struct alias_link *link;
1389 link = FindLinkIn(nullAddress, alias_addr,
1390 0, 0, LINK_ADDR, 0);
1394 if (targetAddress.s_addr != 0)
1395 return targetAddress;
1401 if (link->src_addr.s_addr == 0)
1402 return aliasAddress;
1404 return link->src_addr;
1410 FindAliasAddress(struct in_addr original_addr)
1412 struct alias_link *link;
1414 link = FindLinkOut(original_addr, nullAddress,
1418 return aliasAddress;
1422 if (link->alias_addr.s_addr == 0)
1423 return aliasAddress;
1425 return link->alias_addr;
1430 /* External routines for getting or changing link data
1431 (external to alias_db.c, but internal to alias*.c)
1433 SetFragmentData(), GetFragmentData()
1434 SetFragmentPtr(), GetFragmentPtr()
1435 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1436 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1437 GetOriginalPort(), GetAliasPort()
1438 SetAckModified(), GetAckModified()
1439 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1444 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1446 link->data.frag_addr = src_addr;
1451 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1453 *src_addr = link->data.frag_addr;
1458 SetFragmentPtr(struct alias_link *link, char *fptr)
1460 link->data.frag_ptr = fptr;
1465 GetFragmentPtr(struct alias_link *link, char **fptr)
1467 *fptr = link->data.frag_ptr;
1472 SetStateIn(struct alias_link *link, int state)
1474 /* TCP input state */
1476 case ALIAS_TCP_STATE_DISCONNECTED:
1477 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) {
1478 link->expire_time = TCP_EXPIRE_DEAD;
1480 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1482 link->data.tcp->state.in = state;
1484 case ALIAS_TCP_STATE_CONNECTED:
1485 link->expire_time = TCP_EXPIRE_CONNECTED;
1487 case ALIAS_TCP_STATE_NOT_CONNECTED:
1488 link->data.tcp->state.in = state;
1497 SetStateOut(struct alias_link *link, int state)
1499 /* TCP output state */
1501 case ALIAS_TCP_STATE_DISCONNECTED:
1502 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) {
1503 link->expire_time = TCP_EXPIRE_DEAD;
1505 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1507 link->data.tcp->state.out = state;
1509 case ALIAS_TCP_STATE_CONNECTED:
1510 link->expire_time = TCP_EXPIRE_CONNECTED;
1512 case ALIAS_TCP_STATE_NOT_CONNECTED:
1513 link->data.tcp->state.out = state;
1522 GetStateIn(struct alias_link *link)
1524 /* TCP input state */
1525 return link->data.tcp->state.in;
1530 GetStateOut(struct alias_link *link)
1532 /* TCP output state */
1533 return link->data.tcp->state.out;
1538 GetOriginalAddress(struct alias_link *link)
1540 if (link->src_addr.s_addr == 0)
1541 return aliasAddress;
1543 return(link->src_addr);
1548 GetDestAddress(struct alias_link *link)
1550 return(link->dst_addr);
1555 GetAliasAddress(struct alias_link *link)
1557 if (link->alias_addr.s_addr == 0)
1558 return aliasAddress;
1560 return link->alias_addr;
1565 GetDefaultAliasAddress()
1567 return aliasAddress;
1572 SetDefaultAliasAddress(struct in_addr alias_addr)
1574 aliasAddress = alias_addr;
1579 GetOriginalPort(struct alias_link *link)
1581 return(link->src_port);
1586 GetAliasPort(struct alias_link *link)
1588 return(link->alias_port);
1592 GetDestPort(struct alias_link *link)
1594 return(link->dst_port);
1598 SetAckModified(struct alias_link *link)
1600 /* Indicate that ack numbers have been modified in a TCP connection */
1601 link->data.tcp->state.ack_modified = 1;
1606 GetProxyAddress(struct alias_link *link)
1608 return link->proxy_addr;
1613 SetProxyAddress(struct alias_link *link, struct in_addr addr)
1615 link->proxy_addr = addr;
1620 GetProxyPort(struct alias_link *link)
1622 return link->proxy_port;
1627 SetProxyPort(struct alias_link *link, u_short port)
1629 link->proxy_port = port;
1634 GetAckModified(struct alias_link *link)
1636 /* See if ack numbers have been modified */
1637 return link->data.tcp->state.ack_modified;
1642 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1645 Find out how much the ack number has been altered for an incoming
1646 TCP packet. To do this, a circular list is ack numbers where the TCP
1647 packet size was altered is searched.
1652 int delta, ack_diff_min;
1655 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1660 for (i=0; i<N_LINK_TCP_DATA; i++)
1662 struct ack_data_record x;
1664 x = link->data.tcp->ack[i];
1669 ack_diff = SeqDiff(x.ack_new, ack);
1672 if (ack_diff_min >= 0)
1674 if (ack_diff < ack_diff_min)
1677 ack_diff_min = ack_diff;
1683 ack_diff_min = ack_diff;
1693 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1696 Find out how much the seq number has been altered for an outgoing
1697 TCP packet. To do this, a circular list is ack numbers where the TCP
1698 packet size was altered is searched.
1703 int delta, seq_diff_min;
1706 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1711 for (i=0; i<N_LINK_TCP_DATA; i++)
1713 struct ack_data_record x;
1715 x = link->data.tcp->ack[i];
1720 seq_diff = SeqDiff(x.ack_old, seq);
1723 if (seq_diff_min >= 0)
1725 if (seq_diff < seq_diff_min)
1728 seq_diff_min = seq_diff;
1734 seq_diff_min = seq_diff;
1744 AddSeq(struct ip *pip, struct alias_link *link, int delta)
1747 When a TCP packet has been altered in length, save this
1748 information in a circular list. If enough packets have
1749 been altered, then this list will begin to overwrite itself.
1753 struct ack_data_record x;
1754 int hlen, tlen, dlen;
1757 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1759 hlen = (pip->ip_hl + tc->th_off) << 2;
1760 tlen = ntohs(pip->ip_len);
1763 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1764 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1768 i = link->data.tcp->state.index;
1769 link->data.tcp->ack[i] = x;
1772 if (i == N_LINK_TCP_DATA)
1773 link->data.tcp->state.index = 0;
1775 link->data.tcp->state.index = i;
1779 SetExpire(struct alias_link *link, int expire)
1783 link->flags &= ~LINK_PERMANENT;
1786 else if (expire == -1)
1788 link->flags |= LINK_PERMANENT;
1790 else if (expire > 0)
1792 link->expire_time = expire;
1797 fprintf(stderr, "PacketAlias/SetExpire(): ");
1798 fprintf(stderr, "error in expire parameter\n");
1804 ClearCheckNewLink(void)
1810 /* Miscellaneous Functions
1813 InitPacketAliasLog()
1814 UninitPacketAliasLog()
1818 Whenever an outgoing or incoming packet is handled, HouseKeeping()
1819 is called to find and remove timed-out aliasing links. Logic exists
1820 to sweep through the entire table and linked list structure
1823 (prototype in alias_local.h)
1834 * Save system time (seconds) in global variable timeStamp for
1835 * use by other functions. This is done so as not to unnecessarily
1836 * waste timeline by making system calls.
1838 gettimeofday(&tv, &tz);
1839 timeStamp = tv.tv_sec;
1841 /* Compute number of spokes (output table link chains) to cover */
1842 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1843 n100 *= timeStamp - lastCleanupTime;
1844 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1848 /* Handle different cases */
1849 if (n > ALIAS_CLEANUP_MAX_SPOKES)
1851 n = ALIAS_CLEANUP_MAX_SPOKES;
1852 lastCleanupTime = timeStamp;
1853 houseKeepingResidual = 0;
1856 IncrementalCleanup();
1860 lastCleanupTime = timeStamp;
1861 houseKeepingResidual = n100 - 100*n;
1864 IncrementalCleanup();
1869 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1870 fprintf(stderr, "something unexpected in time values\n");
1872 lastCleanupTime = timeStamp;
1873 houseKeepingResidual = 0;
1878 /* Init the log file and enable logging */
1880 InitPacketAliasLog(void)
1882 if ((~packetAliasMode & PKT_ALIAS_LOG)
1883 && (monitorFile = fopen("/var/log/alias.log", "w")))
1885 packetAliasMode |= PKT_ALIAS_LOG;
1886 fprintf(monitorFile,
1887 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1892 /* Close the log-file and disable logging. */
1894 UninitPacketAliasLog(void)
1897 fclose(monitorFile);
1900 packetAliasMode &= ~PKT_ALIAS_LOG;
1908 /* Outside world interfaces
1910 -- "outside world" means other than alias*.c routines --
1912 PacketAliasRedirectPort()
1913 PacketAliasRedirectAddr()
1914 PacketAliasRedirectDelete()
1915 PacketAliasSetAddress()
1918 PacketAliasSetMode()
1920 (prototypes in alias.h)
1923 /* Redirection from a specific public addr:port to a
1924 a private addr:port */
1926 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
1927 struct in_addr dst_addr, u_short dst_port,
1928 struct in_addr alias_addr, u_short alias_port,
1932 struct alias_link *link;
1937 link_type = LINK_UDP;
1940 link_type = LINK_TCP;
1944 fprintf(stderr, "PacketAliasRedirectPort(): ");
1945 fprintf(stderr, "only TCP and UDP protocols allowed\n");
1950 link = AddLink(src_addr, dst_addr, alias_addr,
1951 src_port, dst_port, alias_port,
1956 link->flags |= LINK_PERMANENT;
1961 fprintf(stderr, "PacketAliasRedirectPort(): "
1962 "call to AddLink() failed\n");
1969 /* Translate PPTP packets to a machine on the inside
1972 PacketAliasPptp(struct in_addr src_addr)
1975 pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */
1976 pptpAliasFlag = src_addr.s_addr != INADDR_NONE;
1981 int GetPptpAlias (struct in_addr* alias_addr)
1984 *alias_addr = pptpAliasAddr;
1986 return pptpAliasFlag;
1989 /* Static address translation */
1991 PacketAliasRedirectAddr(struct in_addr src_addr,
1992 struct in_addr alias_addr)
1994 struct alias_link *link;
1996 link = AddLink(src_addr, nullAddress, alias_addr,
2002 link->flags |= LINK_PERMANENT;
2007 fprintf(stderr, "PacketAliasRedirectAddr(): "
2008 "call to AddLink() failed\n");
2017 PacketAliasRedirectDelete(struct alias_link *link)
2019 /* This is a dangerous function to put in the API,
2020 because an invalid pointer can crash the program. */
2029 PacketAliasSetAddress(struct in_addr addr)
2031 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2032 && aliasAddress.s_addr != addr.s_addr)
2035 aliasAddress = addr;
2040 PacketAliasSetTarget(struct in_addr target_addr)
2042 targetAddress = target_addr;
2047 PacketAliasInit(void)
2052 static int firstCall = 1;
2056 gettimeofday(&tv, &tz);
2057 timeStamp = tv.tv_sec;
2058 lastCleanupTime = tv.tv_sec;
2059 houseKeepingResidual = 0;
2061 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2062 linkTableOut[i] = NULL;
2063 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2064 linkTableIn[i] = NULL;
2066 atexit(PacketAliasUninit);
2076 aliasAddress.s_addr = 0;
2077 targetAddress.s_addr = 0;
2082 fragmentIdLinkCount = 0;
2083 fragmentPtrLinkCount = 0;
2088 packetAliasMode = PKT_ALIAS_SAME_PORTS
2089 | PKT_ALIAS_USE_SOCKETS
2090 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2096 PacketAliasUninit(void) {
2100 UninitPacketAliasLog();
2107 /* Change mode for some operations */
2110 unsigned int flags, /* Which state to bring flags to */
2111 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2112 probe for flag values) */
2115 /* Enable logging? */
2116 if (flags & mask & PKT_ALIAS_LOG)
2118 InitPacketAliasLog(); /* Do the enable */
2120 /* _Disable_ logging? */
2121 if (~flags & mask & PKT_ALIAS_LOG) {
2122 UninitPacketAliasLog();
2126 /* Start punching holes in the firewall? */
2127 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2130 /* Stop punching holes in the firewall? */
2131 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2136 /* Other flags can be set/cleared without special action */
2137 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2138 return packetAliasMode;
2143 PacketAliasCheckNewLink(void)
2145 return newDefaultLink;
2152 Code to support firewall punching. This shouldn't really be in this
2153 file, but making variables global is evil too.
2156 /* Firewall include files */
2157 #include <sys/queue.h>
2159 #include <netinet/ip_fw.h>
2163 static void ClearAllFWHoles(void);
2165 static int fireWallBaseNum; /* The first firewall entry free for our use */
2166 static int fireWallNumNums; /* How many entries can we use? */
2167 static int fireWallActiveNum; /* Which entry did we last use? */
2168 static char *fireWallField; /* bool array for entries */
2170 #define fw_setfield(field, num) \
2173 } /*lint -save -e717 */ while(0) /*lint -restore */
2174 #define fw_clrfield(field, num) \
2177 } /*lint -save -e717 */ while(0) /*lint -restore */
2178 #define fw_tstfield(field, num) ((field)[num])
2181 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2182 fireWallBaseNum = base;
2183 fireWallNumNums = num;
2188 fireWallField = malloc(fireWallNumNums);
2189 if (fireWallField) {
2190 memset(fireWallField, 0, fireWallNumNums);
2191 if (fireWallFD < 0) {
2192 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2195 fireWallActiveNum = fireWallBaseNum;
2200 UninitPunchFW(void) {
2202 if (fireWallFD >= 0)
2206 free(fireWallField);
2207 fireWallField = NULL;
2208 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2211 /* Make a certain link go through the firewall */
2213 PunchFWHole(struct alias_link *link) {
2214 int r; /* Result code */
2215 struct ip_fw rule; /* On-the-fly built rule */
2216 int fwhole; /* Where to punch hole */
2218 /* Don't do anything unless we are asked to */
2219 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2221 link->link_type != LINK_TCP ||
2225 memset(&rule, 0, sizeof rule);
2229 /* Find empty slot */
2230 for (fwhole = fireWallActiveNum;
2231 fwhole < fireWallBaseNum + fireWallNumNums &&
2232 fw_tstfield(fireWallField, fwhole);
2235 if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2236 fw_tstfield(fireWallField, fwhole)) {
2237 for (fwhole = fireWallBaseNum;
2238 fwhole < fireWallActiveNum &&
2239 fw_tstfield(fireWallField, fwhole);
2242 if (fwhole == fireWallActiveNum) {
2243 /* No rule point empty - we can't punch more holes. */
2244 fireWallActiveNum = fireWallBaseNum;
2246 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2251 /* Start next search at next position */
2252 fireWallActiveNum = fwhole+1;
2254 /* Build generic part of the two rules */
2255 rule.fw_number = fwhole;
2256 rule.fw_nports = 1; /* Number of source ports; dest ports follow */
2257 rule.fw_flg = IP_FW_F_ACCEPT;
2258 rule.fw_prot = IPPROTO_TCP;
2259 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2260 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2262 /* Build and apply specific part of the rules */
2263 rule.fw_src = GetOriginalAddress(link);
2264 rule.fw_dst = GetDestAddress(link);
2265 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2266 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2268 /* Skip non-bound links - XXX should not be strictly necessary,
2269 but seems to leave hole if not done. Leak of non-bound links?
2270 (Code should be left even if the problem is fixed - it is a
2271 clear optimization) */
2272 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2273 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2276 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2278 rule.fw_src = GetDestAddress(link);
2279 rule.fw_dst = GetOriginalAddress(link);
2280 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2281 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2282 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2285 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2288 /* Indicate hole applied */
2289 link->data.tcp->fwhole = fwhole;
2290 fw_setfield(fireWallField, fwhole);
2293 /* Remove a hole in a firewall associated with a particular alias
2294 link. Calling this too often is harmless. */
2296 ClearFWHole(struct alias_link *link) {
2297 if (link->link_type == LINK_TCP && link->data.tcp) {
2298 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2304 memset(&rule, 0, sizeof rule);
2305 rule.fw_number = fwhole;
2306 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2308 fw_clrfield(fireWallField, fwhole);
2309 link->data.tcp->fwhole = -1;
2313 /* Clear out the entire range dedicated to firewall holes. */
2315 ClearAllFWHoles(void) {
2316 struct ip_fw rule; /* On-the-fly built rule */
2322 memset(&rule, 0, sizeof rule);
2323 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2325 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2328 memset(fireWallField, 0, fireWallNumNums);