1 /* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
33 Alias_db.c encapsulates all data structures used for storing
34 packet aliasing data. Other parts of the aliasing software
35 access data through functions provided in this file.
37 Data storage is based on the notion of a "link", which is
38 established for ICMP echo/reply packets, UDP datagrams and
39 TCP stream connections. A link stores the original source
40 and destination addresses. For UDP and TCP, it also stores
41 source and destination port numbers, as well as an alias
42 port number. Links are also used to store information about
45 There is a facility for sweeping through and deleting old
46 links as new packets are sent through. A simple timeout is
47 used for ICMP and UDP links. TCP links are left alone unless
48 there is an incomplete connection, in which case the link
49 can be deleted after a certain amount of time.
52 Initial version: August, 1996 (cjm)
54 Version 1.4: September 16, 1996 (cjm)
55 Facility for handling incoming links added.
57 Version 1.6: September 18, 1996 (cjm)
58 ICMP data handling simplified.
60 Version 1.7: January 9, 1997 (cjm)
61 Fragment handling simplified.
62 Saves pointers for unresolved fragments.
63 Permits links for unspecified remote ports
64 or unspecified remote addresses.
65 Fixed bug which did not properly zero port
66 table entries after a link was deleted.
67 Cleaned up some obsolete comments.
69 Version 1.8: January 14, 1997 (cjm)
70 Fixed data type error in StartPoint().
71 (This error did not exist prior to v1.7
72 and was discovered and fixed by Ari Suutari)
74 Version 1.9: February 1, 1997
75 Optionally, connections initiated from packet aliasing host
76 machine will will not have their port number aliased unless it
77 conflicts with an aliasing port already being used. (cjm)
79 All options earlier being #ifdef'ed are now available through
80 a new interface, SetPacketAliasMode(). This allows run time
81 control (which is now available in PPP+pktAlias through the
82 'alias' keyword). (ee)
84 Added ability to create an alias port without
85 either destination address or port specified.
86 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
88 Removed K&R style function headers
89 and general cleanup. (ee)
91 Added packetAliasMode to replace compiler #defines's (ee)
93 Allocates sockets for partially specified
94 ports if ALIAS_USE_SOCKETS defined. (cjm)
96 Version 2.0: March, 1997
97 SetAliasAddress() will now clean up alias links
98 if the aliasing address is changed. (cjm)
100 PacketAliasPermanentLink() function added to support permanent
101 links. (J. Fortes suggested the need for this.)
104 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
106 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
109 These permanent links allow for incoming connections to
110 machines on the local network. They can be given with a
111 user-chosen amount of specificity, with increasing specificity
112 meaning more security. (cjm)
114 Quite a bit of rework to the basic engine. The portTable[]
115 array, which kept track of which ports were in use was replaced
116 by a table/linked list structure. (cjm)
118 SetExpire() function added. (cjm)
120 DeleteLink() no longer frees memory association with a pointer
121 to a fragment (this bug was first recognized by E. Eklund in
124 Version 2.1: May, 1997 (cjm)
125 Packet aliasing engine reworked so that it can handle
126 multiple external addresses rather than just a single
129 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
130 added to the API. The first function is a more generalized
131 version of PacketAliasPermanentLink(). The second function
132 implements static network address translation.
134 Version 3.2: July, 2000 (salander and satoh)
135 Added FindNewPortGroup to get contiguous range of port values.
137 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
138 link but not actually add one.
140 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
141 except that the alias port (from FindNewPortGroup) is provided
144 See HISTORY file for additional revisions.
148 /* System include files */
154 #include <sys/queue.h>
155 #include <sys/socket.h>
156 #include <sys/time.h>
157 #include <sys/types.h>
159 /* BSD network include files */
160 #include <netinet/in_systm.h>
161 #include <netinet/in.h>
162 #include <netinet/ip.h>
163 #include <netinet/tcp.h>
164 #include <arpa/inet.h>
167 #include "alias_local.h"
172 Constants (note: constants are also defined
173 near relevant functions or structs)
176 /* Sizes of input and output link tables */
177 #define LINK_TABLE_OUT_SIZE 101
178 #define LINK_TABLE_IN_SIZE 4001
180 /* Parameters used for cleanup of expired links */
181 #define ALIAS_CLEANUP_INTERVAL_SECS 60
182 #define ALIAS_CLEANUP_MAX_SPOKES 30
184 /* Timeouts (in seconds) for different link types */
185 #define ICMP_EXPIRE_TIME 60
186 #define UDP_EXPIRE_TIME 60
187 #define PROTO_EXPIRE_TIME 60
188 #define FRAGMENT_ID_EXPIRE_TIME 10
189 #define FRAGMENT_PTR_EXPIRE_TIME 30
191 /* TCP link expire time for different cases */
192 /* When the link has been used and closed - minimal grace time to
193 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
194 #ifndef TCP_EXPIRE_DEAD
195 # define TCP_EXPIRE_DEAD 10
198 /* When the link has been used and closed on one side - the other side
199 is allowed to still send data */
200 #ifndef TCP_EXPIRE_SINGLEDEAD
201 # define TCP_EXPIRE_SINGLEDEAD 90
204 /* When the link isn't yet up */
205 #ifndef TCP_EXPIRE_INITIAL
206 # define TCP_EXPIRE_INITIAL 300
209 /* When the link is up */
210 #ifndef TCP_EXPIRE_CONNECTED
211 # define TCP_EXPIRE_CONNECTED 86400
215 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
216 These constants can be anything except zero, which indicates an
217 unknown port number. */
219 #define NO_DEST_PORT 1
220 #define NO_SRC_PORT 1
226 The fundamental data structure used in this program is
227 "struct alias_link". Whenever a TCP connection is made,
228 a UDP datagram is sent out, or an ICMP echo request is made,
229 a link record is made (if it has not already been created).
230 The link record is identified by the source address/port
231 and the destination address/port. In the case of an ICMP
232 echo request, the source port is treated as being equivalent
233 with the 16-bit ID number of the ICMP packet.
235 The link record also can store some auxiliary data. For
236 TCP connections that have had sequence and acknowledgment
237 modifications, data space is available to track these changes.
238 A state field is used to keep track in changes to the TCP
239 connection state. ID numbers of fragments can also be
240 stored in the auxiliary space. Pointers to unresolved
241 fragments can also be stored.
243 The link records support two independent chainings. Lookup
244 tables for input and out tables hold the initial pointers
245 the link chains. On input, the lookup table indexes on alias
246 port and link type. On output, the lookup table indexes on
247 source address, destination address, source port, destination
251 struct ack_data_record /* used to save changes to ACK/sequence numbers */
259 struct tcp_state /* Information about TCP connection */
261 int in; /* State for outside -> inside */
262 int out; /* State for inside -> outside */
263 int index; /* Index to ACK data array */
264 int ack_modified; /* Indicates whether ACK and sequence numbers */
268 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
269 saved for a modified TCP stream */
272 struct tcp_state state;
273 struct ack_data_record ack[N_LINK_TCP_DATA];
274 int fwhole; /* Which firewall record is used for this hole? */
277 struct server /* LSNAT server pool (circular list) */
284 struct alias_link /* Main data structure */
286 struct in_addr src_addr; /* Address and port information */
287 struct in_addr dst_addr;
288 struct in_addr alias_addr;
289 struct in_addr proxy_addr;
294 struct server *server;
296 int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */
298 /* values for link_type */
299 #define LINK_ICMP IPPROTO_ICMP
300 #define LINK_UDP IPPROTO_UDP
301 #define LINK_TCP IPPROTO_TCP
302 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
303 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
304 #define LINK_ADDR (IPPROTO_MAX + 3)
305 #define LINK_PPTP (IPPROTO_MAX + 4)
307 int flags; /* indicates special characteristics */
308 int pflags; /* protocol-specific flags */
311 #define LINK_UNKNOWN_DEST_PORT 0x01
312 #define LINK_UNKNOWN_DEST_ADDR 0x02
313 #define LINK_PERMANENT 0x04
314 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
315 #define LINK_UNFIREWALLED 0x08
317 int timestamp; /* Time link was last accessed */
318 int expire_time; /* Expire time for link */
320 int sockfd; /* socket descriptor */
322 LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */
323 LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */
325 union /* Auxiliary data */
328 struct in_addr frag_addr;
339 The global variables listed here are only accessed from
340 within alias_db.c and so are prefixed with the static
344 int packetAliasMode; /* Mode flags */
345 /* - documented in alias.h */
347 static struct in_addr aliasAddress; /* Address written onto source */
348 /* field of IP packet. */
350 static struct in_addr targetAddress; /* IP address incoming packets */
351 /* are sent to if no aliasing */
352 /* link already exists */
354 static struct in_addr nullAddress; /* Used as a dummy parameter for */
355 /* some function calls */
356 static LIST_HEAD(, alias_link)
357 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */
358 /* chains of link records. Each */
359 static LIST_HEAD(, alias_link) /* link record is doubly indexed */
360 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */
363 static int icmpLinkCount; /* Link statistics */
364 static int udpLinkCount;
365 static int tcpLinkCount;
366 static int pptpLinkCount;
367 static int protoLinkCount;
368 static int fragmentIdLinkCount;
369 static int fragmentPtrLinkCount;
370 static int sockCount;
372 static int cleanupIndex; /* Index to chain of link table */
373 /* being inspected for old links */
375 static int timeStamp; /* System time in seconds for */
378 static int lastCleanupTime; /* Last time IncrementalCleanup() */
381 static int houseKeepingResidual; /* used by HouseKeeping() */
383 static int deleteAllLinks; /* If equal to zero, DeleteLink() */
384 /* will not remove permanent links */
386 static FILE *monitorFile; /* File descriptor for link */
387 /* statistics monitoring file */
389 static int newDefaultLink; /* Indicates if a new aliasing */
390 /* link has been created after a */
391 /* call to PacketAliasIn/Out(). */
394 static int fireWallFD = -1; /* File descriptor to be able to */
395 /* control firewall. Opened by */
396 /* PacketAliasSetMode on first */
397 /* setting the PKT_ALIAS_PUNCH_FW */
407 /* Internal utility routines (used only in alias_db.c)
409 Lookup table starting points:
410 StartPointIn() -- link table initial search point for
412 StartPointOut() -- link table initial search point for
416 SeqDiff() -- difference between two TCP sequences
417 ShowAliasStats() -- send alias statistics to a monitor file
421 /* Local prototypes */
422 static u_int StartPointIn(struct in_addr, u_short, int);
424 static u_int StartPointOut(struct in_addr, struct in_addr,
425 u_short, u_short, int);
427 static int SeqDiff(u_long, u_long);
429 static void ShowAliasStats(void);
432 /* Firewall control */
433 static void InitPunchFW(void);
434 static void UninitPunchFW(void);
435 static void ClearFWHole(struct alias_link *link);
438 /* Log file control */
439 static void InitPacketAliasLog(void);
440 static void UninitPacketAliasLog(void);
443 StartPointIn(struct in_addr alias_addr,
449 n = alias_addr.s_addr;
450 if (link_type != LINK_PPTP)
453 return(n % LINK_TABLE_IN_SIZE);
458 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
459 u_short src_port, u_short dst_port, int link_type)
464 n += dst_addr.s_addr;
465 if (link_type != LINK_PPTP) {
471 return(n % LINK_TABLE_OUT_SIZE);
476 SeqDiff(u_long x, u_long y)
478 /* Return the difference between two TCP sequence numbers */
481 This function is encapsulated in case there are any unusual
482 arithmetic conditions that need to be considered.
485 return (ntohl(y) - ntohl(x));
492 /* Used for debugging */
496 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
503 fragmentPtrLinkCount);
505 fprintf(monitorFile, " / tot=%d (sock=%d)\n",
506 icmpLinkCount + udpLinkCount
510 + fragmentIdLinkCount
511 + fragmentPtrLinkCount,
522 /* Internal routines for finding, deleting and adding links
525 GetNewPort() -- find and reserve new alias port number
526 GetSocket() -- try to allocate a socket for a given port
528 Link creation and deletion:
529 CleanupAliasData() - remove all link chains from lookup table
530 IncrementalCleanup() - look for stale links in a single chain
531 DeleteLink() - remove link
533 ReLink() - change link
536 FindLinkOut() - find link for outgoing packets
537 FindLinkIn() - find link for incoming packets
540 FindNewPortGroup() - find an available group of ports
543 /* Local prototypes */
544 static int GetNewPort(struct alias_link *, int);
546 static u_short GetSocket(u_short, int *, int);
548 static void CleanupAliasData(void);
550 static void IncrementalCleanup(void);
552 static void DeleteLink(struct alias_link *);
554 static struct alias_link *
555 AddLink(struct in_addr, struct in_addr, struct in_addr,
556 u_short, u_short, int, int);
558 static struct alias_link *
559 ReLink(struct alias_link *,
560 struct in_addr, struct in_addr, struct in_addr,
561 u_short, u_short, int, int);
563 static struct alias_link *
564 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int);
566 static struct alias_link *
567 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
570 #define ALIAS_PORT_BASE 0x08000
571 #define ALIAS_PORT_MASK 0x07fff
572 #define ALIAS_PORT_MASK_EVEN 0x07ffe
573 #define GET_NEW_PORT_MAX_ATTEMPTS 20
575 #define GET_ALIAS_PORT -1
576 #define GET_ALIAS_ID GET_ALIAS_PORT
578 #define FIND_EVEN_ALIAS_BASE 1
580 /* GetNewPort() allocates port numbers. Note that if a port number
581 is already in use, that does not mean that it cannot be used by
582 another link concurrently. This is because GetNewPort() looks for
583 unused triplets: (dest addr, dest port, alias port). */
586 GetNewPort(struct alias_link *link, int alias_port_param)
594 Description of alias_port_param for GetNewPort(). When
595 this parameter is zero or positive, it precisely specifies
596 the port number. GetNewPort() will return this number
597 without check that it is in use.
599 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
600 selected port number.
603 if (alias_port_param == GET_ALIAS_PORT)
606 * The aliasing port is automatically selected
607 * by one of two methods below:
609 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
611 if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
614 * When the PKT_ALIAS_SAME_PORTS option is
615 * chosen, the first try will be the
616 * actual source port. If this is already
617 * in use, the remainder of the trials
620 port_net = link->src_port;
621 port_sys = ntohs(port_net);
625 /* First trial and all subsequent are random. */
626 port_sys = random() & ALIAS_PORT_MASK;
627 port_sys += ALIAS_PORT_BASE;
628 port_net = htons(port_sys);
631 else if (alias_port_param >= 0 && alias_port_param < 0x10000)
633 link->alias_port = (u_short) alias_port_param;
639 fprintf(stderr, "PacketAlias/GetNewPort(): ");
640 fprintf(stderr, "input parameter error\n");
646 /* Port number search */
647 for (i=0; i<max_trials; i++)
650 struct alias_link *search_result;
652 search_result = FindLinkIn(link->dst_addr, link->alias_addr,
653 link->dst_port, port_net,
656 if (search_result == NULL)
658 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED)
659 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
666 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS)
667 && (link->flags & LINK_PARTIALLY_SPECIFIED)
668 && ((link->link_type == LINK_TCP) ||
669 (link->link_type == LINK_UDP)))
671 if (GetSocket(port_net, &link->sockfd, link->link_type))
673 link->alias_port = port_net;
679 link->alias_port = port_net;
684 port_sys = random() & ALIAS_PORT_MASK;
685 port_sys += ALIAS_PORT_BASE;
686 port_net = htons(port_sys);
690 fprintf(stderr, "PacketAlias/GetnewPort(): ");
691 fprintf(stderr, "could not find free port\n");
699 GetSocket(u_short port_net, int *sockfd, int link_type)
703 struct sockaddr_in sock_addr;
705 if (link_type == LINK_TCP)
706 sock = socket(AF_INET, SOCK_STREAM, 0);
707 else if (link_type == LINK_UDP)
708 sock = socket(AF_INET, SOCK_DGRAM, 0);
712 fprintf(stderr, "PacketAlias/GetSocket(): ");
713 fprintf(stderr, "incorrect link type\n");
721 fprintf(stderr, "PacketAlias/GetSocket(): ");
722 fprintf(stderr, "socket() error %d\n", *sockfd);
727 sock_addr.sin_family = AF_INET;
728 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
729 sock_addr.sin_port = port_net;
732 (struct sockaddr *) &sock_addr,
748 /* FindNewPortGroup() returns a base port number for an available
749 range of contiguous port numbers. Note that if a port number
750 is already in use, that does not mean that it cannot be used by
751 another link concurrently. This is because FindNewPortGroup()
752 looks for unused triplets: (dest addr, dest port, alias port). */
755 FindNewPortGroup(struct in_addr dst_addr,
756 struct in_addr alias_addr,
769 * Get link_type from protocol
775 link_type = LINK_UDP;
778 link_type = LINK_TCP;
786 * The aliasing port is automatically selected
787 * by one of two methods below:
789 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
791 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) {
793 * When the ALIAS_SAME_PORTS option is
794 * chosen, the first try will be the
795 * actual source port. If this is already
796 * in use, the remainder of the trials
799 port_sys = ntohs(src_port);
803 /* First trial and all subsequent are random. */
804 if (align == FIND_EVEN_ALIAS_BASE)
805 port_sys = random() & ALIAS_PORT_MASK_EVEN;
807 port_sys = random() & ALIAS_PORT_MASK;
809 port_sys += ALIAS_PORT_BASE;
812 /* Port number search */
813 for (i = 0; i < max_trials; i++) {
815 struct alias_link *search_result;
817 for (j = 0; j < port_count; j++)
818 if (0 != (search_result = FindLinkIn(dst_addr, alias_addr,
819 dst_port, htons(port_sys + j),
823 /* Found a good range, return base */
825 return (htons(port_sys));
827 /* Find a new base to try */
828 if (align == FIND_EVEN_ALIAS_BASE)
829 port_sys = random() & ALIAS_PORT_MASK_EVEN;
831 port_sys = random() & ALIAS_PORT_MASK;
833 port_sys += ALIAS_PORT_BASE;
837 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
838 fprintf(stderr, "could not find free port(s)\n");
845 CleanupAliasData(void)
847 struct alias_link *link;
851 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
853 link = LIST_FIRST(&linkTableOut[i]);
856 struct alias_link *link_next;
857 link_next = LIST_NEXT(link, list_out);
869 IncrementalCleanup(void)
872 struct alias_link *link;
875 link = LIST_FIRST(&linkTableOut[cleanupIndex++]);
879 struct alias_link *link_next;
881 link_next = LIST_NEXT(link, list_out);
882 idelta = timeStamp - link->timestamp;
883 switch (link->link_type)
886 if (idelta > link->expire_time)
888 struct tcp_dat *tcp_aux;
890 tcp_aux = link->data.tcp;
891 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
892 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
900 if (idelta > link->expire_time)
910 if (cleanupIndex == LINK_TABLE_OUT_SIZE)
915 DeleteLink(struct alias_link *link)
918 /* Don't do anything if the link is marked permanent */
919 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
923 /* Delete associated firewall hole, if any */
927 /* Free memory allocated for LSNAT server pool */
928 if (link->server != NULL) {
929 struct server *head, *curr, *next;
931 head = curr = link->server;
935 } while ((curr = next) != head);
938 /* Adjust output table pointers */
939 LIST_REMOVE(link, list_out);
941 /* Adjust input table pointers */
942 LIST_REMOVE(link, list_in);
944 /* Close socket, if one has been allocated */
945 if (link->sockfd != -1)
951 /* Link-type dependent cleanup */
952 switch(link->link_type)
962 free(link->data.tcp);
967 case LINK_FRAGMENT_ID:
968 fragmentIdLinkCount--;
970 case LINK_FRAGMENT_PTR:
971 fragmentPtrLinkCount--;
972 if (link->data.frag_ptr != NULL)
973 free(link->data.frag_ptr);
985 /* Write statistics, if logging enabled */
986 if (packetAliasMode & PKT_ALIAS_LOG)
993 static struct alias_link *
994 AddLink(struct in_addr src_addr,
995 struct in_addr dst_addr,
996 struct in_addr alias_addr,
999 int alias_port_param, /* if less than zero, alias */
1000 int link_type) /* port will be automatically */
1001 { /* chosen. If greater than */
1002 u_int start_point; /* zero, equal to alias port */
1003 struct alias_link *link;
1005 link = malloc(sizeof(struct alias_link));
1008 /* Basic initialization */
1009 link->src_addr = src_addr;
1010 link->dst_addr = dst_addr;
1011 link->alias_addr = alias_addr;
1012 link->proxy_addr.s_addr = INADDR_ANY;
1013 link->src_port = src_port;
1014 link->dst_port = dst_port;
1015 link->proxy_port = 0;
1016 link->server = NULL;
1017 link->link_type = link_type;
1021 link->timestamp = timeStamp;
1023 /* Expiration time */
1027 link->expire_time = ICMP_EXPIRE_TIME;
1030 link->expire_time = UDP_EXPIRE_TIME;
1033 link->expire_time = TCP_EXPIRE_INITIAL;
1036 link->flags |= LINK_PERMANENT; /* no timeout. */
1038 case LINK_FRAGMENT_ID:
1039 link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1041 case LINK_FRAGMENT_PTR:
1042 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1047 link->expire_time = PROTO_EXPIRE_TIME;
1051 /* Determine alias flags */
1052 if (dst_addr.s_addr == INADDR_ANY)
1053 link->flags |= LINK_UNKNOWN_DEST_ADDR;
1055 link->flags |= LINK_UNKNOWN_DEST_PORT;
1057 /* Determine alias port */
1058 if (GetNewPort(link, alias_port_param) != 0)
1064 /* Link-type dependent initialization */
1067 struct tcp_dat *aux_tcp;
1076 aux_tcp = malloc(sizeof(struct tcp_dat));
1077 if (aux_tcp != NULL)
1082 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1083 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1084 aux_tcp->state.index = 0;
1085 aux_tcp->state.ack_modified = 0;
1086 for (i=0; i<N_LINK_TCP_DATA; i++)
1087 aux_tcp->ack[i].active = 0;
1088 aux_tcp->fwhole = -1;
1089 link->data.tcp = aux_tcp;
1094 fprintf(stderr, "PacketAlias/AddLink: ");
1095 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1104 case LINK_FRAGMENT_ID:
1105 fragmentIdLinkCount++;
1107 case LINK_FRAGMENT_PTR:
1108 fragmentPtrLinkCount++;
1117 /* Set up pointers for output lookup table */
1118 start_point = StartPointOut(src_addr, dst_addr,
1119 src_port, dst_port, link_type);
1120 LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out);
1122 /* Set up pointers for input lookup table */
1123 start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1124 LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in);
1129 fprintf(stderr, "PacketAlias/AddLink(): ");
1130 fprintf(stderr, "malloc() call failed.\n");
1134 if (packetAliasMode & PKT_ALIAS_LOG)
1142 static struct alias_link *
1143 ReLink(struct alias_link *old_link,
1144 struct in_addr src_addr,
1145 struct in_addr dst_addr,
1146 struct in_addr alias_addr,
1149 int alias_port_param, /* if less than zero, alias */
1150 int link_type) /* port will be automatically */
1151 { /* chosen. If greater than */
1152 struct alias_link *new_link; /* zero, equal to alias port */
1154 new_link = AddLink(src_addr, dst_addr, alias_addr,
1155 src_port, dst_port, alias_port_param,
1158 if (new_link != NULL &&
1159 old_link->link_type == LINK_TCP &&
1160 old_link->data.tcp->fwhole > 0) {
1161 PunchFWHole(new_link);
1164 DeleteLink(old_link);
1168 static struct alias_link *
1169 _FindLinkOut(struct in_addr src_addr,
1170 struct in_addr dst_addr,
1174 int replace_partial_links)
1177 struct alias_link *link;
1179 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1180 LIST_FOREACH(link, &linkTableOut[i], list_out)
1182 if (link->src_addr.s_addr == src_addr.s_addr
1183 && link->server == NULL
1184 && link->dst_addr.s_addr == dst_addr.s_addr
1185 && link->dst_port == dst_port
1186 && link->src_port == src_port
1187 && link->link_type == link_type)
1189 link->timestamp = timeStamp;
1194 /* Search for partially specified links. */
1195 if (link == NULL && replace_partial_links)
1197 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1199 link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1202 link = _FindLinkOut(src_addr, nullAddress, src_port,
1203 dst_port, link_type, 0);
1206 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1208 link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1214 src_addr, dst_addr, link->alias_addr,
1215 src_port, dst_port, link->alias_port,
1223 static struct alias_link *
1224 FindLinkOut(struct in_addr src_addr,
1225 struct in_addr dst_addr,
1229 int replace_partial_links)
1231 struct alias_link *link;
1233 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1234 link_type, replace_partial_links);
1238 /* The following allows permanent links to be
1239 specified as using the default source address
1240 (i.e. device interface address) without knowing
1241 in advance what that address is. */
1242 if (aliasAddress.s_addr != 0 &&
1243 src_addr.s_addr == aliasAddress.s_addr)
1245 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1246 link_type, replace_partial_links);
1254 static struct alias_link *
1255 _FindLinkIn(struct in_addr dst_addr,
1256 struct in_addr alias_addr,
1260 int replace_partial_links)
1264 struct alias_link *link;
1265 struct alias_link *link_fully_specified;
1266 struct alias_link *link_unknown_all;
1267 struct alias_link *link_unknown_dst_addr;
1268 struct alias_link *link_unknown_dst_port;
1270 /* Initialize pointers */
1271 link_fully_specified = NULL;
1272 link_unknown_all = NULL;
1273 link_unknown_dst_addr = NULL;
1274 link_unknown_dst_port = NULL;
1276 /* If either the dest addr or port is unknown, the search
1277 loop will have to know about this. */
1280 if (dst_addr.s_addr == INADDR_ANY)
1281 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1283 flags_in |= LINK_UNKNOWN_DEST_PORT;
1286 start_point = StartPointIn(alias_addr, alias_port, link_type);
1287 LIST_FOREACH(link, &linkTableIn[start_point], list_in)
1291 flags = flags_in | link->flags;
1292 if (!(flags & LINK_PARTIALLY_SPECIFIED))
1294 if (link->alias_addr.s_addr == alias_addr.s_addr
1295 && link->alias_port == alias_port
1296 && link->dst_addr.s_addr == dst_addr.s_addr
1297 && link->dst_port == dst_port
1298 && link->link_type == link_type)
1300 link_fully_specified = link;
1304 else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1305 && (flags & LINK_UNKNOWN_DEST_PORT))
1307 if (link->alias_addr.s_addr == alias_addr.s_addr
1308 && link->alias_port == alias_port
1309 && link->link_type == link_type)
1311 if (link_unknown_all == NULL)
1312 link_unknown_all = link;
1315 else if (flags & LINK_UNKNOWN_DEST_ADDR)
1317 if (link->alias_addr.s_addr == alias_addr.s_addr
1318 && link->alias_port == alias_port
1319 && link->link_type == link_type
1320 && link->dst_port == dst_port)
1322 if (link_unknown_dst_addr == NULL)
1323 link_unknown_dst_addr = link;
1326 else if (flags & LINK_UNKNOWN_DEST_PORT)
1328 if (link->alias_addr.s_addr == alias_addr.s_addr
1329 && link->alias_port == alias_port
1330 && link->link_type == link_type
1331 && link->dst_addr.s_addr == dst_addr.s_addr)
1333 if (link_unknown_dst_port == NULL)
1334 link_unknown_dst_port = link;
1341 if (link_fully_specified != NULL)
1343 link_fully_specified->timestamp = timeStamp;
1344 link = link_fully_specified;
1346 else if (link_unknown_dst_port != NULL)
1347 link = link_unknown_dst_port;
1348 else if (link_unknown_dst_addr != NULL)
1349 link = link_unknown_dst_addr;
1350 else if (link_unknown_all != NULL)
1351 link = link_unknown_all;
1355 if (replace_partial_links &&
1356 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
1358 struct in_addr src_addr;
1361 if (link->server != NULL) { /* LSNAT link */
1362 src_addr = link->server->addr;
1363 src_port = link->server->port;
1364 link->server = link->server->next;
1366 src_addr = link->src_addr;
1367 src_port = link->src_port;
1371 src_addr, dst_addr, alias_addr,
1372 src_port, dst_port, alias_port,
1379 static struct alias_link *
1380 FindLinkIn(struct in_addr dst_addr,
1381 struct in_addr alias_addr,
1385 int replace_partial_links)
1387 struct alias_link *link;
1389 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1390 link_type, replace_partial_links);
1394 /* The following allows permanent links to be
1395 specified as using the default aliasing address
1396 (i.e. device interface address) without knowing
1397 in advance what that address is. */
1398 if (aliasAddress.s_addr != 0 &&
1399 alias_addr.s_addr == aliasAddress.s_addr)
1401 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1402 link_type, replace_partial_links);
1412 /* External routines for finding/adding links
1414 -- "external" means outside alias_db.c, but within alias*.c --
1416 FindIcmpIn(), FindIcmpOut()
1417 FindFragmentIn1(), FindFragmentIn2()
1418 AddFragmentPtrLink(), FindFragmentPtr()
1419 FindProtoIn(), FindProtoOut()
1420 FindUdpTcpIn(), FindUdpTcpOut()
1421 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1422 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1423 FindOriginalAddress(), FindAliasAddress()
1425 (prototypes in alias_local.h)
1430 FindIcmpIn(struct in_addr dst_addr,
1431 struct in_addr alias_addr,
1435 struct alias_link *link;
1437 link = FindLinkIn(dst_addr, alias_addr,
1438 NO_DEST_PORT, id_alias,
1440 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1442 struct in_addr target_addr;
1444 target_addr = FindOriginalAddress(alias_addr);
1445 link = AddLink(target_addr, dst_addr, alias_addr,
1446 id_alias, NO_DEST_PORT, id_alias,
1455 FindIcmpOut(struct in_addr src_addr,
1456 struct in_addr dst_addr,
1460 struct alias_link * link;
1462 link = FindLinkOut(src_addr, dst_addr,
1465 if (link == NULL && create)
1467 struct in_addr alias_addr;
1469 alias_addr = FindAliasAddress(src_addr);
1470 link = AddLink(src_addr, dst_addr, alias_addr,
1471 id, NO_DEST_PORT, GET_ALIAS_ID,
1480 FindFragmentIn1(struct in_addr dst_addr,
1481 struct in_addr alias_addr,
1484 struct alias_link *link;
1486 link = FindLinkIn(dst_addr, alias_addr,
1487 NO_DEST_PORT, ip_id,
1488 LINK_FRAGMENT_ID, 0);
1492 link = AddLink(nullAddress, dst_addr, alias_addr,
1493 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1502 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */
1503 struct in_addr alias_addr, /* is not found. */
1506 return FindLinkIn(dst_addr, alias_addr,
1507 NO_DEST_PORT, ip_id,
1508 LINK_FRAGMENT_ID, 0);
1513 AddFragmentPtrLink(struct in_addr dst_addr,
1516 return AddLink(nullAddress, dst_addr, nullAddress,
1517 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1523 FindFragmentPtr(struct in_addr dst_addr,
1526 return FindLinkIn(dst_addr, nullAddress,
1527 NO_DEST_PORT, ip_id,
1528 LINK_FRAGMENT_PTR, 0);
1533 FindProtoIn(struct in_addr dst_addr,
1534 struct in_addr alias_addr,
1537 struct alias_link *link;
1539 link = FindLinkIn(dst_addr, alias_addr,
1543 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1545 struct in_addr target_addr;
1547 target_addr = FindOriginalAddress(alias_addr);
1548 link = AddLink(target_addr, dst_addr, alias_addr,
1549 NO_SRC_PORT, NO_DEST_PORT, 0,
1558 FindProtoOut(struct in_addr src_addr,
1559 struct in_addr dst_addr,
1562 struct alias_link *link;
1564 link = FindLinkOut(src_addr, dst_addr,
1565 NO_SRC_PORT, NO_DEST_PORT,
1570 struct in_addr alias_addr;
1572 alias_addr = FindAliasAddress(src_addr);
1573 link = AddLink(src_addr, dst_addr, alias_addr,
1574 NO_SRC_PORT, NO_DEST_PORT, 0,
1583 FindUdpTcpIn(struct in_addr dst_addr,
1584 struct in_addr alias_addr,
1591 struct alias_link *link;
1596 link_type = LINK_UDP;
1599 link_type = LINK_TCP;
1606 link = FindLinkIn(dst_addr, alias_addr,
1607 dst_port, alias_port,
1610 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1612 struct in_addr target_addr;
1614 target_addr = FindOriginalAddress(alias_addr);
1615 link = AddLink(target_addr, dst_addr, alias_addr,
1616 alias_port, dst_port, alias_port,
1625 FindUdpTcpOut(struct in_addr src_addr,
1626 struct in_addr dst_addr,
1633 struct alias_link *link;
1638 link_type = LINK_UDP;
1641 link_type = LINK_TCP;
1648 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create);
1650 if (link == NULL && create)
1652 struct in_addr alias_addr;
1654 alias_addr = FindAliasAddress(src_addr);
1655 link = AddLink(src_addr, dst_addr, alias_addr,
1656 src_port, dst_port, GET_ALIAS_PORT,
1665 AddPptp(struct in_addr src_addr,
1666 struct in_addr dst_addr,
1667 struct in_addr alias_addr,
1668 u_int16_t src_call_id)
1670 struct alias_link *link;
1672 link = AddLink(src_addr, dst_addr, alias_addr,
1673 src_call_id, 0, GET_ALIAS_PORT,
1681 FindPptpOutByCallId(struct in_addr src_addr,
1682 struct in_addr dst_addr,
1683 u_int16_t src_call_id)
1686 struct alias_link *link;
1688 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1689 LIST_FOREACH(link, &linkTableOut[i], list_out)
1690 if (link->link_type == LINK_PPTP &&
1691 link->src_addr.s_addr == src_addr.s_addr &&
1692 link->dst_addr.s_addr == dst_addr.s_addr &&
1693 link->src_port == src_call_id)
1701 FindPptpOutByPeerCallId(struct in_addr src_addr,
1702 struct in_addr dst_addr,
1703 u_int16_t dst_call_id)
1706 struct alias_link *link;
1708 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1709 LIST_FOREACH(link, &linkTableOut[i], list_out)
1710 if (link->link_type == LINK_PPTP &&
1711 link->src_addr.s_addr == src_addr.s_addr &&
1712 link->dst_addr.s_addr == dst_addr.s_addr &&
1713 link->dst_port == dst_call_id)
1721 FindPptpInByCallId(struct in_addr dst_addr,
1722 struct in_addr alias_addr,
1723 u_int16_t dst_call_id)
1726 struct alias_link *link;
1728 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1729 LIST_FOREACH(link, &linkTableIn[i], list_in)
1730 if (link->link_type == LINK_PPTP &&
1731 link->dst_addr.s_addr == dst_addr.s_addr &&
1732 link->alias_addr.s_addr == alias_addr.s_addr &&
1733 link->dst_port == dst_call_id)
1741 FindPptpInByPeerCallId(struct in_addr dst_addr,
1742 struct in_addr alias_addr,
1743 u_int16_t alias_call_id)
1745 struct alias_link *link;
1747 link = FindLinkIn(dst_addr, alias_addr,
1748 0/* any */, alias_call_id,
1757 FindRtspOut(struct in_addr src_addr,
1758 struct in_addr dst_addr,
1764 struct alias_link *link;
1769 link_type = LINK_UDP;
1772 link_type = LINK_TCP;
1779 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
1783 struct in_addr alias_addr;
1785 alias_addr = FindAliasAddress(src_addr);
1786 link = AddLink(src_addr, dst_addr, alias_addr,
1787 src_port, 0, alias_port,
1796 FindOriginalAddress(struct in_addr alias_addr)
1798 struct alias_link *link;
1800 link = FindLinkIn(nullAddress, alias_addr,
1801 0, 0, LINK_ADDR, 0);
1805 if (targetAddress.s_addr == INADDR_ANY)
1807 else if (targetAddress.s_addr == INADDR_NONE)
1808 return aliasAddress;
1810 return targetAddress;
1814 if (link->server != NULL) { /* LSNAT link */
1815 struct in_addr src_addr;
1817 src_addr = link->server->addr;
1818 link->server = link->server->next;
1820 } else if (link->src_addr.s_addr == INADDR_ANY)
1821 return aliasAddress;
1823 return link->src_addr;
1829 FindAliasAddress(struct in_addr original_addr)
1831 struct alias_link *link;
1833 link = FindLinkOut(original_addr, nullAddress,
1834 0, 0, LINK_ADDR, 0);
1837 return aliasAddress;
1841 if (link->alias_addr.s_addr == INADDR_ANY)
1842 return aliasAddress;
1844 return link->alias_addr;
1849 /* External routines for getting or changing link data
1850 (external to alias_db.c, but internal to alias*.c)
1852 SetFragmentData(), GetFragmentData()
1853 SetFragmentPtr(), GetFragmentPtr()
1854 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1855 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1856 GetOriginalPort(), GetAliasPort()
1857 SetAckModified(), GetAckModified()
1858 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1859 SetProtocolFlags(), GetProtocolFlags()
1865 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1867 link->data.frag_addr = src_addr;
1872 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1874 *src_addr = link->data.frag_addr;
1879 SetFragmentPtr(struct alias_link *link, char *fptr)
1881 link->data.frag_ptr = fptr;
1886 GetFragmentPtr(struct alias_link *link, char **fptr)
1888 *fptr = link->data.frag_ptr;
1893 SetStateIn(struct alias_link *link, int state)
1895 /* TCP input state */
1897 case ALIAS_TCP_STATE_DISCONNECTED:
1898 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1899 link->expire_time = TCP_EXPIRE_DEAD;
1901 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1903 case ALIAS_TCP_STATE_CONNECTED:
1904 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1905 link->expire_time = TCP_EXPIRE_CONNECTED;
1910 link->data.tcp->state.in = state;
1915 SetStateOut(struct alias_link *link, int state)
1917 /* TCP output state */
1919 case ALIAS_TCP_STATE_DISCONNECTED:
1920 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1921 link->expire_time = TCP_EXPIRE_DEAD;
1923 link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1925 case ALIAS_TCP_STATE_CONNECTED:
1926 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1927 link->expire_time = TCP_EXPIRE_CONNECTED;
1932 link->data.tcp->state.out = state;
1937 GetStateIn(struct alias_link *link)
1939 /* TCP input state */
1940 return link->data.tcp->state.in;
1945 GetStateOut(struct alias_link *link)
1947 /* TCP output state */
1948 return link->data.tcp->state.out;
1953 GetOriginalAddress(struct alias_link *link)
1955 if (link->src_addr.s_addr == INADDR_ANY)
1956 return aliasAddress;
1958 return(link->src_addr);
1963 GetDestAddress(struct alias_link *link)
1965 return(link->dst_addr);
1970 GetAliasAddress(struct alias_link *link)
1972 if (link->alias_addr.s_addr == INADDR_ANY)
1973 return aliasAddress;
1975 return link->alias_addr;
1980 GetDefaultAliasAddress()
1982 return aliasAddress;
1987 SetDefaultAliasAddress(struct in_addr alias_addr)
1989 aliasAddress = alias_addr;
1994 GetOriginalPort(struct alias_link *link)
1996 return(link->src_port);
2001 GetAliasPort(struct alias_link *link)
2003 return(link->alias_port);
2008 GetDestPort(struct alias_link *link)
2010 return(link->dst_port);
2015 SetAckModified(struct alias_link *link)
2017 /* Indicate that ACK numbers have been modified in a TCP connection */
2018 link->data.tcp->state.ack_modified = 1;
2023 GetProxyAddress(struct alias_link *link)
2025 return link->proxy_addr;
2030 SetProxyAddress(struct alias_link *link, struct in_addr addr)
2032 link->proxy_addr = addr;
2037 GetProxyPort(struct alias_link *link)
2039 return link->proxy_port;
2044 SetProxyPort(struct alias_link *link, u_short port)
2046 link->proxy_port = port;
2051 GetAckModified(struct alias_link *link)
2053 /* See if ACK numbers have been modified */
2054 return link->data.tcp->state.ack_modified;
2059 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
2062 Find out how much the ACK number has been altered for an incoming
2063 TCP packet. To do this, a circular list of ACK numbers where the TCP
2064 packet size was altered is searched.
2069 int delta, ack_diff_min;
2072 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2077 for (i=0; i<N_LINK_TCP_DATA; i++)
2079 struct ack_data_record x;
2081 x = link->data.tcp->ack[i];
2086 ack_diff = SeqDiff(x.ack_new, ack);
2089 if (ack_diff_min >= 0)
2091 if (ack_diff < ack_diff_min)
2094 ack_diff_min = ack_diff;
2100 ack_diff_min = ack_diff;
2110 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
2113 Find out how much the sequence number has been altered for an outgoing
2114 TCP packet. To do this, a circular list of ACK numbers where the TCP
2115 packet size was altered is searched.
2120 int delta, seq_diff_min;
2123 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2128 for (i=0; i<N_LINK_TCP_DATA; i++)
2130 struct ack_data_record x;
2132 x = link->data.tcp->ack[i];
2137 seq_diff = SeqDiff(x.ack_old, seq);
2140 if (seq_diff_min >= 0)
2142 if (seq_diff < seq_diff_min)
2145 seq_diff_min = seq_diff;
2151 seq_diff_min = seq_diff;
2161 AddSeq(struct ip *pip, struct alias_link *link, int delta)
2164 When a TCP packet has been altered in length, save this
2165 information in a circular list. If enough packets have
2166 been altered, then this list will begin to overwrite itself.
2170 struct ack_data_record x;
2171 int hlen, tlen, dlen;
2174 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2176 hlen = (pip->ip_hl + tc->th_off) << 2;
2177 tlen = ntohs(pip->ip_len);
2180 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2181 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2185 i = link->data.tcp->state.index;
2186 link->data.tcp->ack[i] = x;
2189 if (i == N_LINK_TCP_DATA)
2190 link->data.tcp->state.index = 0;
2192 link->data.tcp->state.index = i;
2196 SetExpire(struct alias_link *link, int expire)
2200 link->flags &= ~LINK_PERMANENT;
2203 else if (expire == -1)
2205 link->flags |= LINK_PERMANENT;
2207 else if (expire > 0)
2209 link->expire_time = expire;
2214 fprintf(stderr, "PacketAlias/SetExpire(): ");
2215 fprintf(stderr, "error in expire parameter\n");
2221 ClearCheckNewLink(void)
2227 SetProtocolFlags(struct alias_link *link, int pflags)
2230 link->pflags = pflags;;
2234 GetProtocolFlags(struct alias_link *link)
2237 return (link->pflags);
2241 SetDestCallId(struct alias_link *link, u_int16_t cid)
2245 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2246 link->src_port, cid, link->alias_port, link->link_type);
2251 /* Miscellaneous Functions
2254 InitPacketAliasLog()
2255 UninitPacketAliasLog()
2259 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2260 is called to find and remove timed-out aliasing links. Logic exists
2261 to sweep through the entire table and linked list structure
2264 (prototype in alias_local.h)
2275 * Save system time (seconds) in global variable timeStamp for
2276 * use by other functions. This is done so as not to unnecessarily
2277 * waste timeline by making system calls.
2279 gettimeofday(&tv, &tz);
2280 timeStamp = tv.tv_sec;
2282 /* Compute number of spokes (output table link chains) to cover */
2283 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
2284 n100 *= timeStamp - lastCleanupTime;
2285 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2289 /* Handle different cases */
2290 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2292 n = ALIAS_CLEANUP_MAX_SPOKES;
2293 lastCleanupTime = timeStamp;
2294 houseKeepingResidual = 0;
2297 IncrementalCleanup();
2301 lastCleanupTime = timeStamp;
2302 houseKeepingResidual = n100 - 100*n;
2305 IncrementalCleanup();
2310 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2311 fprintf(stderr, "something unexpected in time values\n");
2313 lastCleanupTime = timeStamp;
2314 houseKeepingResidual = 0;
2319 /* Init the log file and enable logging */
2321 InitPacketAliasLog(void)
2323 if ((~packetAliasMode & PKT_ALIAS_LOG)
2324 && (monitorFile = fopen("/var/log/alias.log", "w")))
2326 packetAliasMode |= PKT_ALIAS_LOG;
2327 fprintf(monitorFile,
2328 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2333 /* Close the log-file and disable logging. */
2335 UninitPacketAliasLog(void)
2338 fclose(monitorFile);
2341 packetAliasMode &= ~PKT_ALIAS_LOG;
2349 /* Outside world interfaces
2351 -- "outside world" means other than alias*.c routines --
2353 PacketAliasRedirectPort()
2354 PacketAliasAddServer()
2355 PacketAliasRedirectProto()
2356 PacketAliasRedirectAddr()
2357 PacketAliasRedirectDelete()
2358 PacketAliasSetAddress()
2361 PacketAliasSetMode()
2363 (prototypes in alias.h)
2366 /* Redirection from a specific public addr:port to a
2367 private addr:port */
2369 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port,
2370 struct in_addr dst_addr, u_short dst_port,
2371 struct in_addr alias_addr, u_short alias_port,
2375 struct alias_link *link;
2380 link_type = LINK_UDP;
2383 link_type = LINK_TCP;
2387 fprintf(stderr, "PacketAliasRedirectPort(): ");
2388 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2393 link = AddLink(src_addr, dst_addr, alias_addr,
2394 src_port, dst_port, alias_port,
2399 link->flags |= LINK_PERMANENT;
2404 fprintf(stderr, "PacketAliasRedirectPort(): "
2405 "call to AddLink() failed\n");
2412 /* Add server to the pool of servers */
2414 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
2416 struct server *server;
2418 server = malloc(sizeof(struct server));
2420 if (server != NULL) {
2421 struct server *head;
2423 server->addr = addr;
2424 server->port = port;
2426 head = link->server;
2428 server->next = server;
2432 for (s = head; s->next != head; s = s->next);
2434 server->next = head;
2436 link->server = server;
2442 /* Redirect packets of a given IP protocol from a specific
2443 public address to a private address */
2445 PacketAliasRedirectProto(struct in_addr src_addr,
2446 struct in_addr dst_addr,
2447 struct in_addr alias_addr,
2450 struct alias_link *link;
2452 link = AddLink(src_addr, dst_addr, alias_addr,
2453 NO_SRC_PORT, NO_DEST_PORT, 0,
2458 link->flags |= LINK_PERMANENT;
2463 fprintf(stderr, "PacketAliasRedirectProto(): "
2464 "call to AddLink() failed\n");
2471 /* Static address translation */
2473 PacketAliasRedirectAddr(struct in_addr src_addr,
2474 struct in_addr alias_addr)
2476 struct alias_link *link;
2478 link = AddLink(src_addr, nullAddress, alias_addr,
2484 link->flags |= LINK_PERMANENT;
2489 fprintf(stderr, "PacketAliasRedirectAddr(): "
2490 "call to AddLink() failed\n");
2499 PacketAliasRedirectDelete(struct alias_link *link)
2501 /* This is a dangerous function to put in the API,
2502 because an invalid pointer can crash the program. */
2511 PacketAliasSetAddress(struct in_addr addr)
2513 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2514 && aliasAddress.s_addr != addr.s_addr)
2517 aliasAddress = addr;
2522 PacketAliasSetTarget(struct in_addr target_addr)
2524 targetAddress = target_addr;
2529 PacketAliasInit(void)
2534 static int firstCall = 1;
2538 gettimeofday(&tv, &tz);
2539 timeStamp = tv.tv_sec;
2540 lastCleanupTime = tv.tv_sec;
2541 houseKeepingResidual = 0;
2543 for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2544 LIST_INIT(&linkTableOut[i]);
2545 for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2546 LIST_INIT(&linkTableIn[i]);
2548 atexit(PacketAliasUninit);
2558 aliasAddress.s_addr = INADDR_ANY;
2559 targetAddress.s_addr = INADDR_ANY;
2566 fragmentIdLinkCount = 0;
2567 fragmentPtrLinkCount = 0;
2572 packetAliasMode = PKT_ALIAS_SAME_PORTS
2573 | PKT_ALIAS_USE_SOCKETS
2574 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2578 PacketAliasUninit(void) {
2582 UninitPacketAliasLog();
2589 /* Change mode for some operations */
2592 unsigned int flags, /* Which state to bring flags to */
2593 unsigned int mask /* Mask of which flags to affect (use 0 to do a
2594 probe for flag values) */
2597 /* Enable logging? */
2598 if (flags & mask & PKT_ALIAS_LOG)
2600 InitPacketAliasLog(); /* Do the enable */
2602 /* _Disable_ logging? */
2603 if (~flags & mask & PKT_ALIAS_LOG) {
2604 UninitPacketAliasLog();
2608 /* Start punching holes in the firewall? */
2609 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2612 /* Stop punching holes in the firewall? */
2613 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2618 /* Other flags can be set/cleared without special action */
2619 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2620 return packetAliasMode;
2625 PacketAliasCheckNewLink(void)
2627 return newDefaultLink;
2634 Code to support firewall punching. This shouldn't really be in this
2635 file, but making variables global is evil too.
2639 #define IPFW2 1 /* use new ipfw code */
2642 /* Firewall include files */
2644 #include <netinet/ip_fw.h>
2648 #if IPFW2 /* support for new firewall code */
2650 * helper function, updates the pointer to cmd with the length
2651 * of the current command, and also cleans up the first word of
2652 * the new command in case it has been clobbered before.
2655 next_cmd(ipfw_insn *cmd)
2658 bzero(cmd, sizeof(*cmd));
2663 * A function to fill simple commands of size 1.
2664 * Existing flags are preserved.
2667 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int size,
2668 int flags, u_int16_t arg)
2670 cmd->opcode = opcode;
2671 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2673 return next_cmd(cmd);
2677 fill_ip(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2679 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2681 cmd->addr.s_addr = addr;
2682 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2686 fill_one_port(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2688 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2690 cmd->ports[0] = cmd->ports[1] = port;
2691 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2695 fill_rule(void *buf, int bufsize, int rulenum,
2696 enum ipfw_opcodes action, int proto,
2697 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2699 struct ip_fw *rule = (struct ip_fw *)buf;
2700 ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2702 bzero(buf, bufsize);
2703 rule->rulenum = rulenum;
2705 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2706 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2707 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2708 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2709 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2711 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2712 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2714 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2716 return ((void *)cmd - buf);
2720 static void ClearAllFWHoles(void);
2722 static int fireWallBaseNum; /* The first firewall entry free for our use */
2723 static int fireWallNumNums; /* How many entries can we use? */
2724 static int fireWallActiveNum; /* Which entry did we last use? */
2725 static char *fireWallField; /* bool array for entries */
2727 #define fw_setfield(field, num) \
2729 (field)[(num) - fireWallBaseNum] = 1; \
2730 } /*lint -save -e717 */ while(0) /*lint -restore */
2731 #define fw_clrfield(field, num) \
2733 (field)[(num) - fireWallBaseNum] = 0; \
2734 } /*lint -save -e717 */ while(0) /*lint -restore */
2735 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2739 fireWallField = malloc(fireWallNumNums);
2740 if (fireWallField) {
2741 memset(fireWallField, 0, fireWallNumNums);
2742 if (fireWallFD < 0) {
2743 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2746 fireWallActiveNum = fireWallBaseNum;
2751 UninitPunchFW(void) {
2753 if (fireWallFD >= 0)
2757 free(fireWallField);
2758 fireWallField = NULL;
2759 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2762 /* Make a certain link go through the firewall */
2764 PunchFWHole(struct alias_link *link) {
2765 int r; /* Result code */
2766 struct ip_fw rule; /* On-the-fly built rule */
2767 int fwhole; /* Where to punch hole */
2769 /* Don't do anything unless we are asked to */
2770 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2772 link->link_type != LINK_TCP)
2775 memset(&rule, 0, sizeof rule);
2779 /* Find empty slot */
2780 for (fwhole = fireWallActiveNum;
2781 fwhole < fireWallBaseNum + fireWallNumNums &&
2782 fw_tstfield(fireWallField, fwhole);
2785 if (fwhole == fireWallBaseNum + fireWallNumNums) {
2786 for (fwhole = fireWallBaseNum;
2787 fwhole < fireWallActiveNum &&
2788 fw_tstfield(fireWallField, fwhole);
2791 if (fwhole == fireWallActiveNum) {
2792 /* No rule point empty - we can't punch more holes. */
2793 fireWallActiveNum = fireWallBaseNum;
2795 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2800 /* Start next search at next position */
2801 fireWallActiveNum = fwhole+1;
2804 * generate two rules of the form
2806 * add fwhole accept tcp from OAddr OPort to DAddr DPort
2807 * add fwhole accept tcp from DAddr DPort to OAddr OPort
2810 if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
2811 u_int32_t rulebuf[255];
2814 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2815 O_ACCEPT, IPPROTO_TCP,
2816 GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
2817 GetDestAddress(link), ntohs(GetDestPort(link)) );
2818 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2820 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2822 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2823 O_ACCEPT, IPPROTO_TCP,
2824 GetDestAddress(link), ntohs(GetDestPort(link)),
2825 GetOriginalAddress(link), ntohs(GetOriginalPort(link)) );
2826 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2828 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2830 #else /* !IPFW2, old code to generate ipfw rule */
2832 /* Build generic part of the two rules */
2833 rule.fw_number = fwhole;
2834 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */
2835 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */
2836 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
2837 rule.fw_prot = IPPROTO_TCP;
2838 rule.fw_smsk.s_addr = INADDR_BROADCAST;
2839 rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2841 /* Build and apply specific part of the rules */
2842 rule.fw_src = GetOriginalAddress(link);
2843 rule.fw_dst = GetDestAddress(link);
2844 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2845 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2847 /* Skip non-bound links - XXX should not be strictly necessary,
2848 but seems to leave hole if not done. Leak of non-bound links?
2849 (Code should be left even if the problem is fixed - it is a
2850 clear optimization) */
2851 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2852 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2855 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2857 rule.fw_src = GetDestAddress(link);
2858 rule.fw_dst = GetOriginalAddress(link);
2859 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2860 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2861 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2864 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2868 /* Indicate hole applied */
2869 link->data.tcp->fwhole = fwhole;
2870 fw_setfield(fireWallField, fwhole);
2873 /* Remove a hole in a firewall associated with a particular alias
2874 link. Calling this too often is harmless. */
2876 ClearFWHole(struct alias_link *link) {
2877 if (link->link_type == LINK_TCP) {
2878 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
2884 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2886 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2887 &fwhole, sizeof fwhole))
2890 rule.fw_number = fwhole;
2891 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2892 &rule, sizeof rule))
2895 fw_clrfield(fireWallField, fwhole);
2896 link->data.tcp->fwhole = -1;
2900 /* Clear out the entire range dedicated to firewall holes. */
2902 ClearAllFWHoles(void) {
2903 struct ip_fw rule; /* On-the-fly built rule */
2909 memset(&rule, 0, sizeof rule);
2910 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2913 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r))
2917 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2921 memset(fireWallField, 0, fireWallNumNums);
2926 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2928 fireWallBaseNum = base;
2929 fireWallNumNums = num;