2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 2001 Charles Mott <cmott@scientech.com>
24 * All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * $FreeBSD: src/lib/libalias/alias_db.c,v 1.21.2.12 2001/08/21 03:50:25 brian Exp $
52 Alias_db.c encapsulates all data structures used for storing
53 packet aliasing data. Other parts of the aliasing software
54 access data through functions provided in this file.
56 Data storage is based on the notion of a "link", which is
57 established for ICMP echo/reply packets, UDP datagrams and
58 TCP stream connections. A link stores the original source
59 and destination addresses. For UDP and TCP, it also stores
60 source and destination port numbers, as well as an alias
61 port number. Links are also used to store information about
64 There is a facility for sweeping through and deleting old
65 links as new packets are sent through. A simple timeout is
66 used for ICMP and UDP links. TCP links are left alone unless
67 there is an incomplete connection, in which case the link
68 can be deleted after a certain amount of time.
71 Initial version: August, 1996 (cjm)
73 Version 1.4: September 16, 1996 (cjm)
74 Facility for handling incoming links added.
76 Version 1.6: September 18, 1996 (cjm)
77 ICMP data handling simplified.
79 Version 1.7: January 9, 1997 (cjm)
80 Fragment handling simplified.
81 Saves pointers for unresolved fragments.
82 Permits links for unspecified remote ports
83 or unspecified remote addresses.
84 Fixed bug which did not properly zero port
85 table entries after a link was deleted.
86 Cleaned up some obsolete comments.
88 Version 1.8: January 14, 1997 (cjm)
89 Fixed data type error in StartPoint().
90 (This error did not exist prior to v1.7
91 and was discovered and fixed by Ari Suutari)
93 Version 1.9: February 1, 1997
94 Optionally, connections initiated from packet aliasing host
95 machine will will not have their port number aliased unless it
96 conflicts with an aliasing port already being used. (cjm)
98 All options earlier being #ifdef'ed are now available through
99 a new interface, SetPacketAliasMode(). This allows run time
100 control (which is now available in PPP+pktAlias through the
101 'alias' keyword). (ee)
103 Added ability to create an alias port without
104 either destination address or port specified.
105 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
107 Removed K&R style function headers
108 and general cleanup. (ee)
110 Added packetAliasMode to replace compiler #defines's (ee)
112 Allocates sockets for partially specified
113 ports if ALIAS_USE_SOCKETS defined. (cjm)
115 Version 2.0: March, 1997
116 SetAliasAddress() will now clean up alias links
117 if the aliasing address is changed. (cjm)
119 PacketAliasPermanentLink() function added to support permanent
120 links. (J. Fortes suggested the need for this.)
123 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
125 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
128 These permanent links allow for incoming connections to
129 machines on the local network. They can be given with a
130 user-chosen amount of specificity, with increasing specificity
131 meaning more security. (cjm)
133 Quite a bit of rework to the basic engine. The portTable[]
134 array, which kept track of which ports were in use was replaced
135 by a table/linked list structure. (cjm)
137 SetExpire() function added. (cjm)
139 DeleteLink() no longer frees memory association with a pointer
140 to a fragment (this bug was first recognized by E. Eklund in
143 Version 2.1: May, 1997 (cjm)
144 Packet aliasing engine reworked so that it can handle
145 multiple external addresses rather than just a single
148 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
149 added to the API. The first function is a more generalized
150 version of PacketAliasPermanentLink(). The second function
151 implements static network address translation.
153 Version 3.2: July, 2000 (salander and satoh)
154 Added FindNewPortGroup to get contiguous range of port values.
156 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
157 link but not actually add one.
159 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
160 except that the alias port (from FindNewPortGroup) is provided
163 See HISTORY file for additional revisions.
167 /* System include files */
173 #include <sys/queue.h>
174 #include <sys/socket.h>
175 #include <sys/time.h>
176 #include <sys/types.h>
178 /* BSD network include files */
179 #include <netinet/in_systm.h>
180 #include <netinet/in.h>
181 #include <netinet/ip.h>
182 #include <netinet/tcp.h>
183 #include <arpa/inet.h>
186 #include "alias_local.h"
191 Constants (note: constants are also defined
192 near relevant functions or structs)
195 /* Sizes of input and output link tables */
196 #define LINK_TABLE_OUT_SIZE 101
197 #define LINK_TABLE_IN_SIZE 4001
199 /* Parameters used for cleanup of expired links */
200 #define ALIAS_CLEANUP_INTERVAL_SECS 60
201 #define ALIAS_CLEANUP_MAX_SPOKES 30
203 /* Timeouts (in seconds) for different link types */
204 #define ICMP_EXPIRE_TIME 60
205 #define UDP_EXPIRE_TIME 60
206 #define PROTO_EXPIRE_TIME 60
207 #define FRAGMENT_ID_EXPIRE_TIME 10
208 #define FRAGMENT_PTR_EXPIRE_TIME 30
210 /* TCP link expire time for different cases */
211 /* When the link has been used and closed - minimal grace time to
212 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
213 #ifndef TCP_EXPIRE_DEAD
214 # define TCP_EXPIRE_DEAD 10
217 /* When the link has been used and closed on one side - the other side
218 is allowed to still send data */
219 #ifndef TCP_EXPIRE_SINGLEDEAD
220 # define TCP_EXPIRE_SINGLEDEAD 90
223 /* When the link isn't yet up */
224 #ifndef TCP_EXPIRE_INITIAL
225 # define TCP_EXPIRE_INITIAL 300
228 /* When the link is up */
229 #ifndef TCP_EXPIRE_CONNECTED
230 # define TCP_EXPIRE_CONNECTED 86400
234 static int iChatAVHack
= 1;
237 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
238 These constants can be anything except zero, which indicates an
239 unknown port number. */
241 #define NO_DEST_PORT 1
242 #define NO_SRC_PORT 1
248 The fundamental data structure used in this program is
249 "struct alias_link". Whenever a TCP connection is made,
250 a UDP datagram is sent out, or an ICMP echo request is made,
251 a link record is made (if it has not already been created).
252 The link record is identified by the source address/port
253 and the destination address/port. In the case of an ICMP
254 echo request, the source port is treated as being equivalent
255 with the 16-bit ID number of the ICMP packet.
257 The link record also can store some auxiliary data. For
258 TCP connections that have had sequence and acknowledgment
259 modifications, data space is available to track these changes.
260 A state field is used to keep track in changes to the TCP
261 connection state. ID numbers of fragments can also be
262 stored in the auxiliary space. Pointers to unresolved
263 fragments can also be stored.
265 The link records support two independent chainings. Lookup
266 tables for input and out tables hold the initial pointers
267 the link chains. On input, the lookup table indexes on alias
268 port and link type. On output, the lookup table indexes on
269 source address, destination address, source port, destination
273 struct ack_data_record
/* used to save changes to ACK/sequence numbers */
281 struct tcp_state
/* Information about TCP connection */
283 int in
; /* State for outside -> inside */
284 int out
; /* State for inside -> outside */
285 int index
; /* Index to ACK data array */
286 int ack_modified
; /* Indicates whether ACK and sequence numbers */
290 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
291 saved for a modified TCP stream */
294 struct tcp_state state
;
295 struct ack_data_record ack
[N_LINK_TCP_DATA
];
296 int fwhole
; /* Which firewall record is used for this hole? */
299 struct server
/* LSNAT server pool (circular list) */
306 struct alias_link
/* Main data structure */
308 struct in_addr src_addr
; /* Address and port information */
309 struct in_addr dst_addr
;
310 struct in_addr alias_addr
;
311 struct in_addr proxy_addr
;
316 struct server
*server
;
318 int link_type
; /* Type of link: TCP, UDP, ICMP, proto, frag */
320 /* values for link_type */
321 #define LINK_ICMP IPPROTO_ICMP
322 #define LINK_UDP IPPROTO_UDP
323 #define LINK_TCP IPPROTO_TCP
324 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
325 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
326 #define LINK_ADDR (IPPROTO_MAX + 3)
327 #define LINK_PPTP (IPPROTO_MAX + 4)
329 int flags
; /* indicates special characteristics */
332 #define LINK_UNKNOWN_DEST_PORT 0x01
333 #define LINK_UNKNOWN_DEST_ADDR 0x02
334 #define LINK_PERMANENT 0x04
335 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
336 #define LINK_UNFIREWALLED 0x08
337 #define LINK_LAST_LINE_CRLF_TERMED 0x10
338 #define LINK_CONE 0x20
340 int timestamp
; /* Time link was last accessed */
341 int expire_time
; /* Expire time for link */
343 int sockfd
; /* socket descriptor */
345 LIST_ENTRY(alias_link
) list_out
; /* Linked list of pointers for */
346 LIST_ENTRY(alias_link
) list_in
; /* input and output lookup tables */
348 union /* Auxiliary data */
351 struct in_addr frag_addr
;
362 The global variables listed here are only accessed from
363 within alias_db.c and so are prefixed with the static
367 int packetAliasMode
; /* Mode flags */
368 /* - documented in alias.h */
370 static struct in_addr aliasAddress
; /* Address written onto source */
371 /* field of IP packet. */
373 static struct in_addr targetAddress
; /* IP address incoming packets */
374 /* are sent to if no aliasing */
375 /* link already exists */
377 static struct in_addr nullAddress
; /* Used as a dummy parameter for */
378 /* some function calls */
379 static LIST_HEAD(, alias_link
)
380 linkTableOut
[LINK_TABLE_OUT_SIZE
]; /* Lookup table of pointers to */
381 /* chains of link records. Each */
382 static LIST_HEAD(, alias_link
) /* link record is doubly indexed */
383 linkTableIn
[LINK_TABLE_IN_SIZE
]; /* into input and output lookup */
386 static int icmpLinkCount
; /* Link statistics */
387 static int udpLinkCount
;
388 static int tcpLinkCount
;
389 static int pptpLinkCount
;
390 static int protoLinkCount
;
391 static int fragmentIdLinkCount
;
392 static int fragmentPtrLinkCount
;
393 static int sockCount
;
395 static int cleanupIndex
; /* Index to chain of link table */
396 /* being inspected for old links */
398 static int timeStamp
; /* System time in seconds for */
401 static int lastCleanupTime
; /* Last time IncrementalCleanup() */
404 static int houseKeepingResidual
; /* used by HouseKeeping() */
406 static int deleteAllLinks
; /* If equal to zero, DeleteLink() */
407 /* will not remove permanent links */
409 static FILE *monitorFile
; /* File descriptor for link */
410 /* statistics monitoring file */
412 static int newDefaultLink
; /* Indicates if a new aliasing */
413 /* link has been created after a */
414 /* call to PacketAliasIn/Out(). */
417 static int fireWallFD
= -1; /* File descriptor to be able to */
418 /* control firewall. Opened by */
419 /* PacketAliasSetMode on first */
420 /* setting the PKT_ALIAS_PUNCH_FW */
430 /* Internal utility routines (used only in alias_db.c)
432 Lookup table starting points:
433 StartPointIn() -- link table initial search point for
435 StartPointOut() -- link table initial search point for
439 SeqDiff() -- difference between two TCP sequences
440 ShowAliasStats() -- send alias statistics to a monitor file
444 /* Local prototypes */
445 static u_int
StartPointIn(struct in_addr
, u_short
, int);
447 static u_int
StartPointOut(struct in_addr
, struct in_addr
,
448 u_short
, u_short
, int);
450 static int SeqDiff(u_long
, u_long
);
452 static void ShowAliasStats(void);
455 /* Firewall control */
456 static void InitPunchFW(void);
457 static void UninitPunchFW(void);
458 static void ClearFWHole(struct alias_link
*link
);
461 /* Log file control */
462 static void InitPacketAliasLog(void);
463 static void UninitPacketAliasLog(void);
466 StartPointIn(struct in_addr alias_addr
,
472 n
= alias_addr
.s_addr
;
473 if (link_type
!= LINK_PPTP
)
476 return(n
% LINK_TABLE_IN_SIZE
);
481 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
482 u_short src_port
, u_short dst_port
, int link_type
)
487 n
+= dst_addr
.s_addr
;
488 if (link_type
!= LINK_PPTP
) {
494 return(n
% LINK_TABLE_OUT_SIZE
);
499 SeqDiff(u_long x
, u_long y
)
501 /* Return the difference between two TCP sequence numbers */
504 This function is encapsulated in case there are any unusual
505 arithmetic conditions that need to be considered.
508 return (ntohl(y
) - ntohl(x
));
515 /* Used for debugging */
519 fprintf(monitorFile
, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
526 fragmentPtrLinkCount
);
528 fprintf(monitorFile
, " / tot=%d (sock=%d)\n",
529 icmpLinkCount
+ udpLinkCount
533 + fragmentIdLinkCount
534 + fragmentPtrLinkCount
,
545 /* Internal routines for finding, deleting and adding links
548 GetNewPort() -- find and reserve new alias port number
549 GetSocket() -- try to allocate a socket for a given port
551 Link creation and deletion:
552 CleanupAliasData() - remove all link chains from lookup table
553 IncrementalCleanup() - look for stale links in a single chain
554 DeleteLink() - remove link
556 ReLink() - change link
559 FindLinkOut() - find link for outgoing packets
560 FindLinkIn() - find link for incoming packets
563 FindNewPortGroup() - find an available group of ports
566 /* Local prototypes */
567 static int GetNewPort(struct alias_link
*, int);
569 static u_short
GetSocket(u_short
, int *, int);
571 static void CleanupAliasData(void);
573 static void IncrementalCleanup(void);
575 static void DeleteLink(struct alias_link
*);
577 static struct alias_link
*
578 AddLink(struct in_addr
, struct in_addr
, struct in_addr
,
579 u_short
, u_short
, int, int);
581 static struct alias_link
*
582 ReLink(struct alias_link
*,
583 struct in_addr
, struct in_addr
, struct in_addr
,
584 u_short
, u_short
, int, int);
586 static struct alias_link
*
587 FindLinkOut(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
589 static struct alias_link
*
590 FindLinkIn(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
593 #define ALIAS_PORT_BASE 0x08000
594 #define ALIAS_PORT_MASK 0x07fff
595 #define ALIAS_PORT_MASK_EVEN 0x07ffe
596 #define GET_NEW_PORT_MAX_ATTEMPTS 20
598 #define GET_ALIAS_PORT -1
599 #define GET_ALIAS_ID GET_ALIAS_PORT
601 #define FIND_EVEN_ALIAS_BASE 1
603 /* GetNewPort() allocates port numbers. Note that if a port number
604 is already in use, that does not mean that it cannot be used by
605 another link concurrently. This is because GetNewPort() looks for
606 unused triplets: (dest addr, dest port, alias port). */
609 GetNewPort(struct alias_link
*link
, int alias_port_param
)
617 Description of alias_port_param for GetNewPort(). When
618 this parameter is zero or positive, it precisely specifies
619 the port number. GetNewPort() will return this number
620 without check that it is in use.
622 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
623 selected port number.
626 if (alias_port_param
== GET_ALIAS_PORT
)
629 * The aliasing port is automatically selected
630 * by one of two methods below:
632 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
634 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
)
637 * When the PKT_ALIAS_SAME_PORTS option is
638 * chosen, the first try will be the
639 * actual source port. If this is already
640 * in use, the remainder of the trials
643 port_net
= link
->src_port
;
644 port_sys
= ntohs(port_net
);
648 /* First trial and all subsequent are random. */
649 port_sys
= random() & ALIAS_PORT_MASK
;
650 port_sys
+= ALIAS_PORT_BASE
;
651 port_net
= htons(port_sys
);
654 else if (alias_port_param
>= 0 && alias_port_param
< 0x10000)
656 link
->alias_port
= (u_short
) alias_port_param
;
662 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
663 fprintf(stderr
, "input parameter error\n");
669 /* Port number search */
670 for (i
=0; i
<max_trials
; i
++)
673 struct alias_link
*search_result
;
675 search_result
= FindLinkIn(link
->dst_addr
, link
->alias_addr
,
676 link
->dst_port
, port_net
,
679 if (search_result
== NULL
)
681 else if (!(link
->flags
& LINK_PARTIALLY_SPECIFIED
)
682 && (search_result
->flags
& LINK_PARTIALLY_SPECIFIED
))
689 if ((packetAliasMode
& PKT_ALIAS_USE_SOCKETS
)
690 && (link
->flags
& LINK_PARTIALLY_SPECIFIED
)
691 && ((link
->link_type
== LINK_TCP
) ||
692 (link
->link_type
== LINK_UDP
)))
694 if (GetSocket(port_net
, &link
->sockfd
, link
->link_type
))
696 link
->alias_port
= port_net
;
702 link
->alias_port
= port_net
;
707 port_sys
= random() & ALIAS_PORT_MASK
;
708 port_sys
+= ALIAS_PORT_BASE
;
709 port_net
= htons(port_sys
);
713 fprintf(stderr
, "PacketAlias/GetnewPort(): ");
714 fprintf(stderr
, "could not find free port\n");
722 GetSocket(u_short port_net
, int *sockfd
, int link_type
)
726 struct sockaddr_in sock_addr
;
728 if (link_type
== LINK_TCP
)
729 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
730 else if (link_type
== LINK_UDP
)
731 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
735 fprintf(stderr
, "PacketAlias/GetSocket(): ");
736 fprintf(stderr
, "incorrect link type\n");
744 fprintf(stderr
, "PacketAlias/GetSocket(): ");
745 fprintf(stderr
, "socket() error %d\n", *sockfd
);
750 sock_addr
.sin_family
= AF_INET
;
751 sock_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
752 sock_addr
.sin_port
= port_net
;
755 (struct sockaddr
*) &sock_addr
,
771 /* FindNewPortGroup() returns a base port number for an available
772 range of contiguous port numbers. Note that if a port number
773 is already in use, that does not mean that it cannot be used by
774 another link concurrently. This is because FindNewPortGroup()
775 looks for unused triplets: (dest addr, dest port, alias port). */
778 FindNewPortGroup(struct in_addr dst_addr
,
779 struct in_addr alias_addr
,
792 * Get link_type from protocol
798 link_type
= LINK_UDP
;
801 link_type
= LINK_TCP
;
809 * The aliasing port is automatically selected
810 * by one of two methods below:
812 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
814 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
) {
816 * When the ALIAS_SAME_PORTS option is
817 * chosen, the first try will be the
818 * actual source port. If this is already
819 * in use, the remainder of the trials
822 port_sys
= ntohs(src_port
);
826 /* First trial and all subsequent are random. */
827 if (align
== FIND_EVEN_ALIAS_BASE
)
828 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
830 port_sys
= random() & ALIAS_PORT_MASK
;
832 port_sys
+= ALIAS_PORT_BASE
;
835 /* Port number search */
836 for (i
= 0; i
< max_trials
; i
++) {
838 struct alias_link
*search_result
;
840 for (j
= 0; j
< port_count
; j
++)
841 if (0 != (search_result
= FindLinkIn(dst_addr
, alias_addr
,
842 dst_port
, htons(port_sys
+ j
),
846 /* Found a good range, return base */
848 return (htons(port_sys
));
850 /* Find a new base to try */
851 if (align
== FIND_EVEN_ALIAS_BASE
)
852 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
854 port_sys
= random() & ALIAS_PORT_MASK
;
856 port_sys
+= ALIAS_PORT_BASE
;
860 fprintf(stderr
, "PacketAlias/FindNewPortGroup(): ");
861 fprintf(stderr
, "could not find free port(s)\n");
868 CleanupAliasData(void)
870 struct alias_link
*link
;
874 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
876 link
= LIST_FIRST(&linkTableOut
[i
]);
879 struct alias_link
*link_next
;
880 link_next
= LIST_NEXT(link
, list_out
);
892 IncrementalCleanup(void)
895 struct alias_link
*link
;
898 link
= LIST_FIRST(&linkTableOut
[cleanupIndex
++]);
902 struct alias_link
*link_next
;
904 link_next
= LIST_NEXT(link
, list_out
);
905 idelta
= timeStamp
- link
->timestamp
;
906 switch (link
->link_type
)
909 if (idelta
> link
->expire_time
)
911 struct tcp_dat
*tcp_aux
;
913 tcp_aux
= link
->data
.tcp
;
914 if (tcp_aux
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
915 || tcp_aux
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
923 if (idelta
> link
->expire_time
)
933 if (cleanupIndex
== LINK_TABLE_OUT_SIZE
)
938 DeleteLink(struct alias_link
*link
)
941 /* Don't do anything if the link is marked permanent */
942 if (deleteAllLinks
== 0 && link
->flags
& LINK_PERMANENT
)
946 /* Delete associated firewall hole, if any */
950 /* Free memory allocated for LSNAT server pool */
951 if (link
->server
!= NULL
) {
952 struct server
*head
, *curr
, *next
;
954 head
= curr
= link
->server
;
958 } while ((curr
= next
) != head
);
961 /* Adjust output table pointers */
962 LIST_REMOVE(link
, list_out
);
964 /* Adjust input table pointers */
965 LIST_REMOVE(link
, list_in
);
967 /* Close socket, if one has been allocated */
968 if (link
->sockfd
!= -1)
974 /* Link-type dependent cleanup */
975 switch(link
->link_type
)
985 free(link
->data
.tcp
);
990 case LINK_FRAGMENT_ID
:
991 fragmentIdLinkCount
--;
993 case LINK_FRAGMENT_PTR
:
994 fragmentPtrLinkCount
--;
995 if (link
->data
.frag_ptr
!= NULL
)
996 free(link
->data
.frag_ptr
);
1006 if ((packetAliasMode
& PKT_ALIAS_LOG
) != 0 &&
1007 !IN_MULTICAST(link
->src_addr
.s_addr
) &&
1008 !IN_MULTICAST(link
->dst_addr
.s_addr
))
1014 switch(link
->link_type
)
1025 fprintf(monitorFile
, "Deleted%s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1027 inet_ntop(AF_INET
, &link
->src_addr
, src
, sizeof(src
)), link
->src_port
,
1028 inet_ntop(AF_INET
, &link
->dst_addr
, dst
, sizeof(dst
)), link
->dst_port
,
1029 inet_ntop(AF_INET
, &link
->alias_addr
, alias
, sizeof(alias
)), link
->alias_port
,
1030 dst
, link
->dst_port
);
1031 fflush(monitorFile
);
1034 if (packetAliasMode
& PKT_ALIAS_LOG
)
1043 static struct alias_link
*
1044 AddLink(struct in_addr src_addr
,
1045 struct in_addr dst_addr
,
1046 struct in_addr alias_addr
,
1049 int alias_port_param
, /* if less than zero, alias */
1050 int link_type
) /* port will be automatically */
1051 { /* chosen. If greater than */
1052 u_int start_point
; /* zero, equal to alias port */
1053 struct alias_link
*link
;
1055 link
= malloc(sizeof(struct alias_link
));
1058 /* Basic initialization */
1059 link
->src_addr
= src_addr
;
1060 link
->dst_addr
= dst_addr
;
1061 link
->alias_addr
= alias_addr
;
1062 link
->proxy_addr
.s_addr
= INADDR_ANY
;
1063 link
->src_port
= src_port
;
1064 link
->dst_port
= dst_port
;
1065 link
->proxy_port
= 0;
1066 link
->server
= NULL
;
1067 link
->link_type
= link_type
;
1070 link
->timestamp
= timeStamp
;
1072 /* Expiration time */
1076 link
->expire_time
= ICMP_EXPIRE_TIME
;
1079 if (dst_addr
.s_addr
== 0 && dst_port
== 0)
1080 link
->expire_time
= UDP_EXPIRE_TIME
* 5;
1082 link
->expire_time
= UDP_EXPIRE_TIME
;
1085 link
->expire_time
= TCP_EXPIRE_INITIAL
;
1088 link
->flags
|= LINK_PERMANENT
; /* no timeout. */
1090 case LINK_FRAGMENT_ID
:
1091 link
->expire_time
= FRAGMENT_ID_EXPIRE_TIME
;
1093 case LINK_FRAGMENT_PTR
:
1094 link
->expire_time
= FRAGMENT_PTR_EXPIRE_TIME
;
1099 link
->expire_time
= PROTO_EXPIRE_TIME
;
1103 /* Determine alias flags */
1104 if (dst_addr
.s_addr
== INADDR_ANY
)
1105 link
->flags
|= LINK_UNKNOWN_DEST_ADDR
;
1107 link
->flags
|= LINK_UNKNOWN_DEST_PORT
;
1109 /* Determine alias port */
1110 if (GetNewPort(link
, alias_port_param
) != 0)
1116 /* Link-type dependent initialization */
1119 struct tcp_dat
*aux_tcp
;
1128 aux_tcp
= malloc(sizeof(struct tcp_dat
));
1129 if (aux_tcp
!= NULL
)
1134 aux_tcp
->state
.in
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1135 aux_tcp
->state
.out
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1136 aux_tcp
->state
.index
= 0;
1137 aux_tcp
->state
.ack_modified
= 0;
1138 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
1139 aux_tcp
->ack
[i
].active
= 0;
1140 aux_tcp
->fwhole
= -1;
1141 link
->data
.tcp
= aux_tcp
;
1146 fprintf(stderr
, "PacketAlias/AddLink: ");
1147 fprintf(stderr
, " cannot allocate auxiliary TCP data\n");
1156 case LINK_FRAGMENT_ID
:
1157 fragmentIdLinkCount
++;
1159 case LINK_FRAGMENT_PTR
:
1160 fragmentPtrLinkCount
++;
1169 /* Set up pointers for output lookup table */
1170 start_point
= StartPointOut(src_addr
, dst_addr
,
1171 src_port
, dst_port
, link_type
);
1172 LIST_INSERT_HEAD(&linkTableOut
[start_point
], link
, list_out
);
1174 /* Set up pointers for input lookup table */
1175 start_point
= StartPointIn(alias_addr
, link
->alias_port
, link_type
);
1176 LIST_INSERT_HEAD(&linkTableIn
[start_point
], link
, list_in
);
1181 fprintf(stderr
, "PacketAlias/AddLink(): ");
1182 fprintf(stderr
, "malloc() call failed.\n");
1187 if ((packetAliasMode
& PKT_ALIAS_LOG
) != 0 &&
1188 !IN_MULTICAST(link
->src_addr
.s_addr
) &&
1189 !IN_MULTICAST(link
->dst_addr
.s_addr
))
1195 switch(link
->link_type
)
1206 fprintf(monitorFile
, "Added %s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1208 inet_ntop(AF_INET
, &link
->src_addr
, src
, sizeof(src
)), link
->src_port
,
1209 inet_ntop(AF_INET
, &link
->dst_addr
, dst
, sizeof(dst
)), link
->dst_port
,
1210 inet_ntop(AF_INET
, &link
->alias_addr
, alias
, sizeof(alias
)), link
->alias_port
,
1211 dst
, link
->dst_port
);
1214 if (packetAliasMode
& PKT_ALIAS_LOG
)
1221 static struct alias_link
*
1222 ReLink(struct alias_link
*old_link
,
1223 struct in_addr src_addr
,
1224 struct in_addr dst_addr
,
1225 struct in_addr alias_addr
,
1228 int alias_port_param
, /* if less than zero, alias */
1229 int link_type
) /* port will be automatically */
1230 { /* chosen. If greater than */
1231 struct alias_link
*new_link
; /* zero, equal to alias port */
1233 new_link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1234 src_port
, dst_port
, alias_port_param
,
1237 if (new_link
!= NULL
&&
1238 old_link
->link_type
== LINK_TCP
&&
1239 old_link
->data
.tcp
->fwhole
> 0) {
1240 PunchFWHole(new_link
);
1243 if ((old_link
->flags
& LINK_CONE
) == 0)
1244 DeleteLink(old_link
);
1248 static struct alias_link
*
1249 _FindLinkOut(struct in_addr src_addr
,
1250 struct in_addr dst_addr
,
1254 int replace_partial_links
)
1257 struct alias_link
*link
;
1259 i
= StartPointOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
);
1260 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1262 if (link
->src_addr
.s_addr
== src_addr
.s_addr
1263 && link
->server
== NULL
1264 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1265 && link
->dst_port
== dst_port
1266 && link
->src_port
== src_port
1267 && link
->link_type
== link_type
)
1269 link
->timestamp
= timeStamp
;
1274 /* Search for partially specified links. */
1275 if (link
== NULL
&& replace_partial_links
)
1277 if (dst_port
!= 0 && dst_addr
.s_addr
!= INADDR_ANY
)
1279 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, 0,
1282 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
,
1283 dst_port
, link_type
, 0);
1286 (dst_port
!= 0 || dst_addr
.s_addr
!= INADDR_ANY
))
1288 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
, 0,
1294 src_addr
, dst_addr
, link
->alias_addr
,
1295 src_port
, dst_port
, link
->alias_port
,
1303 static struct alias_link
*
1304 FindLinkOut(struct in_addr src_addr
,
1305 struct in_addr dst_addr
,
1309 int replace_partial_links
)
1311 struct alias_link
*link
;
1313 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
,
1314 link_type
, replace_partial_links
);
1318 /* The following allows permanent links to be
1319 specified as using the default source address
1320 (i.e. device interface address) without knowing
1321 in advance what that address is. */
1322 if (aliasAddress
.s_addr
!= 0 &&
1323 src_addr
.s_addr
== aliasAddress
.s_addr
)
1325 link
= _FindLinkOut(nullAddress
, dst_addr
, src_port
, dst_port
,
1326 link_type
, replace_partial_links
);
1334 static struct alias_link
*
1335 _FindLinkIn(struct in_addr dst_addr
,
1336 struct in_addr alias_addr
,
1340 int replace_partial_links
)
1344 struct alias_link
*link
;
1345 struct alias_link
*link_fully_specified
;
1346 struct alias_link
*link_unknown_all
;
1347 struct alias_link
*link_unknown_dst_addr
;
1348 struct alias_link
*link_unknown_dst_port
;
1350 /* Initialize pointers */
1351 link_fully_specified
= NULL
;
1352 link_unknown_all
= NULL
;
1353 link_unknown_dst_addr
= NULL
;
1354 link_unknown_dst_port
= NULL
;
1356 /* If either the dest addr or port is unknown, the search
1357 loop will have to know about this. */
1360 if (dst_addr
.s_addr
== INADDR_ANY
)
1361 flags_in
|= LINK_UNKNOWN_DEST_ADDR
;
1363 flags_in
|= LINK_UNKNOWN_DEST_PORT
;
1366 start_point
= StartPointIn(alias_addr
, alias_port
, link_type
);
1367 LIST_FOREACH(link
, &linkTableIn
[start_point
], list_in
)
1371 flags
= flags_in
| link
->flags
;
1372 if (!(flags
& LINK_PARTIALLY_SPECIFIED
))
1374 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1375 && link
->alias_port
== alias_port
1376 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1377 && link
->dst_port
== dst_port
1378 && link
->link_type
== link_type
)
1380 link_fully_specified
= link
;
1384 else if ((flags
& LINK_UNKNOWN_DEST_ADDR
)
1385 && (flags
& LINK_UNKNOWN_DEST_PORT
))
1387 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1388 && link
->alias_port
== alias_port
1389 && link
->link_type
== link_type
)
1391 if (link_unknown_all
== NULL
)
1392 link_unknown_all
= link
;
1395 else if (flags
& LINK_UNKNOWN_DEST_ADDR
)
1397 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1398 && link
->alias_port
== alias_port
1399 && link
->link_type
== link_type
1400 && link
->dst_port
== dst_port
)
1402 if (link_unknown_dst_addr
== NULL
)
1403 link_unknown_dst_addr
= link
;
1406 else if (flags
& LINK_UNKNOWN_DEST_PORT
)
1408 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1409 && link
->alias_port
== alias_port
1410 && link
->link_type
== link_type
1411 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
)
1413 if (link_unknown_dst_port
== NULL
)
1414 link_unknown_dst_port
= link
;
1421 if (link_fully_specified
!= NULL
)
1423 link_fully_specified
->timestamp
= timeStamp
;
1424 link
= link_fully_specified
;
1426 else if (link_unknown_dst_port
!= NULL
)
1427 link
= link_unknown_dst_port
;
1428 else if (link_unknown_dst_addr
!= NULL
)
1429 link
= link_unknown_dst_addr
;
1430 else if (link_unknown_all
!= NULL
)
1431 link
= link_unknown_all
;
1435 if (replace_partial_links
&&
1436 (link
->flags
& LINK_PARTIALLY_SPECIFIED
|| link
->server
!= NULL
))
1438 struct in_addr src_addr
;
1441 if (link
->server
!= NULL
) { /* LSNAT link */
1442 src_addr
= link
->server
->addr
;
1443 src_port
= link
->server
->port
;
1444 link
->server
= link
->server
->next
;
1446 src_addr
= link
->src_addr
;
1447 src_port
= link
->src_port
;
1451 src_addr
, dst_addr
, alias_addr
,
1452 src_port
, dst_port
, alias_port
,
1459 static struct alias_link
*
1460 FindLinkIn(struct in_addr dst_addr
,
1461 struct in_addr alias_addr
,
1465 int replace_partial_links
)
1467 struct alias_link
*link
;
1469 link
= _FindLinkIn(dst_addr
, alias_addr
, dst_port
, alias_port
,
1470 link_type
, replace_partial_links
);
1474 /* The following allows permanent links to be
1475 specified as using the default aliasing address
1476 (i.e. device interface address) without knowing
1477 in advance what that address is. */
1478 if (aliasAddress
.s_addr
!= 0 &&
1479 alias_addr
.s_addr
== aliasAddress
.s_addr
)
1481 link
= _FindLinkIn(dst_addr
, nullAddress
, dst_port
, alias_port
,
1482 link_type
, replace_partial_links
);
1492 /* External routines for finding/adding links
1494 -- "external" means outside alias_db.c, but within alias*.c --
1496 FindIcmpIn(), FindIcmpOut()
1497 FindFragmentIn1(), FindFragmentIn2()
1498 AddFragmentPtrLink(), FindFragmentPtr()
1499 FindProtoIn(), FindProtoOut()
1500 FindUdpTcpIn(), FindUdpTcpOut()
1501 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1502 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1503 FindOriginalAddress(), FindAliasAddress()
1505 (prototypes in alias_local.h)
1510 FindIcmpIn(struct in_addr dst_addr
,
1511 struct in_addr alias_addr
,
1515 struct alias_link
*link
;
1517 link
= FindLinkIn(dst_addr
, alias_addr
,
1518 NO_DEST_PORT
, id_alias
,
1520 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1522 struct in_addr target_addr
;
1524 target_addr
= FindOriginalAddress(alias_addr
);
1525 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1526 id_alias
, NO_DEST_PORT
, id_alias
,
1535 FindIcmpOut(struct in_addr src_addr
,
1536 struct in_addr dst_addr
,
1540 struct alias_link
* link
;
1542 link
= FindLinkOut(src_addr
, dst_addr
,
1545 if (link
== NULL
&& create
)
1547 struct in_addr alias_addr
;
1549 alias_addr
= FindAliasAddress(src_addr
);
1550 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1551 id
, NO_DEST_PORT
, GET_ALIAS_ID
,
1560 FindFragmentIn1(struct in_addr dst_addr
,
1561 struct in_addr alias_addr
,
1564 struct alias_link
*link
;
1566 link
= FindLinkIn(dst_addr
, alias_addr
,
1567 NO_DEST_PORT
, ip_id
,
1568 LINK_FRAGMENT_ID
, 0);
1572 link
= AddLink(nullAddress
, dst_addr
, alias_addr
,
1573 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1582 FindFragmentIn2(struct in_addr dst_addr
, /* Doesn't add a link if one */
1583 struct in_addr alias_addr
, /* is not found. */
1586 return FindLinkIn(dst_addr
, alias_addr
,
1587 NO_DEST_PORT
, ip_id
,
1588 LINK_FRAGMENT_ID
, 0);
1593 AddFragmentPtrLink(struct in_addr dst_addr
,
1596 return AddLink(nullAddress
, dst_addr
, nullAddress
,
1597 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1603 FindFragmentPtr(struct in_addr dst_addr
,
1606 return FindLinkIn(dst_addr
, nullAddress
,
1607 NO_DEST_PORT
, ip_id
,
1608 LINK_FRAGMENT_PTR
, 0);
1613 FindProtoIn(struct in_addr dst_addr
,
1614 struct in_addr alias_addr
,
1617 struct alias_link
*link
;
1619 link
= FindLinkIn(dst_addr
, alias_addr
,
1623 if (link
== NULL
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1625 struct in_addr target_addr
;
1627 target_addr
= FindOriginalAddress(alias_addr
);
1628 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1629 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1638 FindProtoOut(struct in_addr src_addr
,
1639 struct in_addr dst_addr
,
1642 struct alias_link
*link
;
1644 link
= FindLinkOut(src_addr
, dst_addr
,
1645 NO_SRC_PORT
, NO_DEST_PORT
,
1650 struct in_addr alias_addr
;
1652 alias_addr
= FindAliasAddress(src_addr
);
1653 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1654 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1663 FindUdpTcpIn(struct in_addr dst_addr
,
1664 struct in_addr alias_addr
,
1671 struct alias_link
*link
;
1676 link_type
= LINK_UDP
;
1679 link_type
= LINK_TCP
;
1686 link
= FindLinkIn(dst_addr
, alias_addr
,
1687 dst_port
, alias_port
,
1690 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1692 struct in_addr target_addr
;
1694 target_addr
= FindOriginalAddress(alias_addr
);
1695 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1696 alias_port
, dst_port
, alias_port
,
1705 FindUdpTcpOut(struct in_addr src_addr
,
1706 struct in_addr dst_addr
,
1713 struct alias_link
*link
;
1718 link_type
= LINK_UDP
;
1721 link_type
= LINK_TCP
;
1728 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
, create
);
1730 if (link
== NULL
&& create
)
1732 struct in_addr alias_addr
;
1733 struct in_addr dst_addr2
= dst_addr
;
1734 u_short dst_port2
= dst_port
;
1736 alias_addr
= FindAliasAddress(src_addr
);
1738 if (iChatAVHack
&& link_type
== LINK_UDP
&& dst_port
== htons(5678)) {
1739 dst_addr2
.s_addr
= 0;
1742 link
= AddLink(src_addr
, dst_addr2
, alias_addr
,
1743 src_port
, dst_port2
, GET_ALIAS_PORT
,
1746 (link
->flags
& (LINK_UNKNOWN_DEST_ADDR
| LINK_UNKNOWN_DEST_PORT
)) != 0)
1748 link
->flags
|= LINK_CONE
;
1749 link
= ReLink(link
, link
->src_addr
, dst_addr
, link
->alias_addr
,
1750 link
->src_port
, dst_port
, link
->alias_port
, link_type
);
1759 AddPptp(struct in_addr src_addr
,
1760 struct in_addr dst_addr
,
1761 struct in_addr alias_addr
,
1762 u_int16_t src_call_id
)
1764 struct alias_link
*link
;
1766 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1767 src_call_id
, 0, GET_ALIAS_PORT
,
1775 FindPptpOutByCallId(struct in_addr src_addr
,
1776 struct in_addr dst_addr
,
1777 u_int16_t src_call_id
)
1780 struct alias_link
*link
;
1782 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1783 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1784 if (link
->link_type
== LINK_PPTP
&&
1785 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1786 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1787 link
->src_port
== src_call_id
)
1795 FindPptpOutByPeerCallId(struct in_addr src_addr
,
1796 struct in_addr dst_addr
,
1797 u_int16_t dst_call_id
)
1800 struct alias_link
*link
;
1802 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1803 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1804 if (link
->link_type
== LINK_PPTP
&&
1805 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1806 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1807 link
->dst_port
== dst_call_id
)
1815 FindPptpInByCallId(struct in_addr dst_addr
,
1816 struct in_addr alias_addr
,
1817 u_int16_t dst_call_id
)
1820 struct alias_link
*link
;
1822 i
= StartPointIn(alias_addr
, 0, LINK_PPTP
);
1823 LIST_FOREACH(link
, &linkTableIn
[i
], list_in
)
1824 if (link
->link_type
== LINK_PPTP
&&
1825 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1826 link
->alias_addr
.s_addr
== alias_addr
.s_addr
&&
1827 link
->dst_port
== dst_call_id
)
1835 FindPptpInByPeerCallId(struct in_addr dst_addr
,
1836 struct in_addr alias_addr
,
1837 u_int16_t alias_call_id
)
1839 struct alias_link
*link
;
1841 link
= FindLinkIn(dst_addr
, alias_addr
,
1842 0/* any */, alias_call_id
,
1851 FindRtspOut(struct in_addr src_addr
,
1852 struct in_addr dst_addr
,
1858 struct alias_link
*link
;
1863 link_type
= LINK_UDP
;
1866 link_type
= LINK_TCP
;
1873 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, 0, link_type
, 1);
1877 struct in_addr alias_addr
;
1879 alias_addr
= FindAliasAddress(src_addr
);
1880 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1881 src_port
, 0, alias_port
,
1890 FindOriginalAddress(struct in_addr alias_addr
)
1892 struct alias_link
*link
;
1894 link
= FindLinkIn(nullAddress
, alias_addr
,
1895 0, 0, LINK_ADDR
, 0);
1899 if (targetAddress
.s_addr
== INADDR_ANY
)
1901 else if (targetAddress
.s_addr
== INADDR_NONE
)
1902 return aliasAddress
;
1904 return targetAddress
;
1908 if (link
->server
!= NULL
) { /* LSNAT link */
1909 struct in_addr src_addr
;
1911 src_addr
= link
->server
->addr
;
1912 link
->server
= link
->server
->next
;
1914 } else if (link
->src_addr
.s_addr
== INADDR_ANY
)
1915 return aliasAddress
;
1917 return link
->src_addr
;
1923 FindAliasAddress(struct in_addr original_addr
)
1925 struct alias_link
*link
;
1927 link
= FindLinkOut(original_addr
, nullAddress
,
1928 0, 0, LINK_ADDR
, 0);
1931 return aliasAddress
;
1935 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1936 return aliasAddress
;
1938 return link
->alias_addr
;
1943 /* External routines for getting or changing link data
1944 (external to alias_db.c, but internal to alias*.c)
1946 SetFragmentData(), GetFragmentData()
1947 SetFragmentPtr(), GetFragmentPtr()
1948 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1949 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1950 GetOriginalPort(), GetAliasPort()
1951 SetAckModified(), GetAckModified()
1952 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1953 SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
1959 SetFragmentAddr(struct alias_link
*link
, struct in_addr src_addr
)
1961 link
->data
.frag_addr
= src_addr
;
1966 GetFragmentAddr(struct alias_link
*link
, struct in_addr
*src_addr
)
1968 *src_addr
= link
->data
.frag_addr
;
1973 SetFragmentPtr(struct alias_link
*link
, char *fptr
)
1975 link
->data
.frag_ptr
= fptr
;
1980 GetFragmentPtr(struct alias_link
*link
, char **fptr
)
1982 *fptr
= link
->data
.frag_ptr
;
1987 SetStateIn(struct alias_link
*link
, int state
)
1989 /* TCP input state */
1991 case ALIAS_TCP_STATE_DISCONNECTED
:
1992 if (link
->data
.tcp
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
1993 link
->expire_time
= TCP_EXPIRE_DEAD
;
1995 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1997 case ALIAS_TCP_STATE_CONNECTED
:
1998 if (link
->data
.tcp
->state
.out
== ALIAS_TCP_STATE_CONNECTED
)
1999 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
2004 link
->data
.tcp
->state
.in
= state
;
2009 SetStateOut(struct alias_link
*link
, int state
)
2011 /* TCP output state */
2013 case ALIAS_TCP_STATE_DISCONNECTED
:
2014 if (link
->data
.tcp
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
)
2015 link
->expire_time
= TCP_EXPIRE_DEAD
;
2017 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
2019 case ALIAS_TCP_STATE_CONNECTED
:
2020 if (link
->data
.tcp
->state
.in
== ALIAS_TCP_STATE_CONNECTED
)
2021 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
2026 link
->data
.tcp
->state
.out
= state
;
2031 GetStateIn(struct alias_link
*link
)
2033 /* TCP input state */
2034 return link
->data
.tcp
->state
.in
;
2039 GetStateOut(struct alias_link
*link
)
2041 /* TCP output state */
2042 return link
->data
.tcp
->state
.out
;
2047 GetOriginalAddress(struct alias_link
*link
)
2049 if (link
->src_addr
.s_addr
== INADDR_ANY
)
2050 return aliasAddress
;
2052 return(link
->src_addr
);
2057 GetDestAddress(struct alias_link
*link
)
2059 return(link
->dst_addr
);
2064 GetAliasAddress(struct alias_link
*link
)
2066 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
2067 return aliasAddress
;
2069 return link
->alias_addr
;
2074 GetDefaultAliasAddress()
2076 return aliasAddress
;
2081 SetDefaultAliasAddress(struct in_addr alias_addr
)
2083 aliasAddress
= alias_addr
;
2088 GetOriginalPort(struct alias_link
*link
)
2090 return(link
->src_port
);
2095 GetAliasPort(struct alias_link
*link
)
2097 return(link
->alias_port
);
2102 GetDestPort(struct alias_link
*link
)
2104 return(link
->dst_port
);
2109 SetAckModified(struct alias_link
*link
)
2111 /* Indicate that ACK numbers have been modified in a TCP connection */
2112 link
->data
.tcp
->state
.ack_modified
= 1;
2117 GetProxyAddress(struct alias_link
*link
)
2119 return link
->proxy_addr
;
2124 SetProxyAddress(struct alias_link
*link
, struct in_addr addr
)
2126 link
->proxy_addr
= addr
;
2131 GetProxyPort(struct alias_link
*link
)
2133 return link
->proxy_port
;
2138 SetProxyPort(struct alias_link
*link
, u_short port
)
2140 link
->proxy_port
= port
;
2145 GetAckModified(struct alias_link
*link
)
2147 /* See if ACK numbers have been modified */
2148 return link
->data
.tcp
->state
.ack_modified
;
2153 GetDeltaAckIn(struct ip
*pip
, struct alias_link
*link
)
2156 Find out how much the ACK number has been altered for an incoming
2157 TCP packet. To do this, a circular list of ACK numbers where the TCP
2158 packet size was altered is searched.
2163 int delta
, ack_diff_min
;
2166 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2171 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2173 struct ack_data_record x
;
2175 x
= link
->data
.tcp
->ack
[i
];
2180 ack_diff
= SeqDiff(x
.ack_new
, ack
);
2183 if (ack_diff_min
>= 0)
2185 if (ack_diff
< ack_diff_min
)
2188 ack_diff_min
= ack_diff
;
2194 ack_diff_min
= ack_diff
;
2204 GetDeltaSeqOut(struct ip
*pip
, struct alias_link
*link
)
2207 Find out how much the sequence number has been altered for an outgoing
2208 TCP packet. To do this, a circular list of ACK numbers where the TCP
2209 packet size was altered is searched.
2214 int delta
, seq_diff_min
;
2217 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2222 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2224 struct ack_data_record x
;
2226 x
= link
->data
.tcp
->ack
[i
];
2231 seq_diff
= SeqDiff(x
.ack_old
, seq
);
2234 if (seq_diff_min
>= 0)
2236 if (seq_diff
< seq_diff_min
)
2239 seq_diff_min
= seq_diff
;
2245 seq_diff_min
= seq_diff
;
2255 AddSeq(struct ip
*pip
, struct alias_link
*link
, int delta
)
2258 When a TCP packet has been altered in length, save this
2259 information in a circular list. If enough packets have
2260 been altered, then this list will begin to overwrite itself.
2264 struct ack_data_record x
;
2265 int hlen
, tlen
, dlen
;
2268 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2270 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
2271 tlen
= ntohs(pip
->ip_len
);
2274 x
.ack_old
= htonl(ntohl(tc
->th_seq
) + dlen
);
2275 x
.ack_new
= htonl(ntohl(tc
->th_seq
) + dlen
+ delta
);
2279 i
= link
->data
.tcp
->state
.index
;
2280 link
->data
.tcp
->ack
[i
] = x
;
2283 if (i
== N_LINK_TCP_DATA
)
2284 link
->data
.tcp
->state
.index
= 0;
2286 link
->data
.tcp
->state
.index
= i
;
2290 SetExpire(struct alias_link
*link
, int expire
)
2294 link
->flags
&= ~LINK_PERMANENT
;
2297 else if (expire
== -1)
2299 link
->flags
|= LINK_PERMANENT
;
2301 else if (expire
> 0)
2303 link
->expire_time
= expire
;
2308 fprintf(stderr
, "PacketAlias/SetExpire(): ");
2309 fprintf(stderr
, "error in expire parameter\n");
2315 ClearCheckNewLink(void)
2321 SetLastLineCrlfTermed(struct alias_link
*link
, int yes
)
2325 link
->flags
|= LINK_LAST_LINE_CRLF_TERMED
;
2327 link
->flags
&= ~LINK_LAST_LINE_CRLF_TERMED
;
2331 GetLastLineCrlfTermed(struct alias_link
*link
)
2334 return (link
->flags
& LINK_LAST_LINE_CRLF_TERMED
);
2338 SetDestCallId(struct alias_link
*link
, u_int16_t cid
)
2342 link
= ReLink(link
, link
->src_addr
, link
->dst_addr
, link
->alias_addr
,
2343 link
->src_port
, cid
, link
->alias_port
, link
->link_type
);
2348 /* Miscellaneous Functions
2351 InitPacketAliasLog()
2352 UninitPacketAliasLog()
2356 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2357 is called to find and remove timed-out aliasing links. Logic exists
2358 to sweep through the entire table and linked list structure
2361 (prototype in alias_local.h)
2372 * Save system time (seconds) in global variable timeStamp for
2373 * use by other functions. This is done so as not to unnecessarily
2374 * waste timeline by making system calls.
2376 gettimeofday(&tv
, &tz
);
2377 timeStamp
= tv
.tv_sec
;
2379 /* Compute number of spokes (output table link chains) to cover */
2380 n100
= LINK_TABLE_OUT_SIZE
* 100 + houseKeepingResidual
;
2381 n100
*= timeStamp
- lastCleanupTime
;
2382 n100
/= ALIAS_CLEANUP_INTERVAL_SECS
;
2386 /* Handle different cases */
2387 if (n
> ALIAS_CLEANUP_MAX_SPOKES
)
2389 n
= ALIAS_CLEANUP_MAX_SPOKES
;
2390 lastCleanupTime
= timeStamp
;
2391 houseKeepingResidual
= 0;
2394 IncrementalCleanup();
2398 lastCleanupTime
= timeStamp
;
2399 houseKeepingResidual
= n100
- 100*n
;
2402 IncrementalCleanup();
2407 fprintf(stderr
, "PacketAlias/HouseKeeping(): ");
2408 fprintf(stderr
, "something unexpected in time values\n");
2410 lastCleanupTime
= timeStamp
;
2411 houseKeepingResidual
= 0;
2416 /* Init the log file and enable logging */
2418 InitPacketAliasLog(void)
2420 if ((~packetAliasMode
& PKT_ALIAS_LOG
)
2421 && (monitorFile
= fopen("/var/log/alias.log", "w")))
2423 packetAliasMode
|= PKT_ALIAS_LOG
;
2424 fprintf(monitorFile
,
2425 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2430 /* Close the log-file and disable logging. */
2432 UninitPacketAliasLog(void)
2435 fclose(monitorFile
);
2438 packetAliasMode
&= ~PKT_ALIAS_LOG
;
2446 /* Outside world interfaces
2448 -- "outside world" means other than alias*.c routines --
2450 PacketAliasRedirectPort()
2451 PacketAliasAddServer()
2452 PacketAliasRedirectProto()
2453 PacketAliasRedirectAddr()
2454 PacketAliasRedirectDelete()
2455 PacketAliasSetAddress()
2458 PacketAliasSetMode()
2460 (prototypes in alias.h)
2463 /* Redirection from a specific public addr:port to a
2464 private addr:port */
2466 PacketAliasRedirectPort(struct in_addr src_addr
, u_short src_port
,
2467 struct in_addr dst_addr
, u_short dst_port
,
2468 struct in_addr alias_addr
, u_short alias_port
,
2472 struct alias_link
*link
;
2477 link_type
= LINK_UDP
;
2480 link_type
= LINK_TCP
;
2484 fprintf(stderr
, "PacketAliasRedirectPort(): ");
2485 fprintf(stderr
, "only TCP and UDP protocols allowed\n");
2490 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2491 src_port
, dst_port
, alias_port
,
2496 link
->flags
|= LINK_PERMANENT
;
2501 fprintf(stderr
, "PacketAliasRedirectPort(): "
2502 "call to AddLink() failed\n");
2509 /* Add server to the pool of servers */
2511 PacketAliasAddServer(struct alias_link
*link
, struct in_addr addr
, u_short port
)
2513 struct server
*server
;
2515 server
= malloc(sizeof(struct server
));
2517 if (server
!= NULL
) {
2518 struct server
*head
;
2520 server
->addr
= addr
;
2521 server
->port
= port
;
2523 head
= link
->server
;
2525 server
->next
= server
;
2529 for (s
= head
; s
->next
!= head
; s
= s
->next
);
2531 server
->next
= head
;
2533 link
->server
= server
;
2539 /* Redirect packets of a given IP protocol from a specific
2540 public address to a private address */
2542 PacketAliasRedirectProto(struct in_addr src_addr
,
2543 struct in_addr dst_addr
,
2544 struct in_addr alias_addr
,
2547 struct alias_link
*link
;
2549 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2550 NO_SRC_PORT
, NO_DEST_PORT
, 0,
2555 link
->flags
|= LINK_PERMANENT
;
2560 fprintf(stderr
, "PacketAliasRedirectProto(): "
2561 "call to AddLink() failed\n");
2568 /* Static address translation */
2570 PacketAliasRedirectAddr(struct in_addr src_addr
,
2571 struct in_addr alias_addr
)
2573 struct alias_link
*link
;
2575 link
= AddLink(src_addr
, nullAddress
, alias_addr
,
2581 link
->flags
|= LINK_PERMANENT
;
2586 fprintf(stderr
, "PacketAliasRedirectAddr(): "
2587 "call to AddLink() failed\n");
2596 PacketAliasRedirectDelete(struct alias_link
*link
)
2598 /* This is a dangerous function to put in the API,
2599 because an invalid pointer can crash the program. */
2608 PacketAliasSetAddress(struct in_addr addr
)
2610 if (packetAliasMode
& PKT_ALIAS_RESET_ON_ADDR_CHANGE
2611 && aliasAddress
.s_addr
!= addr
.s_addr
)
2614 aliasAddress
= addr
;
2619 PacketAliasSetTarget(struct in_addr target_addr
)
2621 targetAddress
= target_addr
;
2626 PacketAliasInit(void)
2631 static int firstCall
= 1;
2635 gettimeofday(&tv
, &tz
);
2636 timeStamp
= tv
.tv_sec
;
2637 lastCleanupTime
= tv
.tv_sec
;
2638 houseKeepingResidual
= 0;
2640 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
2641 LIST_INIT(&linkTableOut
[i
]);
2642 for (i
=0; i
<LINK_TABLE_IN_SIZE
; i
++)
2643 LIST_INIT(&linkTableIn
[i
]);
2645 atexit(PacketAliasUninit
);
2655 aliasAddress
.s_addr
= INADDR_ANY
;
2656 targetAddress
.s_addr
= INADDR_ANY
;
2663 fragmentIdLinkCount
= 0;
2664 fragmentPtrLinkCount
= 0;
2669 packetAliasMode
= PKT_ALIAS_SAME_PORTS
2670 | PKT_ALIAS_USE_SOCKETS
2671 | PKT_ALIAS_RESET_ON_ADDR_CHANGE
;
2675 PacketAliasUninit(void) {
2679 UninitPacketAliasLog();
2686 /* Change mode for some operations */
2689 unsigned int flags
, /* Which state to bring flags to */
2690 unsigned int mask
/* Mask of which flags to affect (use 0 to do a
2691 probe for flag values) */
2694 /* Enable logging? */
2695 if (flags
& mask
& PKT_ALIAS_LOG
)
2697 InitPacketAliasLog(); /* Do the enable */
2699 /* _Disable_ logging? */
2700 if (~flags
& mask
& PKT_ALIAS_LOG
) {
2701 UninitPacketAliasLog();
2705 /* Start punching holes in the firewall? */
2706 if (flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2709 /* Stop punching holes in the firewall? */
2710 if (~flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2715 /* Other flags can be set/cleared without special action */
2716 packetAliasMode
= (flags
& mask
) | (packetAliasMode
& ~mask
);
2717 return packetAliasMode
;
2722 PacketAliasCheckNewLink(void)
2724 return newDefaultLink
;
2731 Code to support firewall punching. This shouldn't really be in this
2732 file, but making variables global is evil too.
2735 /* Firewall include files */
2737 #include <netinet/ip_fw.h>
2741 static void ClearAllFWHoles(void);
2743 static int fireWallBaseNum
; /* The first firewall entry free for our use */
2744 static int fireWallNumNums
; /* How many entries can we use? */
2745 static int fireWallActiveNum
; /* Which entry did we last use? */
2746 static char *fireWallField
; /* bool array for entries */
2748 #define fw_setfield(field, num) \
2750 (field)[(num) - fireWallBaseNum] = 1; \
2751 } /*lint -save -e717 */ while(0) /*lint -restore */
2752 #define fw_clrfield(field, num) \
2754 (field)[(num) - fireWallBaseNum] = 0; \
2755 } /*lint -save -e717 */ while(0) /*lint -restore */
2756 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2760 fireWallField
= malloc(fireWallNumNums
);
2761 if (fireWallField
) {
2762 memset(fireWallField
, 0, fireWallNumNums
);
2763 if (fireWallFD
< 0) {
2764 fireWallFD
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2767 fireWallActiveNum
= fireWallBaseNum
;
2772 UninitPunchFW(void) {
2774 if (fireWallFD
>= 0)
2778 free(fireWallField
);
2779 fireWallField
= NULL
;
2780 packetAliasMode
&= ~PKT_ALIAS_PUNCH_FW
;
2783 /* Make a certain link go through the firewall */
2785 PunchFWHole(struct alias_link
*link
) {
2786 int r
; /* Result code */
2787 struct ip_fw rule
; /* On-the-fly built rule */
2788 int fwhole
; /* Where to punch hole */
2790 /* Don't do anything unless we are asked to */
2791 if ( !(packetAliasMode
& PKT_ALIAS_PUNCH_FW
) ||
2793 link
->link_type
!= LINK_TCP
)
2796 memset(&rule
, 0, sizeof rule
);
2800 /* Find empty slot */
2801 for (fwhole
= fireWallActiveNum
;
2802 fwhole
< fireWallBaseNum
+ fireWallNumNums
&&
2803 fw_tstfield(fireWallField
, fwhole
);
2806 if (fwhole
== fireWallBaseNum
+ fireWallNumNums
) {
2807 for (fwhole
= fireWallBaseNum
;
2808 fwhole
< fireWallActiveNum
&&
2809 fw_tstfield(fireWallField
, fwhole
);
2812 if (fwhole
== fireWallActiveNum
) {
2813 /* No rule point empty - we can't punch more holes. */
2814 fireWallActiveNum
= fireWallBaseNum
;
2816 fprintf(stderr
, "libalias: Unable to create firewall hole!\n");
2821 /* Start next search at next position */
2822 fireWallActiveNum
= fwhole
+1;
2824 /* Build generic part of the two rules */
2825 rule
.fw_number
= fwhole
;
2826 IP_FW_SETNSRCP(&rule
, 1); /* Number of source ports. */
2827 IP_FW_SETNDSTP(&rule
, 1); /* Number of destination ports. */
2828 rule
.fw_flg
= IP_FW_F_ACCEPT
| IP_FW_F_IN
| IP_FW_F_OUT
;
2829 rule
.fw_prot
= IPPROTO_TCP
;
2830 rule
.fw_smsk
.s_addr
= INADDR_BROADCAST
;
2831 rule
.fw_dmsk
.s_addr
= INADDR_BROADCAST
;
2833 /* Build and apply specific part of the rules */
2834 rule
.fw_src
= GetOriginalAddress(link
);
2835 rule
.fw_dst
= GetDestAddress(link
);
2836 rule
.fw_uar
.fw_pts
[0] = ntohs(GetOriginalPort(link
));
2837 rule
.fw_uar
.fw_pts
[1] = ntohs(GetDestPort(link
));
2839 /* Skip non-bound links - XXX should not be strictly necessary,
2840 but seems to leave hole if not done. Leak of non-bound links?
2841 (Code should be left even if the problem is fixed - it is a
2842 clear optimization) */
2843 if (rule
.fw_uar
.fw_pts
[0] != 0 && rule
.fw_uar
.fw_pts
[1] != 0) {
2844 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, &rule
, sizeof rule
);
2847 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2849 rule
.fw_src
= GetDestAddress(link
);
2850 rule
.fw_dst
= GetOriginalAddress(link
);
2851 rule
.fw_uar
.fw_pts
[0] = ntohs(GetDestPort(link
));
2852 rule
.fw_uar
.fw_pts
[1] = ntohs(GetOriginalPort(link
));
2853 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, &rule
, sizeof rule
);
2856 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2859 /* Indicate hole applied */
2860 link
->data
.tcp
->fwhole
= fwhole
;
2861 fw_setfield(fireWallField
, fwhole
);
2864 /* Remove a hole in a firewall associated with a particular alias
2865 link. Calling this too often is harmless. */
2867 ClearFWHole(struct alias_link
*link
) {
2868 if (link
->link_type
== LINK_TCP
) {
2869 int fwhole
= link
->data
.tcp
->fwhole
; /* Where is the firewall hole? */
2875 memset(&rule
, 0, sizeof rule
);
2876 rule
.fw_number
= fwhole
;
2877 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &rule
, sizeof rule
))
2879 fw_clrfield(fireWallField
, fwhole
);
2880 link
->data
.tcp
->fwhole
= -1;
2884 /* Clear out the entire range dedicated to firewall holes. */
2886 ClearAllFWHoles(void) {
2887 struct ip_fw rule
; /* On-the-fly built rule */
2893 memset(&rule
, 0, sizeof rule
);
2894 for (i
= fireWallBaseNum
; i
< fireWallBaseNum
+ fireWallNumNums
; i
++) {
2896 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &rule
, sizeof rule
))
2899 memset(fireWallField
, 0, fireWallNumNums
);
2904 PacketAliasSetFWBase(unsigned int base
, unsigned int num
) {
2906 fireWallBaseNum
= base
;
2907 fireWallNumNums
= num
;