2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 2001 Charles Mott <cmott@scientech.com>
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
38 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * $FreeBSD: src/lib/libalias/alias_db.c,v 1.21.2.12 2001/08/21 03:50:25 brian Exp $
55 Alias_db.c encapsulates all data structures used for storing
56 packet aliasing data. Other parts of the aliasing software
57 access data through functions provided in this file.
59 Data storage is based on the notion of a "link", which is
60 established for ICMP echo/reply packets, UDP datagrams and
61 TCP stream connections. A link stores the original source
62 and destination addresses. For UDP and TCP, it also stores
63 source and destination port numbers, as well as an alias
64 port number. Links are also used to store information about
67 There is a facility for sweeping through and deleting old
68 links as new packets are sent through. A simple timeout is
69 used for ICMP and UDP links. TCP links are left alone unless
70 there is an incomplete connection, in which case the link
71 can be deleted after a certain amount of time.
74 Initial version: August, 1996 (cjm)
76 Version 1.4: September 16, 1996 (cjm)
77 Facility for handling incoming links added.
79 Version 1.6: September 18, 1996 (cjm)
80 ICMP data handling simplified.
82 Version 1.7: January 9, 1997 (cjm)
83 Fragment handling simplified.
84 Saves pointers for unresolved fragments.
85 Permits links for unspecified remote ports
86 or unspecified remote addresses.
87 Fixed bug which did not properly zero port
88 table entries after a link was deleted.
89 Cleaned up some obsolete comments.
91 Version 1.8: January 14, 1997 (cjm)
92 Fixed data type error in StartPoint().
93 (This error did not exist prior to v1.7
94 and was discovered and fixed by Ari Suutari)
96 Version 1.9: February 1, 1997
97 Optionally, connections initiated from packet aliasing host
98 machine will will not have their port number aliased unless it
99 conflicts with an aliasing port already being used. (cjm)
101 All options earlier being #ifdef'ed are now available through
102 a new interface, SetPacketAliasMode(). This allows run time
103 control (which is now available in PPP+pktAlias through the
104 'alias' keyword). (ee)
106 Added ability to create an alias port without
107 either destination address or port specified.
108 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
110 Removed K&R style function headers
111 and general cleanup. (ee)
113 Added packetAliasMode to replace compiler #defines's (ee)
115 Allocates sockets for partially specified
116 ports if ALIAS_USE_SOCKETS defined. (cjm)
118 Version 2.0: March, 1997
119 SetAliasAddress() will now clean up alias links
120 if the aliasing address is changed. (cjm)
122 PacketAliasPermanentLink() function added to support permanent
123 links. (J. Fortes suggested the need for this.)
126 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
128 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
131 These permanent links allow for incoming connections to
132 machines on the local network. They can be given with a
133 user-chosen amount of specificity, with increasing specificity
134 meaning more security. (cjm)
136 Quite a bit of rework to the basic engine. The portTable[]
137 array, which kept track of which ports were in use was replaced
138 by a table/linked list structure. (cjm)
140 SetExpire() function added. (cjm)
142 DeleteLink() no longer frees memory association with a pointer
143 to a fragment (this bug was first recognized by E. Eklund in
146 Version 2.1: May, 1997 (cjm)
147 Packet aliasing engine reworked so that it can handle
148 multiple external addresses rather than just a single
151 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
152 added to the API. The first function is a more generalized
153 version of PacketAliasPermanentLink(). The second function
154 implements static network address translation.
156 Version 3.2: July, 2000 (salander and satoh)
157 Added FindNewPortGroup to get contiguous range of port values.
159 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
160 link but not actually add one.
162 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
163 except that the alias port (from FindNewPortGroup) is provided
166 See HISTORY file for additional revisions.
170 /* System include files */
176 #include <sys/queue.h>
177 #include <sys/socket.h>
178 #include <sys/time.h>
179 #include <sys/types.h>
181 /* BSD network include files */
182 #include <netinet/in_systm.h>
183 #include <netinet/in.h>
184 #include <netinet/ip.h>
185 #include <netinet/tcp.h>
186 #include <arpa/inet.h>
189 #include "alias_local.h"
194 Constants (note: constants are also defined
195 near relevant functions or structs)
198 /* Sizes of input and output link tables */
199 #define LINK_TABLE_OUT_SIZE 101
200 #define LINK_TABLE_IN_SIZE 4001
202 /* Parameters used for cleanup of expired links */
203 #define ALIAS_CLEANUP_INTERVAL_SECS 60
204 #define ALIAS_CLEANUP_MAX_SPOKES 30
206 /* Timeouts (in seconds) for different link types */
207 #define ICMP_EXPIRE_TIME 60
208 #define UDP_EXPIRE_TIME 60
209 #define PROTO_EXPIRE_TIME 60
210 #define FRAGMENT_ID_EXPIRE_TIME 10
211 #define FRAGMENT_PTR_EXPIRE_TIME 30
213 /* TCP link expire time for different cases */
214 /* When the link has been used and closed - minimal grace time to
215 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
216 #ifndef TCP_EXPIRE_DEAD
217 # define TCP_EXPIRE_DEAD 10
220 /* When the link has been used and closed on one side - the other side
221 is allowed to still send data */
222 #ifndef TCP_EXPIRE_SINGLEDEAD
223 # define TCP_EXPIRE_SINGLEDEAD 90
226 /* When the link isn't yet up */
227 #ifndef TCP_EXPIRE_INITIAL
228 # define TCP_EXPIRE_INITIAL 300
231 /* When the link is up */
232 #ifndef TCP_EXPIRE_CONNECTED
233 # define TCP_EXPIRE_CONNECTED 86400
237 static int iChatAVHack
= 1;
240 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
241 These constants can be anything except zero, which indicates an
242 unknown port number. */
244 #define NO_DEST_PORT 1
245 #define NO_SRC_PORT 1
251 The fundamental data structure used in this program is
252 "struct alias_link". Whenever a TCP connection is made,
253 a UDP datagram is sent out, or an ICMP echo request is made,
254 a link record is made (if it has not already been created).
255 The link record is identified by the source address/port
256 and the destination address/port. In the case of an ICMP
257 echo request, the source port is treated as being equivalent
258 with the 16-bit ID number of the ICMP packet.
260 The link record also can store some auxiliary data. For
261 TCP connections that have had sequence and acknowledgment
262 modifications, data space is available to track these changes.
263 A state field is used to keep track in changes to the TCP
264 connection state. ID numbers of fragments can also be
265 stored in the auxiliary space. Pointers to unresolved
266 fragments can also be stored.
268 The link records support two independent chainings. Lookup
269 tables for input and out tables hold the initial pointers
270 the link chains. On input, the lookup table indexes on alias
271 port and link type. On output, the lookup table indexes on
272 source address, destination address, source port, destination
276 struct ack_data_record
/* used to save changes to ACK/sequence numbers */
284 struct tcp_state
/* Information about TCP connection */
286 int in
; /* State for outside -> inside */
287 int out
; /* State for inside -> outside */
288 int index
; /* Index to ACK data array */
289 int ack_modified
; /* Indicates whether ACK and sequence numbers */
293 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
294 saved for a modified TCP stream */
297 struct tcp_state state
;
298 struct ack_data_record ack
[N_LINK_TCP_DATA
];
299 int fwhole
; /* Which firewall record is used for this hole? */
302 struct server
/* LSNAT server pool (circular list) */
309 struct alias_link
/* Main data structure */
311 struct in_addr src_addr
; /* Address and port information */
312 struct in_addr dst_addr
;
313 struct in_addr alias_addr
;
314 struct in_addr proxy_addr
;
319 struct server
*server
;
321 int link_type
; /* Type of link: TCP, UDP, ICMP, proto, frag */
323 /* values for link_type */
324 #define LINK_ICMP IPPROTO_ICMP
325 #define LINK_UDP IPPROTO_UDP
326 #define LINK_TCP IPPROTO_TCP
327 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
328 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
329 #define LINK_ADDR (IPPROTO_MAX + 3)
330 #define LINK_PPTP (IPPROTO_MAX + 4)
332 int flags
; /* indicates special characteristics */
335 #define LINK_UNKNOWN_DEST_PORT 0x01
336 #define LINK_UNKNOWN_DEST_ADDR 0x02
337 #define LINK_PERMANENT 0x04
338 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
339 #define LINK_UNFIREWALLED 0x08
340 #define LINK_LAST_LINE_CRLF_TERMED 0x10
341 #define LINK_CONE 0x20
343 int timestamp
; /* Time link was last accessed */
344 int expire_time
; /* Expire time for link */
346 int sockfd
; /* socket descriptor */
348 LIST_ENTRY(alias_link
) list_out
; /* Linked list of pointers for */
349 LIST_ENTRY(alias_link
) list_in
; /* input and output lookup tables */
351 union /* Auxiliary data */
354 struct in_addr frag_addr
;
365 The global variables listed here are only accessed from
366 within alias_db.c and so are prefixed with the static
370 int packetAliasMode
; /* Mode flags */
371 /* - documented in alias.h */
373 static struct in_addr aliasAddress
; /* Address written onto source */
374 /* field of IP packet. */
376 static struct in_addr targetAddress
; /* IP address incoming packets */
377 /* are sent to if no aliasing */
378 /* link already exists */
380 static struct in_addr nullAddress
; /* Used as a dummy parameter for */
381 /* some function calls */
382 static LIST_HEAD(, alias_link
)
383 linkTableOut
[LINK_TABLE_OUT_SIZE
]; /* Lookup table of pointers to */
384 /* chains of link records. Each */
385 static LIST_HEAD(, alias_link
) /* link record is doubly indexed */
386 linkTableIn
[LINK_TABLE_IN_SIZE
]; /* into input and output lookup */
389 static int icmpLinkCount
; /* Link statistics */
390 static int udpLinkCount
;
391 static int tcpLinkCount
;
392 static int pptpLinkCount
;
393 static int protoLinkCount
;
394 static int fragmentIdLinkCount
;
395 static int fragmentPtrLinkCount
;
396 static int sockCount
;
398 static int cleanupIndex
; /* Index to chain of link table */
399 /* being inspected for old links */
401 static int timeStamp
; /* System time in seconds for */
404 static int lastCleanupTime
; /* Last time IncrementalCleanup() */
407 static int houseKeepingResidual
; /* used by HouseKeeping() */
409 static int deleteAllLinks
; /* If equal to zero, DeleteLink() */
410 /* will not remove permanent links */
412 static FILE *monitorFile
; /* File descriptor for link */
413 /* statistics monitoring file */
415 static int newDefaultLink
; /* Indicates if a new aliasing */
416 /* link has been created after a */
417 /* call to PacketAliasIn/Out(). */
420 static int fireWallFD
= -1; /* File descriptor to be able to */
421 /* control firewall. Opened by */
422 /* PacketAliasSetMode on first */
423 /* setting the PKT_ALIAS_PUNCH_FW */
433 /* Internal utility routines (used only in alias_db.c)
435 Lookup table starting points:
436 StartPointIn() -- link table initial search point for
438 StartPointOut() -- link table initial search point for
442 SeqDiff() -- difference between two TCP sequences
443 ShowAliasStats() -- send alias statistics to a monitor file
447 /* Local prototypes */
448 static u_int
StartPointIn(struct in_addr
, u_short
, int);
450 static u_int
StartPointOut(struct in_addr
, struct in_addr
,
451 u_short
, u_short
, int);
453 static int SeqDiff(u_long
, u_long
);
455 static void ShowAliasStats(void);
458 /* Firewall control */
459 static void InitPunchFW(void);
460 static void UninitPunchFW(void);
461 static void ClearFWHole(struct alias_link
*link
);
464 /* Log file control */
465 static void InitPacketAliasLog(void);
466 static void UninitPacketAliasLog(void);
469 StartPointIn(struct in_addr alias_addr
,
475 n
= alias_addr
.s_addr
;
476 if (link_type
!= LINK_PPTP
)
479 return(n
% LINK_TABLE_IN_SIZE
);
484 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
485 u_short src_port
, u_short dst_port
, int link_type
)
490 n
+= dst_addr
.s_addr
;
491 if (link_type
!= LINK_PPTP
) {
497 return(n
% LINK_TABLE_OUT_SIZE
);
502 SeqDiff(u_long x
, u_long y
)
504 /* Return the difference between two TCP sequence numbers */
507 This function is encapsulated in case there are any unusual
508 arithmetic conditions that need to be considered.
511 return (ntohl(y
) - ntohl(x
));
518 /* Used for debugging */
522 fprintf(monitorFile
, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
529 fragmentPtrLinkCount
);
531 fprintf(monitorFile
, " / tot=%d (sock=%d)\n",
532 icmpLinkCount
+ udpLinkCount
536 + fragmentIdLinkCount
537 + fragmentPtrLinkCount
,
548 /* Internal routines for finding, deleting and adding links
551 GetNewPort() -- find and reserve new alias port number
552 GetSocket() -- try to allocate a socket for a given port
554 Link creation and deletion:
555 CleanupAliasData() - remove all link chains from lookup table
556 IncrementalCleanup() - look for stale links in a single chain
557 DeleteLink() - remove link
559 ReLink() - change link
562 FindLinkOut() - find link for outgoing packets
563 FindLinkIn() - find link for incoming packets
566 FindNewPortGroup() - find an available group of ports
569 /* Local prototypes */
570 static int GetNewPort(struct alias_link
*, int);
572 static u_short
GetSocket(u_short
, int *, int);
574 static void CleanupAliasData(void);
576 static void IncrementalCleanup(void);
578 static void DeleteLink(struct alias_link
*);
580 static struct alias_link
*
581 AddLink(struct in_addr
, struct in_addr
, struct in_addr
,
582 u_short
, u_short
, int, int);
584 static struct alias_link
*
585 ReLink(struct alias_link
*,
586 struct in_addr
, struct in_addr
, struct in_addr
,
587 u_short
, u_short
, int, int);
589 static struct alias_link
*
590 FindLinkOut(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
592 static struct alias_link
*
593 FindLinkIn(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
596 #define ALIAS_PORT_BASE 0x08000
597 #define ALIAS_PORT_MASK 0x07fff
598 #define ALIAS_PORT_MASK_EVEN 0x07ffe
599 #define GET_NEW_PORT_MAX_ATTEMPTS 20
601 #define GET_ALIAS_PORT -1
602 #define GET_ALIAS_ID GET_ALIAS_PORT
604 #define FIND_EVEN_ALIAS_BASE 1
606 /* GetNewPort() allocates port numbers. Note that if a port number
607 is already in use, that does not mean that it cannot be used by
608 another link concurrently. This is because GetNewPort() looks for
609 unused triplets: (dest addr, dest port, alias port). */
612 GetNewPort(struct alias_link
*link
, int alias_port_param
)
620 Description of alias_port_param for GetNewPort(). When
621 this parameter is zero or positive, it precisely specifies
622 the port number. GetNewPort() will return this number
623 without check that it is in use.
625 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
626 selected port number.
629 if (alias_port_param
== GET_ALIAS_PORT
)
632 * The aliasing port is automatically selected
633 * by one of two methods below:
635 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
637 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
)
640 * When the PKT_ALIAS_SAME_PORTS option is
641 * chosen, the first try will be the
642 * actual source port. If this is already
643 * in use, the remainder of the trials
646 port_net
= link
->src_port
;
647 port_sys
= ntohs(port_net
);
651 /* First trial and all subsequent are random. */
652 port_sys
= random() & ALIAS_PORT_MASK
;
653 port_sys
+= ALIAS_PORT_BASE
;
654 port_net
= htons(port_sys
);
657 else if (alias_port_param
>= 0 && alias_port_param
< 0x10000)
659 link
->alias_port
= (u_short
) alias_port_param
;
665 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
666 fprintf(stderr
, "input parameter error\n");
672 /* Port number search */
673 for (i
=0; i
<max_trials
; i
++)
676 struct alias_link
*search_result
;
678 search_result
= FindLinkIn(link
->dst_addr
, link
->alias_addr
,
679 link
->dst_port
, port_net
,
682 if (search_result
== NULL
)
684 else if (!(link
->flags
& LINK_PARTIALLY_SPECIFIED
)
685 && (search_result
->flags
& LINK_PARTIALLY_SPECIFIED
))
692 if ((packetAliasMode
& PKT_ALIAS_USE_SOCKETS
)
693 && (link
->flags
& LINK_PARTIALLY_SPECIFIED
)
694 && ((link
->link_type
== LINK_TCP
) ||
695 (link
->link_type
== LINK_UDP
)))
697 if (GetSocket(port_net
, &link
->sockfd
, link
->link_type
))
699 link
->alias_port
= port_net
;
705 link
->alias_port
= port_net
;
710 port_sys
= random() & ALIAS_PORT_MASK
;
711 port_sys
+= ALIAS_PORT_BASE
;
712 port_net
= htons(port_sys
);
716 fprintf(stderr
, "PacketAlias/GetnewPort(): ");
717 fprintf(stderr
, "could not find free port\n");
725 GetSocket(u_short port_net
, int *sockfd
, int link_type
)
729 struct sockaddr_in sock_addr
;
731 if (link_type
== LINK_TCP
)
732 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
733 else if (link_type
== LINK_UDP
)
734 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
738 fprintf(stderr
, "PacketAlias/GetSocket(): ");
739 fprintf(stderr
, "incorrect link type\n");
747 fprintf(stderr
, "PacketAlias/GetSocket(): ");
748 fprintf(stderr
, "socket() error %d\n", *sockfd
);
753 sock_addr
.sin_family
= AF_INET
;
754 sock_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
755 sock_addr
.sin_port
= port_net
;
758 (struct sockaddr
*) &sock_addr
,
774 /* FindNewPortGroup() returns a base port number for an available
775 range of contiguous port numbers. Note that if a port number
776 is already in use, that does not mean that it cannot be used by
777 another link concurrently. This is because FindNewPortGroup()
778 looks for unused triplets: (dest addr, dest port, alias port). */
781 FindNewPortGroup(struct in_addr dst_addr
,
782 struct in_addr alias_addr
,
795 * Get link_type from protocol
801 link_type
= LINK_UDP
;
804 link_type
= LINK_TCP
;
812 * The aliasing port is automatically selected
813 * by one of two methods below:
815 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
817 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
) {
819 * When the ALIAS_SAME_PORTS option is
820 * chosen, the first try will be the
821 * actual source port. If this is already
822 * in use, the remainder of the trials
825 port_sys
= ntohs(src_port
);
829 /* First trial and all subsequent are random. */
830 if (align
== FIND_EVEN_ALIAS_BASE
)
831 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
833 port_sys
= random() & ALIAS_PORT_MASK
;
835 port_sys
+= ALIAS_PORT_BASE
;
838 /* Port number search */
839 for (i
= 0; i
< max_trials
; i
++) {
841 struct alias_link
*search_result
;
843 for (j
= 0; j
< port_count
; j
++)
844 if (0 != (search_result
= FindLinkIn(dst_addr
, alias_addr
,
845 dst_port
, htons(port_sys
+ j
),
849 /* Found a good range, return base */
851 return (htons(port_sys
));
853 /* Find a new base to try */
854 if (align
== FIND_EVEN_ALIAS_BASE
)
855 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
857 port_sys
= random() & ALIAS_PORT_MASK
;
859 port_sys
+= ALIAS_PORT_BASE
;
863 fprintf(stderr
, "PacketAlias/FindNewPortGroup(): ");
864 fprintf(stderr
, "could not find free port(s)\n");
871 CleanupAliasData(void)
873 struct alias_link
*link
;
877 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
879 link
= LIST_FIRST(&linkTableOut
[i
]);
882 struct alias_link
*link_next
;
883 link_next
= LIST_NEXT(link
, list_out
);
895 IncrementalCleanup(void)
898 struct alias_link
*link
;
901 link
= LIST_FIRST(&linkTableOut
[cleanupIndex
++]);
905 struct alias_link
*link_next
;
907 link_next
= LIST_NEXT(link
, list_out
);
908 idelta
= timeStamp
- link
->timestamp
;
909 switch (link
->link_type
)
912 if (idelta
> link
->expire_time
)
914 struct tcp_dat
*tcp_aux
;
916 tcp_aux
= link
->data
.tcp
;
917 if (tcp_aux
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
918 || tcp_aux
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
926 if (idelta
> link
->expire_time
)
936 if (cleanupIndex
== LINK_TABLE_OUT_SIZE
)
941 DeleteLink(struct alias_link
*link
)
944 /* Don't do anything if the link is marked permanent */
945 if (deleteAllLinks
== 0 && link
->flags
& LINK_PERMANENT
)
949 /* Delete associated firewall hole, if any */
953 /* Free memory allocated for LSNAT server pool */
954 if (link
->server
!= NULL
) {
955 struct server
*head
, *curr
, *next
;
957 head
= curr
= link
->server
;
961 } while ((curr
= next
) != head
);
964 /* Adjust output table pointers */
965 LIST_REMOVE(link
, list_out
);
967 /* Adjust input table pointers */
968 LIST_REMOVE(link
, list_in
);
970 /* Close socket, if one has been allocated */
971 if (link
->sockfd
!= -1)
977 /* Link-type dependent cleanup */
978 switch(link
->link_type
)
988 free(link
->data
.tcp
);
993 case LINK_FRAGMENT_ID
:
994 fragmentIdLinkCount
--;
996 case LINK_FRAGMENT_PTR
:
997 fragmentPtrLinkCount
--;
998 if (link
->data
.frag_ptr
!= NULL
)
999 free(link
->data
.frag_ptr
);
1009 if ((packetAliasMode
& PKT_ALIAS_LOG
) != 0 &&
1010 !IN_MULTICAST(link
->src_addr
.s_addr
) &&
1011 !IN_MULTICAST(link
->dst_addr
.s_addr
))
1017 switch(link
->link_type
)
1028 fprintf(monitorFile
, "Deleted%s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1030 inet_ntop(AF_INET
, &link
->src_addr
, src
, sizeof(src
)), link
->src_port
,
1031 inet_ntop(AF_INET
, &link
->dst_addr
, dst
, sizeof(dst
)), link
->dst_port
,
1032 inet_ntop(AF_INET
, &link
->alias_addr
, alias
, sizeof(alias
)), link
->alias_port
,
1033 dst
, link
->dst_port
);
1034 fflush(monitorFile
);
1037 if (packetAliasMode
& PKT_ALIAS_LOG
)
1046 static struct alias_link
*
1047 AddLink(struct in_addr src_addr
,
1048 struct in_addr dst_addr
,
1049 struct in_addr alias_addr
,
1052 int alias_port_param
, /* if less than zero, alias */
1053 int link_type
) /* port will be automatically */
1054 { /* chosen. If greater than */
1055 u_int start_point
; /* zero, equal to alias port */
1056 struct alias_link
*link
;
1058 link
= malloc(sizeof(struct alias_link
));
1061 /* Basic initialization */
1062 link
->src_addr
= src_addr
;
1063 link
->dst_addr
= dst_addr
;
1064 link
->alias_addr
= alias_addr
;
1065 link
->proxy_addr
.s_addr
= INADDR_ANY
;
1066 link
->src_port
= src_port
;
1067 link
->dst_port
= dst_port
;
1068 link
->proxy_port
= 0;
1069 link
->server
= NULL
;
1070 link
->link_type
= link_type
;
1073 link
->timestamp
= timeStamp
;
1075 /* Expiration time */
1079 link
->expire_time
= ICMP_EXPIRE_TIME
;
1082 if (dst_addr
.s_addr
== 0 && dst_port
== 0)
1083 link
->expire_time
= UDP_EXPIRE_TIME
* 5;
1085 link
->expire_time
= UDP_EXPIRE_TIME
;
1088 link
->expire_time
= TCP_EXPIRE_INITIAL
;
1091 link
->flags
|= LINK_PERMANENT
; /* no timeout. */
1093 case LINK_FRAGMENT_ID
:
1094 link
->expire_time
= FRAGMENT_ID_EXPIRE_TIME
;
1096 case LINK_FRAGMENT_PTR
:
1097 link
->expire_time
= FRAGMENT_PTR_EXPIRE_TIME
;
1102 link
->expire_time
= PROTO_EXPIRE_TIME
;
1106 /* Determine alias flags */
1107 if (dst_addr
.s_addr
== INADDR_ANY
)
1108 link
->flags
|= LINK_UNKNOWN_DEST_ADDR
;
1110 link
->flags
|= LINK_UNKNOWN_DEST_PORT
;
1112 /* Determine alias port */
1113 if (GetNewPort(link
, alias_port_param
) != 0)
1119 /* Link-type dependent initialization */
1122 struct tcp_dat
*aux_tcp
;
1131 aux_tcp
= malloc(sizeof(struct tcp_dat
));
1132 if (aux_tcp
!= NULL
)
1137 aux_tcp
->state
.in
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1138 aux_tcp
->state
.out
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1139 aux_tcp
->state
.index
= 0;
1140 aux_tcp
->state
.ack_modified
= 0;
1141 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
1142 aux_tcp
->ack
[i
].active
= 0;
1143 aux_tcp
->fwhole
= -1;
1144 link
->data
.tcp
= aux_tcp
;
1149 fprintf(stderr
, "PacketAlias/AddLink: ");
1150 fprintf(stderr
, " cannot allocate auxiliary TCP data\n");
1159 case LINK_FRAGMENT_ID
:
1160 fragmentIdLinkCount
++;
1162 case LINK_FRAGMENT_PTR
:
1163 fragmentPtrLinkCount
++;
1172 /* Set up pointers for output lookup table */
1173 start_point
= StartPointOut(src_addr
, dst_addr
,
1174 src_port
, dst_port
, link_type
);
1175 LIST_INSERT_HEAD(&linkTableOut
[start_point
], link
, list_out
);
1177 /* Set up pointers for input lookup table */
1178 start_point
= StartPointIn(alias_addr
, link
->alias_port
, link_type
);
1179 LIST_INSERT_HEAD(&linkTableIn
[start_point
], link
, list_in
);
1184 fprintf(stderr
, "PacketAlias/AddLink(): ");
1185 fprintf(stderr
, "malloc() call failed.\n");
1190 if ((packetAliasMode
& PKT_ALIAS_LOG
) != 0 &&
1191 !IN_MULTICAST(link
->src_addr
.s_addr
) &&
1192 !IN_MULTICAST(link
->dst_addr
.s_addr
))
1198 switch(link
->link_type
)
1209 fprintf(monitorFile
, "Added %s %s:%d<->%s:%d to %s:%d<->%s:%d\n",
1211 inet_ntop(AF_INET
, &link
->src_addr
, src
, sizeof(src
)), link
->src_port
,
1212 inet_ntop(AF_INET
, &link
->dst_addr
, dst
, sizeof(dst
)), link
->dst_port
,
1213 inet_ntop(AF_INET
, &link
->alias_addr
, alias
, sizeof(alias
)), link
->alias_port
,
1214 dst
, link
->dst_port
);
1217 if (packetAliasMode
& PKT_ALIAS_LOG
)
1224 static struct alias_link
*
1225 ReLink(struct alias_link
*old_link
,
1226 struct in_addr src_addr
,
1227 struct in_addr dst_addr
,
1228 struct in_addr alias_addr
,
1231 int alias_port_param
, /* if less than zero, alias */
1232 int link_type
) /* port will be automatically */
1233 { /* chosen. If greater than */
1234 struct alias_link
*new_link
; /* zero, equal to alias port */
1236 new_link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1237 src_port
, dst_port
, alias_port_param
,
1240 if (new_link
!= NULL
&&
1241 old_link
->link_type
== LINK_TCP
&&
1242 old_link
->data
.tcp
->fwhole
> 0) {
1243 PunchFWHole(new_link
);
1246 if ((old_link
->flags
& LINK_CONE
) == 0)
1247 DeleteLink(old_link
);
1251 static struct alias_link
*
1252 _FindLinkOut(struct in_addr src_addr
,
1253 struct in_addr dst_addr
,
1257 int replace_partial_links
)
1260 struct alias_link
*link
;
1262 i
= StartPointOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
);
1263 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1265 if (link
->src_addr
.s_addr
== src_addr
.s_addr
1266 && link
->server
== NULL
1267 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1268 && link
->dst_port
== dst_port
1269 && link
->src_port
== src_port
1270 && link
->link_type
== link_type
)
1272 link
->timestamp
= timeStamp
;
1277 /* Search for partially specified links. */
1278 if (link
== NULL
&& replace_partial_links
)
1280 if (dst_port
!= 0 && dst_addr
.s_addr
!= INADDR_ANY
)
1282 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, 0,
1285 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
,
1286 dst_port
, link_type
, 0);
1289 (dst_port
!= 0 || dst_addr
.s_addr
!= INADDR_ANY
))
1291 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
, 0,
1297 src_addr
, dst_addr
, link
->alias_addr
,
1298 src_port
, dst_port
, link
->alias_port
,
1306 static struct alias_link
*
1307 FindLinkOut(struct in_addr src_addr
,
1308 struct in_addr dst_addr
,
1312 int replace_partial_links
)
1314 struct alias_link
*link
;
1316 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
,
1317 link_type
, replace_partial_links
);
1321 /* The following allows permanent links to be
1322 specified as using the default source address
1323 (i.e. device interface address) without knowing
1324 in advance what that address is. */
1325 if (aliasAddress
.s_addr
!= 0 &&
1326 src_addr
.s_addr
== aliasAddress
.s_addr
)
1328 link
= _FindLinkOut(nullAddress
, dst_addr
, src_port
, dst_port
,
1329 link_type
, replace_partial_links
);
1337 static struct alias_link
*
1338 _FindLinkIn(struct in_addr dst_addr
,
1339 struct in_addr alias_addr
,
1343 int replace_partial_links
)
1347 struct alias_link
*link
;
1348 struct alias_link
*link_fully_specified
;
1349 struct alias_link
*link_unknown_all
;
1350 struct alias_link
*link_unknown_dst_addr
;
1351 struct alias_link
*link_unknown_dst_port
;
1353 /* Initialize pointers */
1354 link_fully_specified
= NULL
;
1355 link_unknown_all
= NULL
;
1356 link_unknown_dst_addr
= NULL
;
1357 link_unknown_dst_port
= NULL
;
1359 /* If either the dest addr or port is unknown, the search
1360 loop will have to know about this. */
1363 if (dst_addr
.s_addr
== INADDR_ANY
)
1364 flags_in
|= LINK_UNKNOWN_DEST_ADDR
;
1366 flags_in
|= LINK_UNKNOWN_DEST_PORT
;
1369 start_point
= StartPointIn(alias_addr
, alias_port
, link_type
);
1370 LIST_FOREACH(link
, &linkTableIn
[start_point
], list_in
)
1374 flags
= flags_in
| link
->flags
;
1375 if (!(flags
& LINK_PARTIALLY_SPECIFIED
))
1377 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1378 && link
->alias_port
== alias_port
1379 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1380 && link
->dst_port
== dst_port
1381 && link
->link_type
== link_type
)
1383 link_fully_specified
= link
;
1387 else if ((flags
& LINK_UNKNOWN_DEST_ADDR
)
1388 && (flags
& LINK_UNKNOWN_DEST_PORT
))
1390 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1391 && link
->alias_port
== alias_port
1392 && link
->link_type
== link_type
)
1394 if (link_unknown_all
== NULL
)
1395 link_unknown_all
= link
;
1398 else if (flags
& LINK_UNKNOWN_DEST_ADDR
)
1400 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1401 && link
->alias_port
== alias_port
1402 && link
->link_type
== link_type
1403 && link
->dst_port
== dst_port
)
1405 if (link_unknown_dst_addr
== NULL
)
1406 link_unknown_dst_addr
= link
;
1409 else if (flags
& LINK_UNKNOWN_DEST_PORT
)
1411 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1412 && link
->alias_port
== alias_port
1413 && link
->link_type
== link_type
1414 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
)
1416 if (link_unknown_dst_port
== NULL
)
1417 link_unknown_dst_port
= link
;
1424 if (link_fully_specified
!= NULL
)
1426 link_fully_specified
->timestamp
= timeStamp
;
1427 link
= link_fully_specified
;
1429 else if (link_unknown_dst_port
!= NULL
)
1430 link
= link_unknown_dst_port
;
1431 else if (link_unknown_dst_addr
!= NULL
)
1432 link
= link_unknown_dst_addr
;
1433 else if (link_unknown_all
!= NULL
)
1434 link
= link_unknown_all
;
1438 if (replace_partial_links
&&
1439 (link
->flags
& LINK_PARTIALLY_SPECIFIED
|| link
->server
!= NULL
))
1441 struct in_addr src_addr
;
1444 if (link
->server
!= NULL
) { /* LSNAT link */
1445 src_addr
= link
->server
->addr
;
1446 src_port
= link
->server
->port
;
1447 link
->server
= link
->server
->next
;
1449 src_addr
= link
->src_addr
;
1450 src_port
= link
->src_port
;
1454 src_addr
, dst_addr
, alias_addr
,
1455 src_port
, dst_port
, alias_port
,
1462 static struct alias_link
*
1463 FindLinkIn(struct in_addr dst_addr
,
1464 struct in_addr alias_addr
,
1468 int replace_partial_links
)
1470 struct alias_link
*link
;
1472 link
= _FindLinkIn(dst_addr
, alias_addr
, dst_port
, alias_port
,
1473 link_type
, replace_partial_links
);
1477 /* The following allows permanent links to be
1478 specified as using the default aliasing address
1479 (i.e. device interface address) without knowing
1480 in advance what that address is. */
1481 if (aliasAddress
.s_addr
!= 0 &&
1482 alias_addr
.s_addr
== aliasAddress
.s_addr
)
1484 link
= _FindLinkIn(dst_addr
, nullAddress
, dst_port
, alias_port
,
1485 link_type
, replace_partial_links
);
1495 /* External routines for finding/adding links
1497 -- "external" means outside alias_db.c, but within alias*.c --
1499 FindIcmpIn(), FindIcmpOut()
1500 FindFragmentIn1(), FindFragmentIn2()
1501 AddFragmentPtrLink(), FindFragmentPtr()
1502 FindProtoIn(), FindProtoOut()
1503 FindUdpTcpIn(), FindUdpTcpOut()
1504 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1505 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1506 FindOriginalAddress(), FindAliasAddress()
1508 (prototypes in alias_local.h)
1513 FindIcmpIn(struct in_addr dst_addr
,
1514 struct in_addr alias_addr
,
1518 struct alias_link
*link
;
1520 link
= FindLinkIn(dst_addr
, alias_addr
,
1521 NO_DEST_PORT
, id_alias
,
1523 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1525 struct in_addr target_addr
;
1527 target_addr
= FindOriginalAddress(alias_addr
);
1528 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1529 id_alias
, NO_DEST_PORT
, id_alias
,
1538 FindIcmpOut(struct in_addr src_addr
,
1539 struct in_addr dst_addr
,
1543 struct alias_link
* link
;
1545 link
= FindLinkOut(src_addr
, dst_addr
,
1548 if (link
== NULL
&& create
)
1550 struct in_addr alias_addr
;
1552 alias_addr
= FindAliasAddress(src_addr
);
1553 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1554 id
, NO_DEST_PORT
, GET_ALIAS_ID
,
1563 FindFragmentIn1(struct in_addr dst_addr
,
1564 struct in_addr alias_addr
,
1567 struct alias_link
*link
;
1569 link
= FindLinkIn(dst_addr
, alias_addr
,
1570 NO_DEST_PORT
, ip_id
,
1571 LINK_FRAGMENT_ID
, 0);
1575 link
= AddLink(nullAddress
, dst_addr
, alias_addr
,
1576 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1585 FindFragmentIn2(struct in_addr dst_addr
, /* Doesn't add a link if one */
1586 struct in_addr alias_addr
, /* is not found. */
1589 return FindLinkIn(dst_addr
, alias_addr
,
1590 NO_DEST_PORT
, ip_id
,
1591 LINK_FRAGMENT_ID
, 0);
1596 AddFragmentPtrLink(struct in_addr dst_addr
,
1599 return AddLink(nullAddress
, dst_addr
, nullAddress
,
1600 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1606 FindFragmentPtr(struct in_addr dst_addr
,
1609 return FindLinkIn(dst_addr
, nullAddress
,
1610 NO_DEST_PORT
, ip_id
,
1611 LINK_FRAGMENT_PTR
, 0);
1616 FindProtoIn(struct in_addr dst_addr
,
1617 struct in_addr alias_addr
,
1620 struct alias_link
*link
;
1622 link
= FindLinkIn(dst_addr
, alias_addr
,
1626 if (link
== NULL
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1628 struct in_addr target_addr
;
1630 target_addr
= FindOriginalAddress(alias_addr
);
1631 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1632 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1641 FindProtoOut(struct in_addr src_addr
,
1642 struct in_addr dst_addr
,
1645 struct alias_link
*link
;
1647 link
= FindLinkOut(src_addr
, dst_addr
,
1648 NO_SRC_PORT
, NO_DEST_PORT
,
1653 struct in_addr alias_addr
;
1655 alias_addr
= FindAliasAddress(src_addr
);
1656 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1657 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1666 FindUdpTcpIn(struct in_addr dst_addr
,
1667 struct in_addr alias_addr
,
1674 struct alias_link
*link
;
1679 link_type
= LINK_UDP
;
1682 link_type
= LINK_TCP
;
1689 link
= FindLinkIn(dst_addr
, alias_addr
,
1690 dst_port
, alias_port
,
1693 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1695 struct in_addr target_addr
;
1697 target_addr
= FindOriginalAddress(alias_addr
);
1698 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1699 alias_port
, dst_port
, alias_port
,
1708 FindUdpTcpOut(struct in_addr src_addr
,
1709 struct in_addr dst_addr
,
1716 struct alias_link
*link
;
1721 link_type
= LINK_UDP
;
1724 link_type
= LINK_TCP
;
1731 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
, create
);
1733 if (link
== NULL
&& create
)
1735 struct in_addr alias_addr
;
1736 struct in_addr dst_addr2
= dst_addr
;
1737 u_short dst_port2
= dst_port
;
1739 alias_addr
= FindAliasAddress(src_addr
);
1741 if (iChatAVHack
&& link_type
== LINK_UDP
&& dst_port
== htons(5678)) {
1742 dst_addr2
.s_addr
= 0;
1745 link
= AddLink(src_addr
, dst_addr2
, alias_addr
,
1746 src_port
, dst_port2
, GET_ALIAS_PORT
,
1749 (link
->flags
& (LINK_UNKNOWN_DEST_ADDR
| LINK_UNKNOWN_DEST_PORT
)) != 0)
1751 link
->flags
|= LINK_CONE
;
1752 link
= ReLink(link
, link
->src_addr
, dst_addr
, link
->alias_addr
,
1753 link
->src_port
, dst_port
, link
->alias_port
, link_type
);
1762 AddPptp(struct in_addr src_addr
,
1763 struct in_addr dst_addr
,
1764 struct in_addr alias_addr
,
1765 u_int16_t src_call_id
)
1767 struct alias_link
*link
;
1769 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1770 src_call_id
, 0, GET_ALIAS_PORT
,
1778 FindPptpOutByCallId(struct in_addr src_addr
,
1779 struct in_addr dst_addr
,
1780 u_int16_t src_call_id
)
1783 struct alias_link
*link
;
1785 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1786 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1787 if (link
->link_type
== LINK_PPTP
&&
1788 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1789 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1790 link
->src_port
== src_call_id
)
1798 FindPptpOutByPeerCallId(struct in_addr src_addr
,
1799 struct in_addr dst_addr
,
1800 u_int16_t dst_call_id
)
1803 struct alias_link
*link
;
1805 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1806 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1807 if (link
->link_type
== LINK_PPTP
&&
1808 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1809 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1810 link
->dst_port
== dst_call_id
)
1818 FindPptpInByCallId(struct in_addr dst_addr
,
1819 struct in_addr alias_addr
,
1820 u_int16_t dst_call_id
)
1823 struct alias_link
*link
;
1825 i
= StartPointIn(alias_addr
, 0, LINK_PPTP
);
1826 LIST_FOREACH(link
, &linkTableIn
[i
], list_in
)
1827 if (link
->link_type
== LINK_PPTP
&&
1828 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1829 link
->alias_addr
.s_addr
== alias_addr
.s_addr
&&
1830 link
->dst_port
== dst_call_id
)
1838 FindPptpInByPeerCallId(struct in_addr dst_addr
,
1839 struct in_addr alias_addr
,
1840 u_int16_t alias_call_id
)
1842 struct alias_link
*link
;
1844 link
= FindLinkIn(dst_addr
, alias_addr
,
1845 0/* any */, alias_call_id
,
1854 FindRtspOut(struct in_addr src_addr
,
1855 struct in_addr dst_addr
,
1861 struct alias_link
*link
;
1866 link_type
= LINK_UDP
;
1869 link_type
= LINK_TCP
;
1876 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, 0, link_type
, 1);
1880 struct in_addr alias_addr
;
1882 alias_addr
= FindAliasAddress(src_addr
);
1883 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1884 src_port
, 0, alias_port
,
1893 FindOriginalAddress(struct in_addr alias_addr
)
1895 struct alias_link
*link
;
1897 link
= FindLinkIn(nullAddress
, alias_addr
,
1898 0, 0, LINK_ADDR
, 0);
1902 if (targetAddress
.s_addr
== INADDR_ANY
)
1904 else if (targetAddress
.s_addr
== INADDR_NONE
)
1905 return aliasAddress
;
1907 return targetAddress
;
1911 if (link
->server
!= NULL
) { /* LSNAT link */
1912 struct in_addr src_addr
;
1914 src_addr
= link
->server
->addr
;
1915 link
->server
= link
->server
->next
;
1917 } else if (link
->src_addr
.s_addr
== INADDR_ANY
)
1918 return aliasAddress
;
1920 return link
->src_addr
;
1926 FindAliasAddress(struct in_addr original_addr
)
1928 struct alias_link
*link
;
1930 link
= FindLinkOut(original_addr
, nullAddress
,
1931 0, 0, LINK_ADDR
, 0);
1934 return aliasAddress
;
1938 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1939 return aliasAddress
;
1941 return link
->alias_addr
;
1946 /* External routines for getting or changing link data
1947 (external to alias_db.c, but internal to alias*.c)
1949 SetFragmentData(), GetFragmentData()
1950 SetFragmentPtr(), GetFragmentPtr()
1951 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1952 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1953 GetOriginalPort(), GetAliasPort()
1954 SetAckModified(), GetAckModified()
1955 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1956 SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
1962 SetFragmentAddr(struct alias_link
*link
, struct in_addr src_addr
)
1964 link
->data
.frag_addr
= src_addr
;
1969 GetFragmentAddr(struct alias_link
*link
, struct in_addr
*src_addr
)
1971 *src_addr
= link
->data
.frag_addr
;
1976 SetFragmentPtr(struct alias_link
*link
, char *fptr
)
1978 link
->data
.frag_ptr
= fptr
;
1983 GetFragmentPtr(struct alias_link
*link
, char **fptr
)
1985 *fptr
= link
->data
.frag_ptr
;
1990 SetStateIn(struct alias_link
*link
, int state
)
1992 /* TCP input state */
1994 case ALIAS_TCP_STATE_DISCONNECTED
:
1995 if (link
->data
.tcp
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
1996 link
->expire_time
= TCP_EXPIRE_DEAD
;
1998 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
2000 case ALIAS_TCP_STATE_CONNECTED
:
2001 if (link
->data
.tcp
->state
.out
== ALIAS_TCP_STATE_CONNECTED
)
2002 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
2007 link
->data
.tcp
->state
.in
= state
;
2012 SetStateOut(struct alias_link
*link
, int state
)
2014 /* TCP output state */
2016 case ALIAS_TCP_STATE_DISCONNECTED
:
2017 if (link
->data
.tcp
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
)
2018 link
->expire_time
= TCP_EXPIRE_DEAD
;
2020 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
2022 case ALIAS_TCP_STATE_CONNECTED
:
2023 if (link
->data
.tcp
->state
.in
== ALIAS_TCP_STATE_CONNECTED
)
2024 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
2029 link
->data
.tcp
->state
.out
= state
;
2034 GetStateIn(struct alias_link
*link
)
2036 /* TCP input state */
2037 return link
->data
.tcp
->state
.in
;
2042 GetStateOut(struct alias_link
*link
)
2044 /* TCP output state */
2045 return link
->data
.tcp
->state
.out
;
2050 GetOriginalAddress(struct alias_link
*link
)
2052 if (link
->src_addr
.s_addr
== INADDR_ANY
)
2053 return aliasAddress
;
2055 return(link
->src_addr
);
2060 GetDestAddress(struct alias_link
*link
)
2062 return(link
->dst_addr
);
2067 GetAliasAddress(struct alias_link
*link
)
2069 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
2070 return aliasAddress
;
2072 return link
->alias_addr
;
2077 GetDefaultAliasAddress()
2079 return aliasAddress
;
2084 SetDefaultAliasAddress(struct in_addr alias_addr
)
2086 aliasAddress
= alias_addr
;
2091 GetOriginalPort(struct alias_link
*link
)
2093 return(link
->src_port
);
2098 GetAliasPort(struct alias_link
*link
)
2100 return(link
->alias_port
);
2105 GetDestPort(struct alias_link
*link
)
2107 return(link
->dst_port
);
2112 SetAckModified(struct alias_link
*link
)
2114 /* Indicate that ACK numbers have been modified in a TCP connection */
2115 link
->data
.tcp
->state
.ack_modified
= 1;
2120 GetProxyAddress(struct alias_link
*link
)
2122 return link
->proxy_addr
;
2127 SetProxyAddress(struct alias_link
*link
, struct in_addr addr
)
2129 link
->proxy_addr
= addr
;
2134 GetProxyPort(struct alias_link
*link
)
2136 return link
->proxy_port
;
2141 SetProxyPort(struct alias_link
*link
, u_short port
)
2143 link
->proxy_port
= port
;
2148 GetAckModified(struct alias_link
*link
)
2150 /* See if ACK numbers have been modified */
2151 return link
->data
.tcp
->state
.ack_modified
;
2156 GetDeltaAckIn(struct ip
*pip
, struct alias_link
*link
)
2159 Find out how much the ACK number has been altered for an incoming
2160 TCP packet. To do this, a circular list of ACK numbers where the TCP
2161 packet size was altered is searched.
2166 int delta
, ack_diff_min
;
2169 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2174 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2176 struct ack_data_record x
;
2178 x
= link
->data
.tcp
->ack
[i
];
2183 ack_diff
= SeqDiff(x
.ack_new
, ack
);
2186 if (ack_diff_min
>= 0)
2188 if (ack_diff
< ack_diff_min
)
2191 ack_diff_min
= ack_diff
;
2197 ack_diff_min
= ack_diff
;
2207 GetDeltaSeqOut(struct ip
*pip
, struct alias_link
*link
)
2210 Find out how much the sequence number has been altered for an outgoing
2211 TCP packet. To do this, a circular list of ACK numbers where the TCP
2212 packet size was altered is searched.
2217 int delta
, seq_diff_min
;
2220 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2225 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2227 struct ack_data_record x
;
2229 x
= link
->data
.tcp
->ack
[i
];
2234 seq_diff
= SeqDiff(x
.ack_old
, seq
);
2237 if (seq_diff_min
>= 0)
2239 if (seq_diff
< seq_diff_min
)
2242 seq_diff_min
= seq_diff
;
2248 seq_diff_min
= seq_diff
;
2258 AddSeq(struct ip
*pip
, struct alias_link
*link
, int delta
)
2261 When a TCP packet has been altered in length, save this
2262 information in a circular list. If enough packets have
2263 been altered, then this list will begin to overwrite itself.
2267 struct ack_data_record x
;
2268 int hlen
, tlen
, dlen
;
2271 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2273 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
2274 tlen
= ntohs(pip
->ip_len
);
2277 x
.ack_old
= htonl(ntohl(tc
->th_seq
) + dlen
);
2278 x
.ack_new
= htonl(ntohl(tc
->th_seq
) + dlen
+ delta
);
2282 i
= link
->data
.tcp
->state
.index
;
2283 link
->data
.tcp
->ack
[i
] = x
;
2286 if (i
== N_LINK_TCP_DATA
)
2287 link
->data
.tcp
->state
.index
= 0;
2289 link
->data
.tcp
->state
.index
= i
;
2293 SetExpire(struct alias_link
*link
, int expire
)
2297 link
->flags
&= ~LINK_PERMANENT
;
2300 else if (expire
== -1)
2302 link
->flags
|= LINK_PERMANENT
;
2304 else if (expire
> 0)
2306 link
->expire_time
= expire
;
2311 fprintf(stderr
, "PacketAlias/SetExpire(): ");
2312 fprintf(stderr
, "error in expire parameter\n");
2318 ClearCheckNewLink(void)
2324 SetLastLineCrlfTermed(struct alias_link
*link
, int yes
)
2328 link
->flags
|= LINK_LAST_LINE_CRLF_TERMED
;
2330 link
->flags
&= ~LINK_LAST_LINE_CRLF_TERMED
;
2334 GetLastLineCrlfTermed(struct alias_link
*link
)
2337 return (link
->flags
& LINK_LAST_LINE_CRLF_TERMED
);
2341 SetDestCallId(struct alias_link
*link
, u_int16_t cid
)
2345 link
= ReLink(link
, link
->src_addr
, link
->dst_addr
, link
->alias_addr
,
2346 link
->src_port
, cid
, link
->alias_port
, link
->link_type
);
2351 /* Miscellaneous Functions
2354 InitPacketAliasLog()
2355 UninitPacketAliasLog()
2359 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2360 is called to find and remove timed-out aliasing links. Logic exists
2361 to sweep through the entire table and linked list structure
2364 (prototype in alias_local.h)
2375 * Save system time (seconds) in global variable timeStamp for
2376 * use by other functions. This is done so as not to unnecessarily
2377 * waste timeline by making system calls.
2379 gettimeofday(&tv
, &tz
);
2380 timeStamp
= tv
.tv_sec
;
2382 /* Compute number of spokes (output table link chains) to cover */
2383 n100
= LINK_TABLE_OUT_SIZE
* 100 + houseKeepingResidual
;
2384 n100
*= timeStamp
- lastCleanupTime
;
2385 n100
/= ALIAS_CLEANUP_INTERVAL_SECS
;
2389 /* Handle different cases */
2390 if (n
> ALIAS_CLEANUP_MAX_SPOKES
)
2392 n
= ALIAS_CLEANUP_MAX_SPOKES
;
2393 lastCleanupTime
= timeStamp
;
2394 houseKeepingResidual
= 0;
2397 IncrementalCleanup();
2401 lastCleanupTime
= timeStamp
;
2402 houseKeepingResidual
= n100
- 100*n
;
2405 IncrementalCleanup();
2410 fprintf(stderr
, "PacketAlias/HouseKeeping(): ");
2411 fprintf(stderr
, "something unexpected in time values\n");
2413 lastCleanupTime
= timeStamp
;
2414 houseKeepingResidual
= 0;
2419 /* Init the log file and enable logging */
2421 InitPacketAliasLog(void)
2423 if ((~packetAliasMode
& PKT_ALIAS_LOG
)
2424 && (monitorFile
= fopen("/var/log/alias.log", "w")))
2426 packetAliasMode
|= PKT_ALIAS_LOG
;
2427 fprintf(monitorFile
,
2428 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2433 /* Close the log-file and disable logging. */
2435 UninitPacketAliasLog(void)
2438 fclose(monitorFile
);
2441 packetAliasMode
&= ~PKT_ALIAS_LOG
;
2449 /* Outside world interfaces
2451 -- "outside world" means other than alias*.c routines --
2453 PacketAliasRedirectPort()
2454 PacketAliasAddServer()
2455 PacketAliasRedirectProto()
2456 PacketAliasRedirectAddr()
2457 PacketAliasRedirectDelete()
2458 PacketAliasSetAddress()
2461 PacketAliasSetMode()
2463 (prototypes in alias.h)
2466 /* Redirection from a specific public addr:port to a
2467 private addr:port */
2469 PacketAliasRedirectPort(struct in_addr src_addr
, u_short src_port
,
2470 struct in_addr dst_addr
, u_short dst_port
,
2471 struct in_addr alias_addr
, u_short alias_port
,
2475 struct alias_link
*link
;
2480 link_type
= LINK_UDP
;
2483 link_type
= LINK_TCP
;
2487 fprintf(stderr
, "PacketAliasRedirectPort(): ");
2488 fprintf(stderr
, "only TCP and UDP protocols allowed\n");
2493 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2494 src_port
, dst_port
, alias_port
,
2499 link
->flags
|= LINK_PERMANENT
;
2504 fprintf(stderr
, "PacketAliasRedirectPort(): "
2505 "call to AddLink() failed\n");
2512 /* Add server to the pool of servers */
2514 PacketAliasAddServer(struct alias_link
*link
, struct in_addr addr
, u_short port
)
2516 struct server
*server
;
2518 server
= malloc(sizeof(struct server
));
2520 if (server
!= NULL
) {
2521 struct server
*head
;
2523 server
->addr
= addr
;
2524 server
->port
= port
;
2526 head
= link
->server
;
2528 server
->next
= server
;
2532 for (s
= head
; s
->next
!= head
; s
= s
->next
);
2534 server
->next
= head
;
2536 link
->server
= server
;
2542 /* Redirect packets of a given IP protocol from a specific
2543 public address to a private address */
2545 PacketAliasRedirectProto(struct in_addr src_addr
,
2546 struct in_addr dst_addr
,
2547 struct in_addr alias_addr
,
2550 struct alias_link
*link
;
2552 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2553 NO_SRC_PORT
, NO_DEST_PORT
, 0,
2558 link
->flags
|= LINK_PERMANENT
;
2563 fprintf(stderr
, "PacketAliasRedirectProto(): "
2564 "call to AddLink() failed\n");
2571 /* Static address translation */
2573 PacketAliasRedirectAddr(struct in_addr src_addr
,
2574 struct in_addr alias_addr
)
2576 struct alias_link
*link
;
2578 link
= AddLink(src_addr
, nullAddress
, alias_addr
,
2584 link
->flags
|= LINK_PERMANENT
;
2589 fprintf(stderr
, "PacketAliasRedirectAddr(): "
2590 "call to AddLink() failed\n");
2599 PacketAliasRedirectDelete(struct alias_link
*link
)
2601 /* This is a dangerous function to put in the API,
2602 because an invalid pointer can crash the program. */
2611 PacketAliasSetAddress(struct in_addr addr
)
2613 if (packetAliasMode
& PKT_ALIAS_RESET_ON_ADDR_CHANGE
2614 && aliasAddress
.s_addr
!= addr
.s_addr
)
2617 aliasAddress
= addr
;
2622 PacketAliasSetTarget(struct in_addr target_addr
)
2624 targetAddress
= target_addr
;
2629 PacketAliasInit(void)
2634 static int firstCall
= 1;
2638 gettimeofday(&tv
, &tz
);
2639 timeStamp
= tv
.tv_sec
;
2640 lastCleanupTime
= tv
.tv_sec
;
2641 houseKeepingResidual
= 0;
2643 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
2644 LIST_INIT(&linkTableOut
[i
]);
2645 for (i
=0; i
<LINK_TABLE_IN_SIZE
; i
++)
2646 LIST_INIT(&linkTableIn
[i
]);
2648 atexit(PacketAliasUninit
);
2658 aliasAddress
.s_addr
= INADDR_ANY
;
2659 targetAddress
.s_addr
= INADDR_ANY
;
2666 fragmentIdLinkCount
= 0;
2667 fragmentPtrLinkCount
= 0;
2672 packetAliasMode
= PKT_ALIAS_SAME_PORTS
2673 | PKT_ALIAS_USE_SOCKETS
2674 | PKT_ALIAS_RESET_ON_ADDR_CHANGE
;
2678 PacketAliasUninit(void) {
2682 UninitPacketAliasLog();
2689 /* Change mode for some operations */
2692 unsigned int flags
, /* Which state to bring flags to */
2693 unsigned int mask
/* Mask of which flags to affect (use 0 to do a
2694 probe for flag values) */
2697 /* Enable logging? */
2698 if (flags
& mask
& PKT_ALIAS_LOG
)
2700 InitPacketAliasLog(); /* Do the enable */
2702 /* _Disable_ logging? */
2703 if (~flags
& mask
& PKT_ALIAS_LOG
) {
2704 UninitPacketAliasLog();
2708 /* Start punching holes in the firewall? */
2709 if (flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2712 /* Stop punching holes in the firewall? */
2713 if (~flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2718 /* Other flags can be set/cleared without special action */
2719 packetAliasMode
= (flags
& mask
) | (packetAliasMode
& ~mask
);
2720 return packetAliasMode
;
2725 PacketAliasCheckNewLink(void)
2727 return newDefaultLink
;
2734 Code to support firewall punching. This shouldn't really be in this
2735 file, but making variables global is evil too.
2738 /* Firewall include files */
2740 #include <netinet/ip_fw.h>
2744 static void ClearAllFWHoles(void);
2746 static int fireWallBaseNum
; /* The first firewall entry free for our use */
2747 static int fireWallNumNums
; /* How many entries can we use? */
2748 static int fireWallActiveNum
; /* Which entry did we last use? */
2749 static char *fireWallField
; /* bool array for entries */
2751 #define fw_setfield(field, num) \
2753 (field)[(num) - fireWallBaseNum] = 1; \
2754 } /*lint -save -e717 */ while(0) /*lint -restore */
2755 #define fw_clrfield(field, num) \
2757 (field)[(num) - fireWallBaseNum] = 0; \
2758 } /*lint -save -e717 */ while(0) /*lint -restore */
2759 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2763 fireWallField
= malloc(fireWallNumNums
);
2764 if (fireWallField
) {
2765 memset(fireWallField
, 0, fireWallNumNums
);
2766 if (fireWallFD
< 0) {
2767 fireWallFD
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2770 fireWallActiveNum
= fireWallBaseNum
;
2775 UninitPunchFW(void) {
2777 if (fireWallFD
>= 0)
2781 free(fireWallField
);
2782 fireWallField
= NULL
;
2783 packetAliasMode
&= ~PKT_ALIAS_PUNCH_FW
;
2786 /* Make a certain link go through the firewall */
2788 PunchFWHole(struct alias_link
*link
) {
2789 int r
; /* Result code */
2790 struct ip_fw rule
; /* On-the-fly built rule */
2791 int fwhole
; /* Where to punch hole */
2793 /* Don't do anything unless we are asked to */
2794 if ( !(packetAliasMode
& PKT_ALIAS_PUNCH_FW
) ||
2796 link
->link_type
!= LINK_TCP
)
2799 memset(&rule
, 0, sizeof rule
);
2803 /* Find empty slot */
2804 for (fwhole
= fireWallActiveNum
;
2805 fwhole
< fireWallBaseNum
+ fireWallNumNums
&&
2806 fw_tstfield(fireWallField
, fwhole
);
2809 if (fwhole
== fireWallBaseNum
+ fireWallNumNums
) {
2810 for (fwhole
= fireWallBaseNum
;
2811 fwhole
< fireWallActiveNum
&&
2812 fw_tstfield(fireWallField
, fwhole
);
2815 if (fwhole
== fireWallActiveNum
) {
2816 /* No rule point empty - we can't punch more holes. */
2817 fireWallActiveNum
= fireWallBaseNum
;
2819 fprintf(stderr
, "libalias: Unable to create firewall hole!\n");
2824 /* Start next search at next position */
2825 fireWallActiveNum
= fwhole
+1;
2827 /* Build generic part of the two rules */
2828 rule
.fw_number
= fwhole
;
2829 IP_FW_SETNSRCP(&rule
, 1); /* Number of source ports. */
2830 IP_FW_SETNDSTP(&rule
, 1); /* Number of destination ports. */
2831 rule
.fw_flg
= IP_FW_F_ACCEPT
| IP_FW_F_IN
| IP_FW_F_OUT
;
2832 rule
.fw_prot
= IPPROTO_TCP
;
2833 rule
.fw_smsk
.s_addr
= INADDR_BROADCAST
;
2834 rule
.fw_dmsk
.s_addr
= INADDR_BROADCAST
;
2836 /* Build and apply specific part of the rules */
2837 rule
.fw_src
= GetOriginalAddress(link
);
2838 rule
.fw_dst
= GetDestAddress(link
);
2839 rule
.fw_uar
.fw_pts
[0] = ntohs(GetOriginalPort(link
));
2840 rule
.fw_uar
.fw_pts
[1] = ntohs(GetDestPort(link
));
2842 /* Skip non-bound links - XXX should not be strictly necessary,
2843 but seems to leave hole if not done. Leak of non-bound links?
2844 (Code should be left even if the problem is fixed - it is a
2845 clear optimization) */
2846 if (rule
.fw_uar
.fw_pts
[0] != 0 && rule
.fw_uar
.fw_pts
[1] != 0) {
2847 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, &rule
, sizeof rule
);
2850 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2852 rule
.fw_src
= GetDestAddress(link
);
2853 rule
.fw_dst
= GetOriginalAddress(link
);
2854 rule
.fw_uar
.fw_pts
[0] = ntohs(GetDestPort(link
));
2855 rule
.fw_uar
.fw_pts
[1] = ntohs(GetOriginalPort(link
));
2856 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, &rule
, sizeof rule
);
2859 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2862 /* Indicate hole applied */
2863 link
->data
.tcp
->fwhole
= fwhole
;
2864 fw_setfield(fireWallField
, fwhole
);
2867 /* Remove a hole in a firewall associated with a particular alias
2868 link. Calling this too often is harmless. */
2870 ClearFWHole(struct alias_link
*link
) {
2871 if (link
->link_type
== LINK_TCP
) {
2872 int fwhole
= link
->data
.tcp
->fwhole
; /* Where is the firewall hole? */
2878 memset(&rule
, 0, sizeof rule
);
2879 rule
.fw_number
= fwhole
;
2880 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &rule
, sizeof rule
))
2882 fw_clrfield(fireWallField
, fwhole
);
2883 link
->data
.tcp
->fwhole
= -1;
2887 /* Clear out the entire range dedicated to firewall holes. */
2889 ClearAllFWHoles(void) {
2890 struct ip_fw rule
; /* On-the-fly built rule */
2896 memset(&rule
, 0, sizeof rule
);
2897 for (i
= fireWallBaseNum
; i
< fireWallBaseNum
+ fireWallNumNums
; i
++) {
2899 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &rule
, sizeof rule
))
2902 memset(fireWallField
, 0, fireWallNumNums
);
2907 PacketAliasSetFWBase(unsigned int base
, unsigned int num
) {
2909 fireWallBaseNum
= base
;
2910 fireWallNumNums
= num
;