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 unspecified 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 are now available through
52 a new interface, SetPacketAliasMode(). This allows 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 permanent 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 PROTO_EXPIRE_TIME 60
151 #define FRAGMENT_ID_EXPIRE_TIME 10
152 #define FRAGMENT_PTR_EXPIRE_TIME 30
154 /* TCP link expire time for different cases */
155 /* When the link has been used and closed - minimal grace time to
156 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
157 #ifndef TCP_EXPIRE_DEAD
158 # define TCP_EXPIRE_DEAD 10
161 /* When the link has been used and closed on one side - the other side
162 is allowed to still send data */
163 #ifndef TCP_EXPIRE_SINGLEDEAD
164 # define TCP_EXPIRE_SINGLEDEAD 90
167 /* When the link isn't yet up */
168 #ifndef TCP_EXPIRE_INITIAL
169 # define TCP_EXPIRE_INITIAL 300
172 /* When the link is up */
173 #ifndef TCP_EXPIRE_CONNECTED
174 # define TCP_EXPIRE_CONNECTED 86400
178 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
179 These constants can be anything except zero, which indicates an
180 unknown port number. */
182 #define NO_DEST_PORT 1
183 #define NO_SRC_PORT 1
189 The fundamental data structure used in this program is
190 "struct alias_link". Whenever a TCP connection is made,
191 a UDP datagram is sent out, or an ICMP echo request is made,
192 a link record is made (if it has not already been created).
193 The link record is identified by the source address/port
194 and the destination address/port. In the case of an ICMP
195 echo request, the source port is treated as being equivalent
196 with the 16-bit ID number of the ICMP packet.
198 The link record also can store some auxiliary data. For
199 TCP connections that have had sequence and acknowledgment
200 modifications, data space is available to track these changes.
201 A state field is used to keep track in changes to the TCP
202 connection state. ID numbers of fragments can also be
203 stored in the auxiliary space. Pointers to unresolved
204 fragments can also be stored.
206 The link records support two independent chainings. Lookup
207 tables for input and out tables hold the initial pointers
208 the link chains. On input, the lookup table indexes on alias
209 port and link type. On output, the lookup table indexes on
210 source address, destination address, source port, destination
214 struct ack_data_record /* used to save changes to ACK/sequence numbers */
222 struct tcp_state /* Information about TCP connection */
224 int in; /* State for outside -> inside */
225 int out; /* State for inside -> outside */
226 int index; /* Index to ACK data array */
227 int ack_modified; /* Indicates whether ACK and sequence numbers */
231 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
232 saved for a modified TCP stream */
235 struct tcp_state state;
236 struct ack_data_record ack[N_LINK_TCP_DATA];
237 int fwhole; /* Which firewall record is used for this hole? */
240 struct server /* LSNAT server pool (circular list) */
247 struct alias_link /* Main data structure */
249 struct in_addr src_addr; /* Address and port information */
250 struct in_addr dst_addr;
251 struct in_addr alias_addr;
252 struct in_addr proxy_addr;
257 struct server *server;
259 int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */
261 /* values for link_type */
262 #define LINK_ICMP IPPROTO_ICMP
263 #define LINK_UDP IPPROTO_UDP
264 #define LINK_TCP IPPROTO_TCP
265 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
266 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
267 #define LINK_ADDR (IPPROTO_MAX + 3)
269 int flags; /* indicates special characteristics */
272 #define LINK_UNKNOWN_DEST_PORT 0x01
273 #define LINK_UNKNOWN_DEST_ADDR 0x02
274 #define LINK_PERMANENT 0x04
275 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
276 #define LINK_UNFIREWALLED 0x08
278 int timestamp; /* Time link was last accessed */
279 int expire_time; /* Expire time for link */
281 int sockfd; /* socket descriptor */
283 u_int start_point_out; /* Index number in output lookup table */
284 u_int start_point_in;
285 struct alias_link *next_out; /* Linked list pointers for input and */
286 struct alias_link *last_out; /* output tables */
287 struct alias_link *next_in; /* . */
288 struct alias_link *last_in; /* . */
290 union /* Auxiliary data */
293 struct in_addr frag_addr;
304 The global variables listed here are only accessed from
305 within alias_db.c and so are prefixed with the static
309 int packetAliasMode; /* Mode flags */
310 /* - documented in alias.h */
312 static struct in_addr aliasAddress; /* Address written onto source */
313 /* field of IP packet. */
315 static struct in_addr targetAddress; /* IP address incoming packets */
316 /* are sent to if no aliasing */
317 /* link already exists */
319 static struct in_addr nullAddress; /* Used as a dummy parameter for */
320 /* some function calls */
321 static struct alias_link *
322 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */
323 /* chains of link records. Each */
324 static struct alias_link * /* link record is doubly indexed */
325 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */
328 static int icmpLinkCount; /* Link statistics */
329 static int udpLinkCount;
330 static int tcpLinkCount;
331 static int protoLinkCount;
332 static int fragmentIdLinkCount;
333 static int fragmentPtrLinkCount;
334 static int sockCount;
336 static int cleanupIndex; /* Index to chain of link table */
337 /* being inspected for old links */
339 static int timeStamp; /* System time in seconds for */
342 static int lastCleanupTime; /* Last time IncrementalCleanup() */
345 static int houseKeepingResidual; /* used by HouseKeeping() */
347 static int deleteAllLinks; /* If equal to zero, DeleteLink() */
348 /* will not remove permanent links */
350 static FILE *monitorFile; /* File descriptor for link */
351 /* statistics monitoring file */
353 static int newDefaultLink; /* Indicates if a new aliasing */
354 /* link has been created after a */
355 /* call to PacketAliasIn/Out(). */
358 static int fireWallFD = -1; /* File descriptor to be able to */
359 /* control firewall. Opened by */
360 /* PacketAliasSetMode on first */
361 /* setting the PKT_ALIAS_PUNCH_FW */
371 /* Internal utility routines (used only in alias_db.c)
373 Lookup table starting points:
374 StartPointIn() -- link table initial search point for
376 StartPointOut() -- link table initial search point for
380 SeqDiff() -- difference between two TCP sequences
381 ShowAliasStats() -- send alias statistics to a monitor file
385 /* Local prototypes */
386 static u_int StartPointIn(struct in_addr, u_short, int);
388 static u_int StartPointOut(struct in_addr, struct in_addr,
389 u_short, u_short, int);
391 static int SeqDiff(u_long, u_long);
393 static void ShowAliasStats(void);
396 /* Firewall control */
397 static void InitPunchFW(void);
398 static void UninitPunchFW(void);
399 static void ClearFWHole(struct alias_link *link);
402 /* Log file control */
403 static void InitPacketAliasLog(void);
404 static void UninitPacketAliasLog(void);
407 StartPointIn(struct in_addr alias_addr,
413 n = alias_addr.s_addr;
416 return(n % LINK_TABLE_IN_SIZE);
421 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
422 u_short src_port, u_short dst_port, int link_type)
427 n += dst_addr.s_addr;
432 return(n % LINK_TABLE_OUT_SIZE);
437 SeqDiff(u_long x, u_long y)
439 /* Return the difference between two TCP sequence numbers */
442 This function is encapsulated in case there are any unusual
443 arithmetic conditions that need to be considered.
446 return (ntohl(y) - ntohl(x));
453 /* Used for debugging */
457 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, proto=%d, frag_id=%d frag_ptr=%d",
463 fragmentPtrLinkCount);
465 fprintf(monitorFile, " / tot=%d (sock=%d)\n",
466 icmpLinkCount + udpLinkCount
469 + fragmentIdLinkCount
470 + fragmentPtrLinkCount,
481 /* Internal routines for finding, deleting and adding links
484 GetNewPort() -- find and reserve new alias port number
485 GetSocket() -- try to allocate a socket for a given port
487 Link creation and deletion:
488 CleanupAliasData() - remove all link chains from lookup table
489 IncrementalCleanup() - look for stale links in a single chain
490 DeleteLink() - remove link
492 ReLink() - change link
495 FindLinkOut() - find link for outgoing packets
496 FindLinkIn() - find link for incoming packets
499 /* Local prototypes */
500 static int GetNewPort(struct alias_link *, int);
502 static u_short GetSocket(u_short, int *, int);
504 static void CleanupAliasData(void);
506 static void IncrementalCleanup(void);
508 static void DeleteLink(struct alias_link *);
510 static struct alias_link *
511 AddLink(struct in_addr, struct in_addr, struct in_addr,
512 u_short, u_short, int, int);
514 static struct alias_link *
515 ReLink(struct alias_link *,
516 struct in_addr, struct in_addr, struct in_addr,
517 u_short, u_short, int, int);
519 static struct alias_link *
520 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int);
522 static struct alias_link *
523 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
526 #define ALIAS_PORT_BASE 0x08000
527 #define ALIAS_PORT_MASK 0x07fff
528 #define GET_NEW_PORT_MAX_ATTEMPTS 20
530 #define GET_ALIAS_PORT -1
531 #define GET_ALIAS_ID GET_ALIAS_PORT
533 /* GetNewPort() allocates port numbers. Note that if a port number
534 is already in use, that does not mean that it cannot be used by
535 another link concurrently. This is because GetNewPort() looks for
536 unused triplets: (dest addr, dest port, alias port). */
539 GetNewPort(struct alias_link *link, int alias_port_param)
547 Description of alias_port_param for GetNewPort(). When
548 this parameter is zero or positive, it precisely specifies
549 the port number. GetNewPort() will return this number
550 without check that it is in use.
552 When this parameter is -1, it indicates to get a randomly
553 selected port number.
556 if (alias_port_param == GET_ALIAS_PORT)
559 * The aliasing port is automatically selected
560 * by one of two methods below:
562 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
564 if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
567 * When the PKT_ALIAS_SAME_PORTS option is
568 * chosen, the first try will be the
569 * actual source port. If this is already
570 * in use, the remainder of the trials
573 port_net = link->src_port;
574 port_sys = ntohs(port_net);
578 /* First trial and all subsequent are random. */
579 port_sys = random() & ALIAS_PORT_MASK;
580 port_sys += ALIAS_PORT_BASE;
581 port_net = htons(port_sys);
584 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
586 link->alias_port = (u_short) alias_port_param;
592 fprintf(stderr, "PacketAlias/GetNewPort(): ");
593 fprintf(stderr, "input parameter error\n");
599 /* Port number search */
600 for (i=0; i<max_trials; i++)
603 struct alias_link *search_result;
605 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
606 link->dst_port, port_net,
609 if (search_result == NULL)
611 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
612 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
619 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS)
620 && (link->flags & LINK_PARTIALLY_SPECIFIED))
622 if (GetSocket(port_net, &link->sockfd, link->link_type))
624 link->alias_port = port_net;
630 link->alias_port = port_net;
635 port_sys = random() & ALIAS_PORT_MASK;
636 port_sys += ALIAS_PORT_BASE;
637 port_net = htons(port_sys);
641 fprintf(stderr, "PacketAlias/GetnewPort(): ");
642 fprintf(stderr, "could not find free port\n");
650 GetSocket(u_short port_net, int *sockfd, int link_type)
654 struct sockaddr_in sock_addr;
656 if (link_type == LINK_TCP)
657 sock = socket(AF_INET, SOCK_STREAM, 0);
658 else if (link_type == LINK_UDP)
659 sock = socket(AF_INET, SOCK_DGRAM, 0);
663 fprintf(stderr, "PacketAlias/GetSocket(): ");
664 fprintf(stderr, "incorrect link type\n");
672 fprintf(stderr, "PacketAlias/GetSocket(): ");
673 fprintf(stderr, "socket() error %d\n", *sockfd);
678 sock_addr.sin_family = AF_INET;
679 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
680 sock_addr.sin_port = port_net;
683 (struct sockaddr *) &sock_addr,
700 CleanupAliasData(void)
702 struct alias_link *link;
706 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
708 link = linkTableOut[i];
711 struct alias_link *link_next;
712 link_next = link->next_out;
724 IncrementalCleanup(void)
727 struct alias_link *link;
730 link = linkTableOut[cleanupIndex++];
734 struct alias_link *link_next;
736 link_next = link->next_out;
737 idelta = timeStamp - link->timestamp;
738 switch (link->link_type)
741 if (idelta > link->expire_time)
743 struct tcp_dat *tcp_aux;
745 tcp_aux = link->data.tcp;
746 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
747 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
755 if (idelta > link->expire_time)
765 if (cleanupIndex == LINK_TABLE_OUT_SIZE)
770 DeleteLink(struct alias_link *link)
772 struct alias_link *link_last;
773 struct alias_link *link_next;
775 /* Don't do anything if the link is marked permanent */
776 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
780 /* Delete associated firewall hole, if any */
784 /* Free memory allocated for LSNAT server pool */
785 if (link->server != NULL) {
786 struct server *head, *curr, *next;
788 head = curr = link->server;
792 } while ((curr = next) != head);
795 /* Adjust output table pointers */
796 link_last = link->last_out;
797 link_next = link->next_out;
799 if (link_last != NULL)
800 link_last->next_out = link_next;
802 linkTableOut[link->start_point_out] = link_next;
804 if (link_next != NULL)
805 link_next->last_out = link_last;
807 /* Adjust input table pointers */
808 link_last = link->last_in;
809 link_next = link->next_in;
811 if (link_last != NULL)
812 link_last->next_in = link_next;
814 linkTableIn[link->start_point_in] = link_next;
816 if (link_next != NULL)
817 link_next->last_in = link_last;
819 /* Close socket, if one has been allocated */
820 if (link->sockfd != -1)
826 /* Link-type dependent cleanup */
827 switch(link->link_type)
837 if (link->data.tcp != NULL)
838 free(link->data.tcp);
840 case LINK_FRAGMENT_ID:
841 fragmentIdLinkCount--;
843 case LINK_FRAGMENT_PTR:
844 fragmentPtrLinkCount--;
845 if (link->data.frag_ptr != NULL)
846 free(link->data.frag_ptr);
858 /* Write statistics, if logging enabled */
859 if (packetAliasMode & PKT_ALIAS_LOG)
866 static struct alias_link *
867 AddLink(struct in_addr src_addr,
868 struct in_addr dst_addr,
869 struct in_addr alias_addr,
872 int alias_port_param, /* if less than zero, alias */
873 int link_type) /* port will be automatically */
874 { /* chosen. If greater than */
875 u_int start_point; /* zero, equal to alias port */
876 struct alias_link *link;
877 struct alias_link *first_link;
879 link = malloc(sizeof(struct alias_link));
882 /* Basic initialization */
883 link->src_addr = src_addr;
884 link->dst_addr = dst_addr;
885 link->alias_addr = alias_addr;
886 link->proxy_addr.s_addr = INADDR_ANY;
887 link->src_port = src_port;
888 link->dst_port = dst_port;
889 link->proxy_port = 0;
891 link->link_type = link_type;
894 link->timestamp = timeStamp;
896 /* Expiration time */
900 link->expire_time = ICMP_EXPIRE_TIME;
903 link->expire_time = UDP_EXPIRE_TIME;
906 link->expire_time = TCP_EXPIRE_INITIAL;
908 case LINK_FRAGMENT_ID:
909 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
911 case LINK_FRAGMENT_PTR:
912 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
917 link->expire_time = PROTO_EXPIRE_TIME;
921 /* Determine alias flags */
922 if (dst_addr.s_addr == INADDR_ANY)
923 link->flags |= LINK_UNKNOWN_DEST_ADDR;
925 link->flags |= LINK_UNKNOWN_DEST_PORT;
927 /* Determine alias port */
928 if (GetNewPort(link, alias_port_param) != 0)
934 /* Set up pointers for output lookup table */
935 start_point = StartPointOut(src_addr, dst_addr,
936 src_port, dst_port, link_type);
937 first_link = linkTableOut[start_point];
939 link->last_out = NULL;
940 link->next_out = first_link;
941 link->start_point_out = start_point;
943 if (first_link != NULL)
944 first_link->last_out = link;
946 linkTableOut[start_point] = link;
948 /* Set up pointers for input lookup table */
949 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
950 first_link = linkTableIn[start_point];
952 link->last_in = NULL;
953 link->next_in = first_link;
954 link->start_point_in = start_point;
956 if (first_link != NULL)
957 first_link->last_in = link;
959 linkTableIn[start_point] = link;
961 /* Link-type dependent initialization */
964 struct tcp_dat *aux_tcp;
973 aux_tcp = malloc(sizeof(struct tcp_dat));
974 link->data.tcp = aux_tcp;
980 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
981 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
982 aux_tcp->state.index = 0;
983 aux_tcp->state.ack_modified = 0;
984 for (i=0; i<N_LINK_TCP_DATA; i++)
985 aux_tcp->ack[i].active = 0;
986 aux_tcp->fwhole = -1;
991 fprintf(stderr, "PacketAlias/AddLink: ");
992 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
996 case LINK_FRAGMENT_ID:
997 fragmentIdLinkCount++;
999 case LINK_FRAGMENT_PTR:
1000 fragmentPtrLinkCount++;
1012 fprintf(stderr, "PacketAlias/AddLink(): ");
1013 fprintf(stderr, "malloc() call failed.\n");
1017 if (packetAliasMode & PKT_ALIAS_LOG)
1025 static struct alias_link *
1026 ReLink(struct alias_link *old_link,
1027 struct in_addr src_addr,
1028 struct in_addr dst_addr,
1029 struct in_addr alias_addr,
1032 int alias_port_param, /* if less than zero, alias */
1033 int link_type) /* port will be automatically */
1034 { /* chosen. If greater than */
1035 struct alias_link *new_link; /* zero, equal to alias port */
1037 new_link = AddLink(src_addr, dst_addr, alias_addr,
1038 src_port, dst_port, alias_port_param,
1041 if (new_link != NULL &&
1042 old_link->link_type == LINK_TCP &&
1043 old_link->data.tcp &&
1044 old_link->data.tcp->fwhole > 0) {
1045 PunchFWHole(new_link);
1048 DeleteLink(old_link);
1052 static struct alias_link *
1053 _FindLinkOut(struct in_addr src_addr,
1054 struct in_addr dst_addr,
1058 int replace_partial_links)
1061 struct alias_link *link;
1063 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1064 link = linkTableOut[i];
1065 while (link != NULL)
1067 if (link->src_addr.s_addr == src_addr.s_addr
1068 && link->server == NULL
1069 && link->dst_addr.s_addr == dst_addr.s_addr
1070 && link->dst_port == dst_port
1071 && link->src_port == src_port
1072 && link->link_type == link_type)
1074 link->timestamp = timeStamp;
1077 link = link->next_out;
1080 /* Search for partially specified links. */
1081 if (link == NULL && replace_partial_links)
1083 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1085 link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1088 link = _FindLinkOut(src_addr, nullAddress, src_port,
1089 dst_port, link_type, 0);
1092 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1094 link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1100 src_addr, dst_addr, link->alias_addr,
1101 src_port, dst_port, link->alias_port,
1109 static struct alias_link *
1110 FindLinkOut(struct in_addr src_addr,
1111 struct in_addr dst_addr,
1115 int replace_partial_links)
1117 struct alias_link *link;
1119 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1120 link_type, replace_partial_links);
1124 /* The following allows permanent links to be
1125 specified as using the default source address
1126 (i.e. device interface address) without knowing
1127 in advance what that address is. */
1128 if (aliasAddress.s_addr != 0 &&
1129 src_addr.s_addr == aliasAddress.s_addr)
1131 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1132 link_type, replace_partial_links);
1140 static struct alias_link *
1141 _FindLinkIn(struct in_addr dst_addr,
1142 struct in_addr alias_addr,
1146 int replace_partial_links)
1150 struct alias_link *link;
1151 struct alias_link *link_fully_specified;
1152 struct alias_link *link_unknown_all;
1153 struct alias_link *link_unknown_dst_addr;
1154 struct alias_link *link_unknown_dst_port;
1156 /* Initialize pointers */
1157 link_fully_specified = NULL;
1158 link_unknown_all = NULL;
1159 link_unknown_dst_addr = NULL;
1160 link_unknown_dst_port = NULL;
1162 /* If either the dest addr or port is unknown, the search
1163 loop will have to know about this. */
1166 if (dst_addr.s_addr == INADDR_ANY)
1167 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1169 flags_in |= LINK_UNKNOWN_DEST_PORT;
1172 start_point = StartPointIn(alias_addr, alias_port, link_type);
1173 link = linkTableIn[start_point];
1174 while (link != NULL)
1178 flags = flags_in | link->flags;
1179 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1181 if (link->alias_addr.s_addr == alias_addr.s_addr
1182 && link->alias_port == alias_port
1183 && link->dst_addr.s_addr == dst_addr.s_addr
1184 && link->dst_port == dst_port
1185 && link->link_type == link_type)
1187 link_fully_specified = link;
1191 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1192 && (flags & LINK_UNKNOWN_DEST_PORT))
1194 if (link->alias_addr.s_addr == alias_addr.s_addr
1195 && link->alias_port == alias_port
1196 && link->link_type == link_type)
1198 if (link_unknown_all == NULL)
1199 link_unknown_all = link;
1202 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1204 if (link->alias_addr.s_addr == alias_addr.s_addr
1205 && link->alias_port == alias_port
1206 && link->link_type == link_type
1207 && link->dst_port == dst_port)
1209 if (link_unknown_dst_addr == NULL)
1210 link_unknown_dst_addr = link;
1213 else if (flags & LINK_UNKNOWN_DEST_PORT)
1215 if (link->alias_addr.s_addr == alias_addr.s_addr
1216 && link->alias_port == alias_port
1217 && link->link_type == link_type
1218 && link->dst_addr.s_addr == dst_addr.s_addr)
1220 if (link_unknown_dst_port == NULL)
1221 link_unknown_dst_port = link;
1224 link = link->next_in;
1229 if (link_fully_specified != NULL)
1231 link_fully_specified->timestamp = timeStamp;
1232 link = link_fully_specified;
1234 else if (link_unknown_dst_port != NULL)
1235 link = link_unknown_dst_port;
1236 else if (link_unknown_dst_addr != NULL)
1237 link = link_unknown_dst_addr;
1238 else if (link_unknown_all != NULL)
1239 link = link_unknown_all;
1243 if (replace_partial_links &&
1244 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
1246 struct in_addr src_addr;
1249 if (link->server != NULL) { /* LSNAT link */
1250 src_addr = link->server->addr;
1251 src_port = link->server->port;
1252 link->server = link->server->next;
1254 src_addr = link->src_addr;
1255 src_port = link->src_port;
1259 src_addr, dst_addr, alias_addr,
1260 src_port, dst_port, alias_port,
1267 static struct alias_link *
1268 FindLinkIn(struct in_addr dst_addr,
1269 struct in_addr alias_addr,
1273 int replace_partial_links)
1275 struct alias_link *link;
1277 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1278 link_type, replace_partial_links);
1282 /* The following allows permanent links to be
1283 specified as using the default aliasing address
1284 (i.e. device interface address) without knowing
1285 in advance what that address is. */
1286 if (aliasAddress.s_addr != 0 &&
1287 alias_addr.s_addr == aliasAddress.s_addr)
1289 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1290 link_type, replace_partial_links);
1300 /* External routines for finding/adding links
1302 -- "external" means outside alias_db.c, but within alias*.c --
1304 FindIcmpIn(), FindIcmpOut()
1305 FindFragmentIn1(), FindFragmentIn2()
1306 AddFragmentPtrLink(), FindFragmentPtr()
1307 FindProtoIn(), FindProtoOut()
1308 FindUdpTcpIn(), FindUdpTcpOut()
1309 FindOriginalAddress(), FindAliasAddress()
1311 (prototypes in alias_local.h)
1316 FindIcmpIn(struct in_addr dst_addr,
1317 struct in_addr alias_addr,
1320 return FindLinkIn(dst_addr, alias_addr,
1321 NO_DEST_PORT, id_alias,
1327 FindIcmpOut(struct in_addr src_addr,
1328 struct in_addr dst_addr,
1331 struct alias_link * link;
1333 link = FindLinkOut(src_addr, dst_addr,
1338 struct in_addr alias_addr;
1340 alias_addr = FindAliasAddress(src_addr);
1341 link = AddLink(src_addr, dst_addr, alias_addr,
1342 id, NO_DEST_PORT, GET_ALIAS_ID,
1351 FindFragmentIn1(struct in_addr dst_addr,
1352 struct in_addr alias_addr,
1355 struct alias_link *link;
1357 link = FindLinkIn(dst_addr, alias_addr,
1358 NO_DEST_PORT, ip_id,
1359 LINK_FRAGMENT_ID, 0);
1363 link = AddLink(nullAddress, dst_addr, alias_addr,
1364 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1373 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1374 struct in_addr alias_addr, /* is not found. */
1377 return FindLinkIn(dst_addr, alias_addr,
1378 NO_DEST_PORT, ip_id,
1379 LINK_FRAGMENT_ID, 0);
1384 AddFragmentPtrLink(struct in_addr dst_addr,
1387 return AddLink(nullAddress, dst_addr, nullAddress,
1388 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1394 FindFragmentPtr(struct in_addr dst_addr,
1397 return FindLinkIn(dst_addr, nullAddress,
1398 NO_DEST_PORT, ip_id,
1399 LINK_FRAGMENT_PTR, 0);
1404 FindProtoIn(struct in_addr dst_addr,
1405 struct in_addr alias_addr,
1408 struct alias_link *link;
1410 link = FindLinkIn(dst_addr, alias_addr,
1414 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1416 struct in_addr target_addr;
1418 target_addr = FindOriginalAddress(alias_addr);
1419 link = AddLink(target_addr, dst_addr, alias_addr,
1420 NO_SRC_PORT, NO_DEST_PORT, 0,
1429 FindProtoOut(struct in_addr src_addr,
1430 struct in_addr dst_addr,
1433 struct alias_link *link;
1435 link = FindLinkOut(src_addr, dst_addr,
1436 NO_SRC_PORT, NO_DEST_PORT,
1441 struct in_addr alias_addr;
1443 alias_addr = FindAliasAddress(src_addr);
1444 link = AddLink(src_addr, dst_addr, alias_addr,
1445 NO_SRC_PORT, NO_DEST_PORT, 0,
1454 FindUdpTcpIn(struct in_addr dst_addr,
1455 struct in_addr alias_addr,
1461 struct alias_link *link;
1466 link_type = LINK_UDP;
1469 link_type = LINK_TCP;
1476 link = FindLinkIn(dst_addr, alias_addr,
1477 dst_port, alias_port,
1480 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING)
1481 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)
1484 struct in_addr target_addr;
1486 target_addr = FindOriginalAddress(alias_addr);
1487 link = AddLink(target_addr, dst_addr, alias_addr,
1488 alias_port, dst_port, alias_port,
1497 FindUdpTcpOut(struct in_addr src_addr,
1498 struct in_addr dst_addr,
1504 struct alias_link *link;
1509 link_type = LINK_UDP;
1512 link_type = LINK_TCP;
1519 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1);
1523 struct in_addr alias_addr;
1525 alias_addr = FindAliasAddress(src_addr);
1526 link = AddLink(src_addr, dst_addr, alias_addr,
1527 src_port, dst_port, GET_ALIAS_PORT,
1536 FindOriginalAddress(struct in_addr alias_addr)
1538 struct alias_link *link;
1540 link = FindLinkIn(nullAddress, alias_addr,
1541 0, 0, LINK_ADDR, 0);
1545 if (targetAddress.s_addr == INADDR_ANY)
1547 else if (targetAddress.s_addr == INADDR_NONE)
1548 return aliasAddress;
1550 return targetAddress;
1554 if (link->server != NULL) { /* LSNAT link */
1555 struct in_addr src_addr;
1557 src_addr = link->server->addr;
1558 link->server = link->server->next;
1560 } else if (link->src_addr.s_addr == INADDR_ANY)
1561 return aliasAddress;
1563 return link->src_addr;
1569 FindAliasAddress(struct in_addr original_addr)
1571 struct alias_link *link;
1573 link = FindLinkOut(original_addr, nullAddress,
1574 0, 0, LINK_ADDR, 0);
1577 return aliasAddress;
1581 if (link->alias_addr.s_addr == INADDR_ANY)
1582 return aliasAddress;
1584 return link->alias_addr;
1589 /* External routines for getting or changing link data
1590 (external to alias_db.c, but internal to alias*.c)
1592 SetFragmentData(), GetFragmentData()
1593 SetFragmentPtr(), GetFragmentPtr()
1594 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1595 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1596 GetOriginalPort(), GetAliasPort()
1597 SetAckModified(), GetAckModified()
1598 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1603 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1605 link->data.frag_addr = src_addr;
1610 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1612 *src_addr = link->data.frag_addr;
1617 SetFragmentPtr(struct alias_link *link, char *fptr)
1619 link->data.frag_ptr = fptr;
1624 GetFragmentPtr(struct alias_link *link, char **fptr)
1626 *fptr = link->data.frag_ptr;
1631 SetStateIn(struct alias_link *link, int state)
1633 /* TCP input state */
1635 case ALIAS_TCP_STATE_DISCONNECTED:
1636 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1637 link->expire_time = TCP_EXPIRE_DEAD;
1639 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1641 case ALIAS_TCP_STATE_CONNECTED:
1642 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1643 link->expire_time = TCP_EXPIRE_CONNECTED;
1648 link->data.tcp->state.in = state;
1653 SetStateOut(struct alias_link *link, int state)
1655 /* TCP output state */
1657 case ALIAS_TCP_STATE_DISCONNECTED:
1658 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1659 link->expire_time = TCP_EXPIRE_DEAD;
1661 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1663 case ALIAS_TCP_STATE_CONNECTED:
1664 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1665 link->expire_time = TCP_EXPIRE_CONNECTED;
1670 link->data.tcp->state.out = state;
1675 GetStateIn(struct alias_link *link)
1677 /* TCP input state */
1678 return link->data.tcp->state.in;
1683 GetStateOut(struct alias_link *link)
1685 /* TCP output state */
1686 return link->data.tcp->state.out;
1691 GetOriginalAddress(struct alias_link *link)
1693 if (link->src_addr.s_addr == INADDR_ANY)
1694 return aliasAddress;
1696 return(link->src_addr);
1701 GetDestAddress(struct alias_link *link)
1703 return(link->dst_addr);
1708 GetAliasAddress(struct alias_link *link)
1710 if (link->alias_addr.s_addr == INADDR_ANY)
1711 return aliasAddress;
1713 return link->alias_addr;
1718 GetDefaultAliasAddress()
1720 return aliasAddress;
1725 SetDefaultAliasAddress(struct in_addr alias_addr)
1727 aliasAddress = alias_addr;
1732 GetOriginalPort(struct alias_link *link)
1734 return(link->src_port);
1739 GetAliasPort(struct alias_link *link)
1741 return(link->alias_port);
1746 GetDestPort(struct alias_link *link)
1748 return(link->dst_port);
1753 SetAckModified(struct alias_link *link)
1755 /* Indicate that ACK numbers have been modified in a TCP connection */
1756 link->data.tcp->state.ack_modified = 1;
1761 GetProxyAddress(struct alias_link *link)
1763 return link->proxy_addr;
1768 SetProxyAddress(struct alias_link *link, struct in_addr addr)
1770 link->proxy_addr = addr;
1775 GetProxyPort(struct alias_link *link)
1777 return link->proxy_port;
1782 SetProxyPort(struct alias_link *link, u_short port)
1784 link->proxy_port = port;
1789 GetAckModified(struct alias_link *link)
1791 /* See if ACK numbers have been modified */
1792 return link->data.tcp->state.ack_modified;
1797 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1800 Find out how much the ACK number has been altered for an incoming
1801 TCP packet. To do this, a circular list of ACK numbers where the TCP
1802 packet size was altered is searched.
1807 int delta, ack_diff_min;
1810 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1815 for (i=0; i<N_LINK_TCP_DATA; i++)
1817 struct ack_data_record x;
1819 x = link->data.tcp->ack[i];
1824 ack_diff = SeqDiff(x.ack_new, ack);
1827 if (ack_diff_min >= 0)
1829 if (ack_diff < ack_diff_min)
1832 ack_diff_min = ack_diff;
1838 ack_diff_min = ack_diff;
1848 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1851 Find out how much the sequence number has been altered for an outgoing
1852 TCP packet. To do this, a circular list of ACK numbers where the TCP
1853 packet size was altered is searched.
1858 int delta, seq_diff_min;
1861 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1866 for (i=0; i<N_LINK_TCP_DATA; i++)
1868 struct ack_data_record x;
1870 x = link->data.tcp->ack[i];
1875 seq_diff = SeqDiff(x.ack_old, seq);
1878 if (seq_diff_min >= 0)
1880 if (seq_diff < seq_diff_min)
1883 seq_diff_min = seq_diff;
1889 seq_diff_min = seq_diff;
1899 AddSeq(struct ip *pip, struct alias_link *link, int delta)
1902 When a TCP packet has been altered in length, save this
1903 information in a circular list. If enough packets have
1904 been altered, then this list will begin to overwrite itself.
1908 struct ack_data_record x;
1909 int hlen, tlen, dlen;
1912 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1914 hlen = (pip->ip_hl + tc->th_off) << 2;
1915 tlen = ntohs(pip->ip_len);
1918 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1919 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1923 i = link->data.tcp->state.index;
1924 link->data.tcp->ack[i] = x;
1927 if (i == N_LINK_TCP_DATA)
1928 link->data.tcp->state.index = 0;
1930 link->data.tcp->state.index = i;
1934 SetExpire(struct alias_link *link, int expire)
1938 link->flags &= ~LINK_PERMANENT;
1941 else if (expire == -1)
1943 link->flags |= LINK_PERMANENT;
1945 else if (expire > 0)
1947 link->expire_time = expire;
1952 fprintf(stderr, "PacketAlias/SetExpire(): ");
1953 fprintf(stderr, "error in expire parameter\n");
1959 ClearCheckNewLink(void)
1965 /* Miscellaneous Functions
1968 InitPacketAliasLog()
1969 UninitPacketAliasLog()
1973 Whenever an outgoing or incoming packet is handled, HouseKeeping()
1974 is called to find and remove timed-out aliasing links. Logic exists
1975 to sweep through the entire table and linked list structure
1978 (prototype in alias_local.h)
1989 * Save system time (seconds) in global variable timeStamp for
1990 * use by other functions. This is done so as not to unnecessarily
1991 * waste timeline by making system calls.
1993 gettimeofday(&tv, &tz);
1994 timeStamp = tv.tv_sec;
1996 /* Compute number of spokes (output table link chains) to cover */
1997 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1998 n100 *= timeStamp - lastCleanupTime;
1999 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2003 /* Handle different cases */
2004 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2006 n = ALIAS_CLEANUP_MAX_SPOKES;
2007 lastCleanupTime = timeStamp;
2008 houseKeepingResidual = 0;
2011 IncrementalCleanup();
2015 lastCleanupTime = timeStamp;
2016 houseKeepingResidual = n100 - 100*n;
2019 IncrementalCleanup();
2024 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2025 fprintf(stderr, "something unexpected in time values\n");
2027 lastCleanupTime = timeStamp;
2028 houseKeepingResidual = 0;
2033 /* Init the log file and enable logging */
2035 InitPacketAliasLog(void)
2037 if ((~packetAliasMode & PKT_ALIAS_LOG)
2038 && (monitorFile = fopen("/var/log/alias.log", "w")))
2040 packetAliasMode |= PKT_ALIAS_LOG;
2041 fprintf(monitorFile,
2042 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2047 /* Close the log-file and disable logging. */
2049 UninitPacketAliasLog(void)
2052 fclose(monitorFile);
2055 packetAliasMode &= ~PKT_ALIAS_LOG;
2063 /* Outside world interfaces
2065 -- "outside world" means other than alias*.c routines --
2067 PacketAliasRedirectPort()
2068 PacketAliasAddServer()
2069 PacketAliasRedirectProto()
2070 PacketAliasRedirectAddr()
2071 PacketAliasRedirectDelete()
2072 PacketAliasSetAddress()
2075 PacketAliasSetMode()
2077 (prototypes in alias.h)
2080 /* Redirection from a specific public addr:port to a
2081 private addr:port */
2083 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
2084 struct in_addr dst_addr, u_short dst_port,
2085 struct in_addr alias_addr, u_short alias_port,
2089 struct alias_link *link;
2094 link_type = LINK_UDP;
2097 link_type = LINK_TCP;
2101 fprintf(stderr, "PacketAliasRedirectPort(): ");
2102 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2107 link = AddLink(src_addr, dst_addr, alias_addr,
2108 src_port, dst_port, alias_port,
2113 link->flags |= LINK_PERMANENT;
2118 fprintf(stderr, "PacketAliasRedirectPort(): "
2119 "call to AddLink() failed\n");
2126 /* Add server to the pool of servers */
2128 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
2130 struct server *server;
2132 server = malloc(sizeof(struct server));
2134 if (server != NULL) {
2135 struct server *head;
2137 server->addr = addr;
2138 server->port = port;
2140 head = link->server;
2142 server->next = server;
2146 for (s = head; s->next != head; s = s->next);
2148 server->next = head;
2150 link->server = server;
2156 /* Translate PPTP packets to a machine on the inside
2157 * XXX This function is made obsolete by PacketAliasRedirectProto().
2160 PacketAliasPptp(struct in_addr src_addr)
2163 if (src_addr.s_addr != INADDR_NONE)
2164 (void)PacketAliasRedirectProto(src_addr, nullAddress, nullAddress,
2170 /* Redirect packets of a given IP protocol from a specific
2171 public address to a private address */
2173 PacketAliasRedirectProto(struct in_addr src_addr,
2174 struct in_addr dst_addr,
2175 struct in_addr alias_addr,
2178 struct alias_link *link;
2180 link = AddLink(src_addr, dst_addr, alias_addr,
2181 NO_SRC_PORT, NO_DEST_PORT, 0,
2186 link->flags |= LINK_PERMANENT;
2191 fprintf(stderr, "PacketAliasRedirectProto(): "
2192 "call to AddLink() failed\n");
2199 /* Static address translation */
2201 PacketAliasRedirectAddr(struct in_addr src_addr,
2202 struct in_addr alias_addr)
2204 struct alias_link *link;
2206 link = AddLink(src_addr, nullAddress, alias_addr,
2212 link->flags |= LINK_PERMANENT;
2217 fprintf(stderr, "PacketAliasRedirectAddr(): "
2218 "call to AddLink() failed\n");
2227 PacketAliasRedirectDelete(struct alias_link *link)
2229 /* This is a dangerous function to put in the API,
2230 because an invalid pointer can crash the program. */
2239 PacketAliasSetAddress(struct in_addr addr)
2241 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2242 && aliasAddress.s_addr != addr.s_addr)
2245 aliasAddress = addr;
2250 PacketAliasSetTarget(struct in_addr target_addr)
2252 targetAddress = target_addr;
2257 PacketAliasInit(void)
2262 static int firstCall = 1;
2266 gettimeofday(&tv, &tz);
2267 timeStamp = tv.tv_sec;
2268 lastCleanupTime = tv.tv_sec;
2269 houseKeepingResidual = 0;
2271 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2272 linkTableOut[i] = NULL;
2273 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2274 linkTableIn[i] = NULL;
2276 atexit(PacketAliasUninit);
2286 aliasAddress.s_addr = INADDR_ANY;
2287 targetAddress.s_addr = INADDR_ANY;
2293 fragmentIdLinkCount = 0;
2294 fragmentPtrLinkCount = 0;
2299 packetAliasMode = PKT_ALIAS_SAME_PORTS
2300 | PKT_ALIAS_USE_SOCKETS
2301 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2305 PacketAliasUninit(void) {
2309 UninitPacketAliasLog();
2316 /* Change mode for some operations */
2319 unsigned int flags, /* Which state to bring flags to */
2320 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2321 probe for flag values) */
2324 /* Enable logging? */
2325 if (flags & mask & PKT_ALIAS_LOG)
2327 InitPacketAliasLog(); /* Do the enable */
2329 /* _Disable_ logging? */
2330 if (~flags & mask & PKT_ALIAS_LOG) {
2331 UninitPacketAliasLog();
2335 /* Start punching holes in the firewall? */
2336 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2339 /* Stop punching holes in the firewall? */
2340 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2345 /* Other flags can be set/cleared without special action */
2346 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2347 return packetAliasMode;
2352 PacketAliasCheckNewLink(void)
2354 return newDefaultLink;
2361 Code to support firewall punching. This shouldn't really be in this
2362 file, but making variables global is evil too.
2365 /* Firewall include files */
2366 #include <sys/queue.h>
2368 #include <netinet/ip_fw.h>
2372 static void ClearAllFWHoles(void);
2374 static int fireWallBaseNum; /* The first firewall entry free for our use */
2375 static int fireWallNumNums; /* How many entries can we use? */
2376 static int fireWallActiveNum; /* Which entry did we last use? */
2377 static char *fireWallField; /* bool array for entries */
2379 #define fw_setfield(field, num) \
2382 } /*lint -save -e717 */ while(0) /*lint -restore */
2383 #define fw_clrfield(field, num) \
2386 } /*lint -save -e717 */ while(0) /*lint -restore */
2387 #define fw_tstfield(field, num) ((field)[num])
2390 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2391 fireWallBaseNum = base;
2392 fireWallNumNums = num;
2397 fireWallField = malloc(fireWallNumNums);
2398 if (fireWallField) {
2399 memset(fireWallField, 0, fireWallNumNums);
2400 if (fireWallFD < 0) {
2401 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2404 fireWallActiveNum = fireWallBaseNum;
2409 UninitPunchFW(void) {
2411 if (fireWallFD >= 0)
2415 free(fireWallField);
2416 fireWallField = NULL;
2417 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2420 /* Make a certain link go through the firewall */
2422 PunchFWHole(struct alias_link *link) {
2423 int r; /* Result code */
2424 struct ip_fw rule; /* On-the-fly built rule */
2425 int fwhole; /* Where to punch hole */
2427 /* Don't do anything unless we are asked to */
2428 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2430 link->link_type != LINK_TCP ||
2434 memset(&rule, 0, sizeof rule);
2438 /* Find empty slot */
2439 for (fwhole = fireWallActiveNum;
2440 fwhole < fireWallBaseNum + fireWallNumNums &&
2441 fw_tstfield(fireWallField, fwhole);
2444 if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2445 fw_tstfield(fireWallField, fwhole)) {
2446 for (fwhole = fireWallBaseNum;
2447 fwhole < fireWallActiveNum &&
2448 fw_tstfield(fireWallField, fwhole);
2451 if (fwhole == fireWallActiveNum) {
2452 /* No rule point empty - we can't punch more holes. */
2453 fireWallActiveNum = fireWallBaseNum;
2455 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2460 /* Start next search at next position */
2461 fireWallActiveNum = fwhole+1;
2463 /* Build generic part of the two rules */
2464 rule.fw_number = fwhole;
2465 rule.fw_nports = 1; /* Number of source ports; dest ports follow */
2466 rule.fw_flg = IP_FW_F_ACCEPT;
2467 rule.fw_prot = IPPROTO_TCP;
2468 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2469 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2471 /* Build and apply specific part of the rules */
2472 rule.fw_src = GetOriginalAddress(link);
2473 rule.fw_dst = GetDestAddress(link);
2474 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2475 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2477 /* Skip non-bound links - XXX should not be strictly necessary,
2478 but seems to leave hole if not done. Leak of non-bound links?
2479 (Code should be left even if the problem is fixed - it is a
2480 clear optimization) */
2481 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2482 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2485 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2487 rule.fw_src = GetDestAddress(link);
2488 rule.fw_dst = GetOriginalAddress(link);
2489 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2490 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2491 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2494 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2497 /* Indicate hole applied */
2498 link->data.tcp->fwhole = fwhole;
2499 fw_setfield(fireWallField, fwhole);
2502 /* Remove a hole in a firewall associated with a particular alias
2503 link. Calling this too often is harmless. */
2505 ClearFWHole(struct alias_link *link) {
2506 if (link->link_type == LINK_TCP && link->data.tcp) {
2507 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2513 memset(&rule, 0, sizeof rule);
2514 rule.fw_number = fwhole;
2515 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2517 fw_clrfield(fireWallField, fwhole);
2518 link->data.tcp->fwhole = -1;
2522 /* Clear out the entire range dedicated to firewall holes. */
2524 ClearAllFWHoles(void) {
2525 struct ip_fw rule; /* On-the-fly built rule */
2531 memset(&rule, 0, sizeof rule);
2532 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2534 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2537 memset(fireWallField, 0, fireWallNumNums);