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 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
235 These constants can be anything except zero, which indicates an
236 unknown port number. */
238 #define NO_DEST_PORT 1
239 #define NO_SRC_PORT 1
245 The fundamental data structure used in this program is
246 "struct alias_link". Whenever a TCP connection is made,
247 a UDP datagram is sent out, or an ICMP echo request is made,
248 a link record is made (if it has not already been created).
249 The link record is identified by the source address/port
250 and the destination address/port. In the case of an ICMP
251 echo request, the source port is treated as being equivalent
252 with the 16-bit ID number of the ICMP packet.
254 The link record also can store some auxiliary data. For
255 TCP connections that have had sequence and acknowledgment
256 modifications, data space is available to track these changes.
257 A state field is used to keep track in changes to the TCP
258 connection state. ID numbers of fragments can also be
259 stored in the auxiliary space. Pointers to unresolved
260 fragments can also be stored.
262 The link records support two independent chainings. Lookup
263 tables for input and out tables hold the initial pointers
264 the link chains. On input, the lookup table indexes on alias
265 port and link type. On output, the lookup table indexes on
266 source address, destination address, source port, destination
270 struct ack_data_record
/* used to save changes to ACK/sequence numbers */
278 struct tcp_state
/* Information about TCP connection */
280 int in
; /* State for outside -> inside */
281 int out
; /* State for inside -> outside */
282 int index
; /* Index to ACK data array */
283 int ack_modified
; /* Indicates whether ACK and sequence numbers */
287 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
288 saved for a modified TCP stream */
291 struct tcp_state state
;
292 struct ack_data_record ack
[N_LINK_TCP_DATA
];
293 int fwhole
; /* Which firewall record is used for this hole? */
296 struct server
/* LSNAT server pool (circular list) */
303 struct alias_link
/* Main data structure */
305 struct in_addr src_addr
; /* Address and port information */
306 struct in_addr dst_addr
;
307 struct in_addr alias_addr
;
308 struct in_addr proxy_addr
;
313 struct server
*server
;
315 int link_type
; /* Type of link: TCP, UDP, ICMP, proto, frag */
317 /* values for link_type */
318 #define LINK_ICMP IPPROTO_ICMP
319 #define LINK_UDP IPPROTO_UDP
320 #define LINK_TCP IPPROTO_TCP
321 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
322 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
323 #define LINK_ADDR (IPPROTO_MAX + 3)
324 #define LINK_PPTP (IPPROTO_MAX + 4)
326 int flags
; /* indicates special characteristics */
329 #define LINK_UNKNOWN_DEST_PORT 0x01
330 #define LINK_UNKNOWN_DEST_ADDR 0x02
331 #define LINK_PERMANENT 0x04
332 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
333 #define LINK_UNFIREWALLED 0x08
334 #define LINK_LAST_LINE_CRLF_TERMED 0x10
336 int timestamp
; /* Time link was last accessed */
337 int expire_time
; /* Expire time for link */
339 int sockfd
; /* socket descriptor */
341 LIST_ENTRY(alias_link
) list_out
; /* Linked list of pointers for */
342 LIST_ENTRY(alias_link
) list_in
; /* input and output lookup tables */
344 union /* Auxiliary data */
347 struct in_addr frag_addr
;
358 The global variables listed here are only accessed from
359 within alias_db.c and so are prefixed with the static
363 int packetAliasMode
; /* Mode flags */
364 /* - documented in alias.h */
366 static struct in_addr aliasAddress
; /* Address written onto source */
367 /* field of IP packet. */
369 static struct in_addr targetAddress
; /* IP address incoming packets */
370 /* are sent to if no aliasing */
371 /* link already exists */
373 static struct in_addr nullAddress
; /* Used as a dummy parameter for */
374 /* some function calls */
375 static LIST_HEAD(, alias_link
)
376 linkTableOut
[LINK_TABLE_OUT_SIZE
]; /* Lookup table of pointers to */
377 /* chains of link records. Each */
378 static LIST_HEAD(, alias_link
) /* link record is doubly indexed */
379 linkTableIn
[LINK_TABLE_IN_SIZE
]; /* into input and output lookup */
382 static int icmpLinkCount
; /* Link statistics */
383 static int udpLinkCount
;
384 static int tcpLinkCount
;
385 static int pptpLinkCount
;
386 static int protoLinkCount
;
387 static int fragmentIdLinkCount
;
388 static int fragmentPtrLinkCount
;
389 static int sockCount
;
391 static int cleanupIndex
; /* Index to chain of link table */
392 /* being inspected for old links */
394 static int timeStamp
; /* System time in seconds for */
397 static int lastCleanupTime
; /* Last time IncrementalCleanup() */
400 static int houseKeepingResidual
; /* used by HouseKeeping() */
402 static int deleteAllLinks
; /* If equal to zero, DeleteLink() */
403 /* will not remove permanent links */
405 static FILE *monitorFile
; /* File descriptor for link */
406 /* statistics monitoring file */
408 static int newDefaultLink
; /* Indicates if a new aliasing */
409 /* link has been created after a */
410 /* call to PacketAliasIn/Out(). */
413 static int fireWallFD
= -1; /* File descriptor to be able to */
414 /* control firewall. Opened by */
415 /* PacketAliasSetMode on first */
416 /* setting the PKT_ALIAS_PUNCH_FW */
426 /* Internal utility routines (used only in alias_db.c)
428 Lookup table starting points:
429 StartPointIn() -- link table initial search point for
431 StartPointOut() -- link table initial search point for
435 SeqDiff() -- difference between two TCP sequences
436 ShowAliasStats() -- send alias statistics to a monitor file
440 /* Local prototypes */
441 static u_int
StartPointIn(struct in_addr
, u_short
, int);
443 static u_int
StartPointOut(struct in_addr
, struct in_addr
,
444 u_short
, u_short
, int);
446 static int SeqDiff(u_long
, u_long
);
448 static void ShowAliasStats(void);
451 /* Firewall control */
452 static void InitPunchFW(void);
453 static void UninitPunchFW(void);
454 static void ClearFWHole(struct alias_link
*link
);
457 /* Log file control */
458 static void InitPacketAliasLog(void);
459 static void UninitPacketAliasLog(void);
462 StartPointIn(struct in_addr alias_addr
,
468 n
= alias_addr
.s_addr
;
469 if (link_type
!= LINK_PPTP
)
472 return(n
% LINK_TABLE_IN_SIZE
);
477 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
478 u_short src_port
, u_short dst_port
, int link_type
)
483 n
+= dst_addr
.s_addr
;
484 if (link_type
!= LINK_PPTP
) {
490 return(n
% LINK_TABLE_OUT_SIZE
);
495 SeqDiff(u_long x
, u_long y
)
497 /* Return the difference between two TCP sequence numbers */
500 This function is encapsulated in case there are any unusual
501 arithmetic conditions that need to be considered.
504 return (ntohl(y
) - ntohl(x
));
511 /* Used for debugging */
515 fprintf(monitorFile
, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
522 fragmentPtrLinkCount
);
524 fprintf(monitorFile
, " / tot=%d (sock=%d)\n",
525 icmpLinkCount
+ udpLinkCount
529 + fragmentIdLinkCount
530 + fragmentPtrLinkCount
,
541 /* Internal routines for finding, deleting and adding links
544 GetNewPort() -- find and reserve new alias port number
545 GetSocket() -- try to allocate a socket for a given port
547 Link creation and deletion:
548 CleanupAliasData() - remove all link chains from lookup table
549 IncrementalCleanup() - look for stale links in a single chain
550 DeleteLink() - remove link
552 ReLink() - change link
555 FindLinkOut() - find link for outgoing packets
556 FindLinkIn() - find link for incoming packets
559 FindNewPortGroup() - find an available group of ports
562 /* Local prototypes */
563 static int GetNewPort(struct alias_link
*, int);
565 static u_short
GetSocket(u_short
, int *, int);
567 static void CleanupAliasData(void);
569 static void IncrementalCleanup(void);
571 static void DeleteLink(struct alias_link
*);
573 static struct alias_link
*
574 AddLink(struct in_addr
, struct in_addr
, struct in_addr
,
575 u_short
, u_short
, int, int);
577 static struct alias_link
*
578 ReLink(struct alias_link
*,
579 struct in_addr
, struct in_addr
, struct in_addr
,
580 u_short
, u_short
, int, int);
582 static struct alias_link
*
583 FindLinkOut(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
585 static struct alias_link
*
586 FindLinkIn(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
589 #define ALIAS_PORT_BASE 0x08000
590 #define ALIAS_PORT_MASK 0x07fff
591 #define ALIAS_PORT_MASK_EVEN 0x07ffe
592 #define GET_NEW_PORT_MAX_ATTEMPTS 20
594 #define GET_ALIAS_PORT -1
595 #define GET_ALIAS_ID GET_ALIAS_PORT
597 #define FIND_EVEN_ALIAS_BASE 1
599 /* GetNewPort() allocates port numbers. Note that if a port number
600 is already in use, that does not mean that it cannot be used by
601 another link concurrently. This is because GetNewPort() looks for
602 unused triplets: (dest addr, dest port, alias port). */
605 GetNewPort(struct alias_link
*link
, int alias_port_param
)
613 Description of alias_port_param for GetNewPort(). When
614 this parameter is zero or positive, it precisely specifies
615 the port number. GetNewPort() will return this number
616 without check that it is in use.
618 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
619 selected port number.
622 if (alias_port_param
== GET_ALIAS_PORT
)
625 * The aliasing port is automatically selected
626 * by one of two methods below:
628 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
630 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
)
633 * When the PKT_ALIAS_SAME_PORTS option is
634 * chosen, the first try will be the
635 * actual source port. If this is already
636 * in use, the remainder of the trials
639 port_net
= link
->src_port
;
640 port_sys
= ntohs(port_net
);
644 /* First trial and all subsequent are random. */
645 port_sys
= random() & ALIAS_PORT_MASK
;
646 port_sys
+= ALIAS_PORT_BASE
;
647 port_net
= htons(port_sys
);
650 else if (alias_port_param
>= 0 && alias_port_param
< 0x10000)
652 link
->alias_port
= (u_short
) alias_port_param
;
658 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
659 fprintf(stderr
, "input parameter error\n");
665 /* Port number search */
666 for (i
=0; i
<max_trials
; i
++)
669 struct alias_link
*search_result
;
671 search_result
= FindLinkIn(link
->dst_addr
, link
->alias_addr
,
672 link
->dst_port
, port_net
,
675 if (search_result
== NULL
)
677 else if (!(link
->flags
& LINK_PARTIALLY_SPECIFIED
)
678 && (search_result
->flags
& LINK_PARTIALLY_SPECIFIED
))
685 if ((packetAliasMode
& PKT_ALIAS_USE_SOCKETS
)
686 && (link
->flags
& LINK_PARTIALLY_SPECIFIED
)
687 && ((link
->link_type
== LINK_TCP
) ||
688 (link
->link_type
== LINK_UDP
)))
690 if (GetSocket(port_net
, &link
->sockfd
, link
->link_type
))
692 link
->alias_port
= port_net
;
698 link
->alias_port
= port_net
;
703 port_sys
= random() & ALIAS_PORT_MASK
;
704 port_sys
+= ALIAS_PORT_BASE
;
705 port_net
= htons(port_sys
);
709 fprintf(stderr
, "PacketAlias/GetnewPort(): ");
710 fprintf(stderr
, "could not find free port\n");
718 GetSocket(u_short port_net
, int *sockfd
, int link_type
)
722 struct sockaddr_in sock_addr
;
724 if (link_type
== LINK_TCP
)
725 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
726 else if (link_type
== LINK_UDP
)
727 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
731 fprintf(stderr
, "PacketAlias/GetSocket(): ");
732 fprintf(stderr
, "incorrect link type\n");
740 fprintf(stderr
, "PacketAlias/GetSocket(): ");
741 fprintf(stderr
, "socket() error %d\n", *sockfd
);
746 sock_addr
.sin_family
= AF_INET
;
747 sock_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
748 sock_addr
.sin_port
= port_net
;
751 (struct sockaddr
*) &sock_addr
,
767 /* FindNewPortGroup() returns a base port number for an available
768 range of contiguous port numbers. Note that if a port number
769 is already in use, that does not mean that it cannot be used by
770 another link concurrently. This is because FindNewPortGroup()
771 looks for unused triplets: (dest addr, dest port, alias port). */
774 FindNewPortGroup(struct in_addr dst_addr
,
775 struct in_addr alias_addr
,
788 * Get link_type from protocol
794 link_type
= LINK_UDP
;
797 link_type
= LINK_TCP
;
805 * The aliasing port is automatically selected
806 * by one of two methods below:
808 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
810 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
) {
812 * When the ALIAS_SAME_PORTS option is
813 * chosen, the first try will be the
814 * actual source port. If this is already
815 * in use, the remainder of the trials
818 port_sys
= ntohs(src_port
);
822 /* First trial and all subsequent are random. */
823 if (align
== FIND_EVEN_ALIAS_BASE
)
824 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
826 port_sys
= random() & ALIAS_PORT_MASK
;
828 port_sys
+= ALIAS_PORT_BASE
;
831 /* Port number search */
832 for (i
= 0; i
< max_trials
; i
++) {
834 struct alias_link
*search_result
;
836 for (j
= 0; j
< port_count
; j
++)
837 if (0 != (search_result
= FindLinkIn(dst_addr
, alias_addr
,
838 dst_port
, htons(port_sys
+ j
),
842 /* Found a good range, return base */
844 return (htons(port_sys
));
846 /* Find a new base to try */
847 if (align
== FIND_EVEN_ALIAS_BASE
)
848 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
850 port_sys
= random() & ALIAS_PORT_MASK
;
852 port_sys
+= ALIAS_PORT_BASE
;
856 fprintf(stderr
, "PacketAlias/FindNewPortGroup(): ");
857 fprintf(stderr
, "could not find free port(s)\n");
864 CleanupAliasData(void)
866 struct alias_link
*link
;
870 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
872 link
= LIST_FIRST(&linkTableOut
[i
]);
875 struct alias_link
*link_next
;
876 link_next
= LIST_NEXT(link
, list_out
);
888 IncrementalCleanup(void)
891 struct alias_link
*link
;
894 link
= LIST_FIRST(&linkTableOut
[cleanupIndex
++]);
898 struct alias_link
*link_next
;
900 link_next
= LIST_NEXT(link
, list_out
);
901 idelta
= timeStamp
- link
->timestamp
;
902 switch (link
->link_type
)
905 if (idelta
> link
->expire_time
)
907 struct tcp_dat
*tcp_aux
;
909 tcp_aux
= link
->data
.tcp
;
910 if (tcp_aux
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
911 || tcp_aux
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
919 if (idelta
> link
->expire_time
)
929 if (cleanupIndex
== LINK_TABLE_OUT_SIZE
)
934 DeleteLink(struct alias_link
*link
)
937 /* Don't do anything if the link is marked permanent */
938 if (deleteAllLinks
== 0 && link
->flags
& LINK_PERMANENT
)
942 /* Delete associated firewall hole, if any */
946 /* Free memory allocated for LSNAT server pool */
947 if (link
->server
!= NULL
) {
948 struct server
*head
, *curr
, *next
;
950 head
= curr
= link
->server
;
954 } while ((curr
= next
) != head
);
957 /* Adjust output table pointers */
958 LIST_REMOVE(link
, list_out
);
960 /* Adjust input table pointers */
961 LIST_REMOVE(link
, list_in
);
963 /* Close socket, if one has been allocated */
964 if (link
->sockfd
!= -1)
970 /* Link-type dependent cleanup */
971 switch(link
->link_type
)
981 free(link
->data
.tcp
);
986 case LINK_FRAGMENT_ID
:
987 fragmentIdLinkCount
--;
989 case LINK_FRAGMENT_PTR
:
990 fragmentPtrLinkCount
--;
991 if (link
->data
.frag_ptr
!= NULL
)
992 free(link
->data
.frag_ptr
);
1004 /* Write statistics, if logging enabled */
1005 if (packetAliasMode
& PKT_ALIAS_LOG
)
1012 static struct alias_link
*
1013 AddLink(struct in_addr src_addr
,
1014 struct in_addr dst_addr
,
1015 struct in_addr alias_addr
,
1018 int alias_port_param
, /* if less than zero, alias */
1019 int link_type
) /* port will be automatically */
1020 { /* chosen. If greater than */
1021 u_int start_point
; /* zero, equal to alias port */
1022 struct alias_link
*link
;
1024 link
= malloc(sizeof(struct alias_link
));
1027 /* Basic initialization */
1028 link
->src_addr
= src_addr
;
1029 link
->dst_addr
= dst_addr
;
1030 link
->alias_addr
= alias_addr
;
1031 link
->proxy_addr
.s_addr
= INADDR_ANY
;
1032 link
->src_port
= src_port
;
1033 link
->dst_port
= dst_port
;
1034 link
->proxy_port
= 0;
1035 link
->server
= NULL
;
1036 link
->link_type
= link_type
;
1039 link
->timestamp
= timeStamp
;
1041 /* Expiration time */
1045 link
->expire_time
= ICMP_EXPIRE_TIME
;
1048 link
->expire_time
= UDP_EXPIRE_TIME
;
1051 link
->expire_time
= TCP_EXPIRE_INITIAL
;
1054 link
->flags
|= LINK_PERMANENT
; /* no timeout. */
1056 case LINK_FRAGMENT_ID
:
1057 link
->expire_time
= FRAGMENT_ID_EXPIRE_TIME
;
1059 case LINK_FRAGMENT_PTR
:
1060 link
->expire_time
= FRAGMENT_PTR_EXPIRE_TIME
;
1065 link
->expire_time
= PROTO_EXPIRE_TIME
;
1069 /* Determine alias flags */
1070 if (dst_addr
.s_addr
== INADDR_ANY
)
1071 link
->flags
|= LINK_UNKNOWN_DEST_ADDR
;
1073 link
->flags
|= LINK_UNKNOWN_DEST_PORT
;
1075 /* Determine alias port */
1076 if (GetNewPort(link
, alias_port_param
) != 0)
1082 /* Link-type dependent initialization */
1085 struct tcp_dat
*aux_tcp
;
1094 aux_tcp
= malloc(sizeof(struct tcp_dat
));
1095 if (aux_tcp
!= NULL
)
1100 aux_tcp
->state
.in
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1101 aux_tcp
->state
.out
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1102 aux_tcp
->state
.index
= 0;
1103 aux_tcp
->state
.ack_modified
= 0;
1104 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
1105 aux_tcp
->ack
[i
].active
= 0;
1106 aux_tcp
->fwhole
= -1;
1107 link
->data
.tcp
= aux_tcp
;
1112 fprintf(stderr
, "PacketAlias/AddLink: ");
1113 fprintf(stderr
, " cannot allocate auxiliary TCP data\n");
1122 case LINK_FRAGMENT_ID
:
1123 fragmentIdLinkCount
++;
1125 case LINK_FRAGMENT_PTR
:
1126 fragmentPtrLinkCount
++;
1135 /* Set up pointers for output lookup table */
1136 start_point
= StartPointOut(src_addr
, dst_addr
,
1137 src_port
, dst_port
, link_type
);
1138 LIST_INSERT_HEAD(&linkTableOut
[start_point
], link
, list_out
);
1140 /* Set up pointers for input lookup table */
1141 start_point
= StartPointIn(alias_addr
, link
->alias_port
, link_type
);
1142 LIST_INSERT_HEAD(&linkTableIn
[start_point
], link
, list_in
);
1147 fprintf(stderr
, "PacketAlias/AddLink(): ");
1148 fprintf(stderr
, "malloc() call failed.\n");
1152 if (packetAliasMode
& PKT_ALIAS_LOG
)
1160 static struct alias_link
*
1161 ReLink(struct alias_link
*old_link
,
1162 struct in_addr src_addr
,
1163 struct in_addr dst_addr
,
1164 struct in_addr alias_addr
,
1167 int alias_port_param
, /* if less than zero, alias */
1168 int link_type
) /* port will be automatically */
1169 { /* chosen. If greater than */
1170 struct alias_link
*new_link
; /* zero, equal to alias port */
1172 new_link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1173 src_port
, dst_port
, alias_port_param
,
1176 if (new_link
!= NULL
&&
1177 old_link
->link_type
== LINK_TCP
&&
1178 old_link
->data
.tcp
->fwhole
> 0) {
1179 PunchFWHole(new_link
);
1182 DeleteLink(old_link
);
1186 static struct alias_link
*
1187 _FindLinkOut(struct in_addr src_addr
,
1188 struct in_addr dst_addr
,
1192 int replace_partial_links
)
1195 struct alias_link
*link
;
1197 i
= StartPointOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
);
1198 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1200 if (link
->src_addr
.s_addr
== src_addr
.s_addr
1201 && link
->server
== NULL
1202 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1203 && link
->dst_port
== dst_port
1204 && link
->src_port
== src_port
1205 && link
->link_type
== link_type
)
1207 link
->timestamp
= timeStamp
;
1212 /* Search for partially specified links. */
1213 if (link
== NULL
&& replace_partial_links
)
1215 if (dst_port
!= 0 && dst_addr
.s_addr
!= INADDR_ANY
)
1217 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, 0,
1220 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
,
1221 dst_port
, link_type
, 0);
1224 (dst_port
!= 0 || dst_addr
.s_addr
!= INADDR_ANY
))
1226 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
, 0,
1232 src_addr
, dst_addr
, link
->alias_addr
,
1233 src_port
, dst_port
, link
->alias_port
,
1241 static struct alias_link
*
1242 FindLinkOut(struct in_addr src_addr
,
1243 struct in_addr dst_addr
,
1247 int replace_partial_links
)
1249 struct alias_link
*link
;
1251 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
,
1252 link_type
, replace_partial_links
);
1256 /* The following allows permanent links to be
1257 specified as using the default source address
1258 (i.e. device interface address) without knowing
1259 in advance what that address is. */
1260 if (aliasAddress
.s_addr
!= 0 &&
1261 src_addr
.s_addr
== aliasAddress
.s_addr
)
1263 link
= _FindLinkOut(nullAddress
, dst_addr
, src_port
, dst_port
,
1264 link_type
, replace_partial_links
);
1272 static struct alias_link
*
1273 _FindLinkIn(struct in_addr dst_addr
,
1274 struct in_addr alias_addr
,
1278 int replace_partial_links
)
1282 struct alias_link
*link
;
1283 struct alias_link
*link_fully_specified
;
1284 struct alias_link
*link_unknown_all
;
1285 struct alias_link
*link_unknown_dst_addr
;
1286 struct alias_link
*link_unknown_dst_port
;
1288 /* Initialize pointers */
1289 link_fully_specified
= NULL
;
1290 link_unknown_all
= NULL
;
1291 link_unknown_dst_addr
= NULL
;
1292 link_unknown_dst_port
= NULL
;
1294 /* If either the dest addr or port is unknown, the search
1295 loop will have to know about this. */
1298 if (dst_addr
.s_addr
== INADDR_ANY
)
1299 flags_in
|= LINK_UNKNOWN_DEST_ADDR
;
1301 flags_in
|= LINK_UNKNOWN_DEST_PORT
;
1304 start_point
= StartPointIn(alias_addr
, alias_port
, link_type
);
1305 LIST_FOREACH(link
, &linkTableIn
[start_point
], list_in
)
1309 flags
= flags_in
| link
->flags
;
1310 if (!(flags
& LINK_PARTIALLY_SPECIFIED
))
1312 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1313 && link
->alias_port
== alias_port
1314 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1315 && link
->dst_port
== dst_port
1316 && link
->link_type
== link_type
)
1318 link_fully_specified
= link
;
1322 else if ((flags
& LINK_UNKNOWN_DEST_ADDR
)
1323 && (flags
& LINK_UNKNOWN_DEST_PORT
))
1325 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1326 && link
->alias_port
== alias_port
1327 && link
->link_type
== link_type
)
1329 if (link_unknown_all
== NULL
)
1330 link_unknown_all
= link
;
1333 else if (flags
& LINK_UNKNOWN_DEST_ADDR
)
1335 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1336 && link
->alias_port
== alias_port
1337 && link
->link_type
== link_type
1338 && link
->dst_port
== dst_port
)
1340 if (link_unknown_dst_addr
== NULL
)
1341 link_unknown_dst_addr
= link
;
1344 else if (flags
& LINK_UNKNOWN_DEST_PORT
)
1346 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1347 && link
->alias_port
== alias_port
1348 && link
->link_type
== link_type
1349 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
)
1351 if (link_unknown_dst_port
== NULL
)
1352 link_unknown_dst_port
= link
;
1359 if (link_fully_specified
!= NULL
)
1361 link_fully_specified
->timestamp
= timeStamp
;
1362 link
= link_fully_specified
;
1364 else if (link_unknown_dst_port
!= NULL
)
1365 link
= link_unknown_dst_port
;
1366 else if (link_unknown_dst_addr
!= NULL
)
1367 link
= link_unknown_dst_addr
;
1368 else if (link_unknown_all
!= NULL
)
1369 link
= link_unknown_all
;
1373 if (replace_partial_links
&&
1374 (link
->flags
& LINK_PARTIALLY_SPECIFIED
|| link
->server
!= NULL
))
1376 struct in_addr src_addr
;
1379 if (link
->server
!= NULL
) { /* LSNAT link */
1380 src_addr
= link
->server
->addr
;
1381 src_port
= link
->server
->port
;
1382 link
->server
= link
->server
->next
;
1384 src_addr
= link
->src_addr
;
1385 src_port
= link
->src_port
;
1389 src_addr
, dst_addr
, alias_addr
,
1390 src_port
, dst_port
, alias_port
,
1397 static struct alias_link
*
1398 FindLinkIn(struct in_addr dst_addr
,
1399 struct in_addr alias_addr
,
1403 int replace_partial_links
)
1405 struct alias_link
*link
;
1407 link
= _FindLinkIn(dst_addr
, alias_addr
, dst_port
, alias_port
,
1408 link_type
, replace_partial_links
);
1412 /* The following allows permanent links to be
1413 specified as using the default aliasing address
1414 (i.e. device interface address) without knowing
1415 in advance what that address is. */
1416 if (aliasAddress
.s_addr
!= 0 &&
1417 alias_addr
.s_addr
== aliasAddress
.s_addr
)
1419 link
= _FindLinkIn(dst_addr
, nullAddress
, dst_port
, alias_port
,
1420 link_type
, replace_partial_links
);
1430 /* External routines for finding/adding links
1432 -- "external" means outside alias_db.c, but within alias*.c --
1434 FindIcmpIn(), FindIcmpOut()
1435 FindFragmentIn1(), FindFragmentIn2()
1436 AddFragmentPtrLink(), FindFragmentPtr()
1437 FindProtoIn(), FindProtoOut()
1438 FindUdpTcpIn(), FindUdpTcpOut()
1439 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1440 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1441 FindOriginalAddress(), FindAliasAddress()
1443 (prototypes in alias_local.h)
1448 FindIcmpIn(struct in_addr dst_addr
,
1449 struct in_addr alias_addr
,
1453 struct alias_link
*link
;
1455 link
= FindLinkIn(dst_addr
, alias_addr
,
1456 NO_DEST_PORT
, id_alias
,
1458 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1460 struct in_addr target_addr
;
1462 target_addr
= FindOriginalAddress(alias_addr
);
1463 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1464 id_alias
, NO_DEST_PORT
, id_alias
,
1473 FindIcmpOut(struct in_addr src_addr
,
1474 struct in_addr dst_addr
,
1478 struct alias_link
* link
;
1480 link
= FindLinkOut(src_addr
, dst_addr
,
1483 if (link
== NULL
&& create
)
1485 struct in_addr alias_addr
;
1487 alias_addr
= FindAliasAddress(src_addr
);
1488 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1489 id
, NO_DEST_PORT
, GET_ALIAS_ID
,
1498 FindFragmentIn1(struct in_addr dst_addr
,
1499 struct in_addr alias_addr
,
1502 struct alias_link
*link
;
1504 link
= FindLinkIn(dst_addr
, alias_addr
,
1505 NO_DEST_PORT
, ip_id
,
1506 LINK_FRAGMENT_ID
, 0);
1510 link
= AddLink(nullAddress
, dst_addr
, alias_addr
,
1511 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1520 FindFragmentIn2(struct in_addr dst_addr
, /* Doesn't add a link if one */
1521 struct in_addr alias_addr
, /* is not found. */
1524 return FindLinkIn(dst_addr
, alias_addr
,
1525 NO_DEST_PORT
, ip_id
,
1526 LINK_FRAGMENT_ID
, 0);
1531 AddFragmentPtrLink(struct in_addr dst_addr
,
1534 return AddLink(nullAddress
, dst_addr
, nullAddress
,
1535 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1541 FindFragmentPtr(struct in_addr dst_addr
,
1544 return FindLinkIn(dst_addr
, nullAddress
,
1545 NO_DEST_PORT
, ip_id
,
1546 LINK_FRAGMENT_PTR
, 0);
1551 FindProtoIn(struct in_addr dst_addr
,
1552 struct in_addr alias_addr
,
1555 struct alias_link
*link
;
1557 link
= FindLinkIn(dst_addr
, alias_addr
,
1561 if (link
== NULL
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1563 struct in_addr target_addr
;
1565 target_addr
= FindOriginalAddress(alias_addr
);
1566 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1567 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1576 FindProtoOut(struct in_addr src_addr
,
1577 struct in_addr dst_addr
,
1580 struct alias_link
*link
;
1582 link
= FindLinkOut(src_addr
, dst_addr
,
1583 NO_SRC_PORT
, NO_DEST_PORT
,
1588 struct in_addr alias_addr
;
1590 alias_addr
= FindAliasAddress(src_addr
);
1591 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1592 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1601 FindUdpTcpIn(struct in_addr dst_addr
,
1602 struct in_addr alias_addr
,
1609 struct alias_link
*link
;
1614 link_type
= LINK_UDP
;
1617 link_type
= LINK_TCP
;
1624 link
= FindLinkIn(dst_addr
, alias_addr
,
1625 dst_port
, alias_port
,
1628 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1630 struct in_addr target_addr
;
1632 target_addr
= FindOriginalAddress(alias_addr
);
1633 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1634 alias_port
, dst_port
, alias_port
,
1643 FindUdpTcpOut(struct in_addr src_addr
,
1644 struct in_addr dst_addr
,
1651 struct alias_link
*link
;
1656 link_type
= LINK_UDP
;
1659 link_type
= LINK_TCP
;
1666 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
, create
);
1668 if (link
== NULL
&& create
)
1670 struct in_addr alias_addr
;
1672 alias_addr
= FindAliasAddress(src_addr
);
1673 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1674 src_port
, dst_port
, GET_ALIAS_PORT
,
1683 AddPptp(struct in_addr src_addr
,
1684 struct in_addr dst_addr
,
1685 struct in_addr alias_addr
,
1686 u_int16_t src_call_id
)
1688 struct alias_link
*link
;
1690 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1691 src_call_id
, 0, GET_ALIAS_PORT
,
1699 FindPptpOutByCallId(struct in_addr src_addr
,
1700 struct in_addr dst_addr
,
1701 u_int16_t src_call_id
)
1704 struct alias_link
*link
;
1706 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1707 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1708 if (link
->link_type
== LINK_PPTP
&&
1709 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1710 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1711 link
->src_port
== src_call_id
)
1719 FindPptpOutByPeerCallId(struct in_addr src_addr
,
1720 struct in_addr dst_addr
,
1721 u_int16_t dst_call_id
)
1724 struct alias_link
*link
;
1726 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1727 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1728 if (link
->link_type
== LINK_PPTP
&&
1729 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1730 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1731 link
->dst_port
== dst_call_id
)
1739 FindPptpInByCallId(struct in_addr dst_addr
,
1740 struct in_addr alias_addr
,
1741 u_int16_t dst_call_id
)
1744 struct alias_link
*link
;
1746 i
= StartPointIn(alias_addr
, 0, LINK_PPTP
);
1747 LIST_FOREACH(link
, &linkTableIn
[i
], list_in
)
1748 if (link
->link_type
== LINK_PPTP
&&
1749 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1750 link
->alias_addr
.s_addr
== alias_addr
.s_addr
&&
1751 link
->dst_port
== dst_call_id
)
1759 FindPptpInByPeerCallId(struct in_addr dst_addr
,
1760 struct in_addr alias_addr
,
1761 u_int16_t alias_call_id
)
1763 struct alias_link
*link
;
1765 link
= FindLinkIn(dst_addr
, alias_addr
,
1766 0/* any */, alias_call_id
,
1775 FindRtspOut(struct in_addr src_addr
,
1776 struct in_addr dst_addr
,
1782 struct alias_link
*link
;
1787 link_type
= LINK_UDP
;
1790 link_type
= LINK_TCP
;
1797 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, 0, link_type
, 1);
1801 struct in_addr alias_addr
;
1803 alias_addr
= FindAliasAddress(src_addr
);
1804 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1805 src_port
, 0, alias_port
,
1814 FindOriginalAddress(struct in_addr alias_addr
)
1816 struct alias_link
*link
;
1818 link
= FindLinkIn(nullAddress
, alias_addr
,
1819 0, 0, LINK_ADDR
, 0);
1823 if (targetAddress
.s_addr
== INADDR_ANY
)
1825 else if (targetAddress
.s_addr
== INADDR_NONE
)
1826 return aliasAddress
;
1828 return targetAddress
;
1832 if (link
->server
!= NULL
) { /* LSNAT link */
1833 struct in_addr src_addr
;
1835 src_addr
= link
->server
->addr
;
1836 link
->server
= link
->server
->next
;
1838 } else if (link
->src_addr
.s_addr
== INADDR_ANY
)
1839 return aliasAddress
;
1841 return link
->src_addr
;
1847 FindAliasAddress(struct in_addr original_addr
)
1849 struct alias_link
*link
;
1851 link
= FindLinkOut(original_addr
, nullAddress
,
1852 0, 0, LINK_ADDR
, 0);
1855 return aliasAddress
;
1859 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1860 return aliasAddress
;
1862 return link
->alias_addr
;
1867 /* External routines for getting or changing link data
1868 (external to alias_db.c, but internal to alias*.c)
1870 SetFragmentData(), GetFragmentData()
1871 SetFragmentPtr(), GetFragmentPtr()
1872 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1873 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1874 GetOriginalPort(), GetAliasPort()
1875 SetAckModified(), GetAckModified()
1876 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1877 SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
1883 SetFragmentAddr(struct alias_link
*link
, struct in_addr src_addr
)
1885 link
->data
.frag_addr
= src_addr
;
1890 GetFragmentAddr(struct alias_link
*link
, struct in_addr
*src_addr
)
1892 *src_addr
= link
->data
.frag_addr
;
1897 SetFragmentPtr(struct alias_link
*link
, char *fptr
)
1899 link
->data
.frag_ptr
= fptr
;
1904 GetFragmentPtr(struct alias_link
*link
, char **fptr
)
1906 *fptr
= link
->data
.frag_ptr
;
1911 SetStateIn(struct alias_link
*link
, int state
)
1913 /* TCP input state */
1915 case ALIAS_TCP_STATE_DISCONNECTED
:
1916 if (link
->data
.tcp
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
1917 link
->expire_time
= TCP_EXPIRE_DEAD
;
1919 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1921 case ALIAS_TCP_STATE_CONNECTED
:
1922 if (link
->data
.tcp
->state
.out
== ALIAS_TCP_STATE_CONNECTED
)
1923 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
1928 link
->data
.tcp
->state
.in
= state
;
1933 SetStateOut(struct alias_link
*link
, int state
)
1935 /* TCP output state */
1937 case ALIAS_TCP_STATE_DISCONNECTED
:
1938 if (link
->data
.tcp
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
)
1939 link
->expire_time
= TCP_EXPIRE_DEAD
;
1941 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1943 case ALIAS_TCP_STATE_CONNECTED
:
1944 if (link
->data
.tcp
->state
.in
== ALIAS_TCP_STATE_CONNECTED
)
1945 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
1950 link
->data
.tcp
->state
.out
= state
;
1955 GetStateIn(struct alias_link
*link
)
1957 /* TCP input state */
1958 return link
->data
.tcp
->state
.in
;
1963 GetStateOut(struct alias_link
*link
)
1965 /* TCP output state */
1966 return link
->data
.tcp
->state
.out
;
1971 GetOriginalAddress(struct alias_link
*link
)
1973 if (link
->src_addr
.s_addr
== INADDR_ANY
)
1974 return aliasAddress
;
1976 return(link
->src_addr
);
1981 GetDestAddress(struct alias_link
*link
)
1983 return(link
->dst_addr
);
1988 GetAliasAddress(struct alias_link
*link
)
1990 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1991 return aliasAddress
;
1993 return link
->alias_addr
;
1998 GetDefaultAliasAddress()
2000 return aliasAddress
;
2005 SetDefaultAliasAddress(struct in_addr alias_addr
)
2007 aliasAddress
= alias_addr
;
2012 GetOriginalPort(struct alias_link
*link
)
2014 return(link
->src_port
);
2019 GetAliasPort(struct alias_link
*link
)
2021 return(link
->alias_port
);
2026 GetDestPort(struct alias_link
*link
)
2028 return(link
->dst_port
);
2033 SetAckModified(struct alias_link
*link
)
2035 /* Indicate that ACK numbers have been modified in a TCP connection */
2036 link
->data
.tcp
->state
.ack_modified
= 1;
2041 GetProxyAddress(struct alias_link
*link
)
2043 return link
->proxy_addr
;
2048 SetProxyAddress(struct alias_link
*link
, struct in_addr addr
)
2050 link
->proxy_addr
= addr
;
2055 GetProxyPort(struct alias_link
*link
)
2057 return link
->proxy_port
;
2062 SetProxyPort(struct alias_link
*link
, u_short port
)
2064 link
->proxy_port
= port
;
2069 GetAckModified(struct alias_link
*link
)
2071 /* See if ACK numbers have been modified */
2072 return link
->data
.tcp
->state
.ack_modified
;
2077 GetDeltaAckIn(struct ip
*pip
, struct alias_link
*link
)
2080 Find out how much the ACK number has been altered for an incoming
2081 TCP packet. To do this, a circular list of ACK numbers where the TCP
2082 packet size was altered is searched.
2087 int delta
, ack_diff_min
;
2090 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2095 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2097 struct ack_data_record x
;
2099 x
= link
->data
.tcp
->ack
[i
];
2104 ack_diff
= SeqDiff(x
.ack_new
, ack
);
2107 if (ack_diff_min
>= 0)
2109 if (ack_diff
< ack_diff_min
)
2112 ack_diff_min
= ack_diff
;
2118 ack_diff_min
= ack_diff
;
2128 GetDeltaSeqOut(struct ip
*pip
, struct alias_link
*link
)
2131 Find out how much the sequence number has been altered for an outgoing
2132 TCP packet. To do this, a circular list of ACK numbers where the TCP
2133 packet size was altered is searched.
2138 int delta
, seq_diff_min
;
2141 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2146 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2148 struct ack_data_record x
;
2150 x
= link
->data
.tcp
->ack
[i
];
2155 seq_diff
= SeqDiff(x
.ack_old
, seq
);
2158 if (seq_diff_min
>= 0)
2160 if (seq_diff
< seq_diff_min
)
2163 seq_diff_min
= seq_diff
;
2169 seq_diff_min
= seq_diff
;
2179 AddSeq(struct ip
*pip
, struct alias_link
*link
, int delta
)
2182 When a TCP packet has been altered in length, save this
2183 information in a circular list. If enough packets have
2184 been altered, then this list will begin to overwrite itself.
2188 struct ack_data_record x
;
2189 int hlen
, tlen
, dlen
;
2192 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2194 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
2195 tlen
= ntohs(pip
->ip_len
);
2198 x
.ack_old
= htonl(ntohl(tc
->th_seq
) + dlen
);
2199 x
.ack_new
= htonl(ntohl(tc
->th_seq
) + dlen
+ delta
);
2203 i
= link
->data
.tcp
->state
.index
;
2204 link
->data
.tcp
->ack
[i
] = x
;
2207 if (i
== N_LINK_TCP_DATA
)
2208 link
->data
.tcp
->state
.index
= 0;
2210 link
->data
.tcp
->state
.index
= i
;
2214 SetExpire(struct alias_link
*link
, int expire
)
2218 link
->flags
&= ~LINK_PERMANENT
;
2221 else if (expire
== -1)
2223 link
->flags
|= LINK_PERMANENT
;
2225 else if (expire
> 0)
2227 link
->expire_time
= expire
;
2232 fprintf(stderr
, "PacketAlias/SetExpire(): ");
2233 fprintf(stderr
, "error in expire parameter\n");
2239 ClearCheckNewLink(void)
2245 SetLastLineCrlfTermed(struct alias_link
*link
, int yes
)
2249 link
->flags
|= LINK_LAST_LINE_CRLF_TERMED
;
2251 link
->flags
&= ~LINK_LAST_LINE_CRLF_TERMED
;
2255 GetLastLineCrlfTermed(struct alias_link
*link
)
2258 return (link
->flags
& LINK_LAST_LINE_CRLF_TERMED
);
2262 SetDestCallId(struct alias_link
*link
, u_int16_t cid
)
2266 link
= ReLink(link
, link
->src_addr
, link
->dst_addr
, link
->alias_addr
,
2267 link
->src_port
, cid
, link
->alias_port
, link
->link_type
);
2272 /* Miscellaneous Functions
2275 InitPacketAliasLog()
2276 UninitPacketAliasLog()
2280 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2281 is called to find and remove timed-out aliasing links. Logic exists
2282 to sweep through the entire table and linked list structure
2285 (prototype in alias_local.h)
2296 * Save system time (seconds) in global variable timeStamp for
2297 * use by other functions. This is done so as not to unnecessarily
2298 * waste timeline by making system calls.
2300 gettimeofday(&tv
, &tz
);
2301 timeStamp
= tv
.tv_sec
;
2303 /* Compute number of spokes (output table link chains) to cover */
2304 n100
= LINK_TABLE_OUT_SIZE
* 100 + houseKeepingResidual
;
2305 n100
*= timeStamp
- lastCleanupTime
;
2306 n100
/= ALIAS_CLEANUP_INTERVAL_SECS
;
2310 /* Handle different cases */
2311 if (n
> ALIAS_CLEANUP_MAX_SPOKES
)
2313 n
= ALIAS_CLEANUP_MAX_SPOKES
;
2314 lastCleanupTime
= timeStamp
;
2315 houseKeepingResidual
= 0;
2318 IncrementalCleanup();
2322 lastCleanupTime
= timeStamp
;
2323 houseKeepingResidual
= n100
- 100*n
;
2326 IncrementalCleanup();
2331 fprintf(stderr
, "PacketAlias/HouseKeeping(): ");
2332 fprintf(stderr
, "something unexpected in time values\n");
2334 lastCleanupTime
= timeStamp
;
2335 houseKeepingResidual
= 0;
2340 /* Init the log file and enable logging */
2342 InitPacketAliasLog(void)
2344 if ((~packetAliasMode
& PKT_ALIAS_LOG
)
2345 && (monitorFile
= fopen("/var/log/alias.log", "w")))
2347 packetAliasMode
|= PKT_ALIAS_LOG
;
2348 fprintf(monitorFile
,
2349 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2354 /* Close the log-file and disable logging. */
2356 UninitPacketAliasLog(void)
2359 fclose(monitorFile
);
2362 packetAliasMode
&= ~PKT_ALIAS_LOG
;
2370 /* Outside world interfaces
2372 -- "outside world" means other than alias*.c routines --
2374 PacketAliasRedirectPort()
2375 PacketAliasAddServer()
2376 PacketAliasRedirectProto()
2377 PacketAliasRedirectAddr()
2378 PacketAliasRedirectDelete()
2379 PacketAliasSetAddress()
2382 PacketAliasSetMode()
2384 (prototypes in alias.h)
2387 /* Redirection from a specific public addr:port to a
2388 private addr:port */
2390 PacketAliasRedirectPort(struct in_addr src_addr
, u_short src_port
,
2391 struct in_addr dst_addr
, u_short dst_port
,
2392 struct in_addr alias_addr
, u_short alias_port
,
2396 struct alias_link
*link
;
2401 link_type
= LINK_UDP
;
2404 link_type
= LINK_TCP
;
2408 fprintf(stderr
, "PacketAliasRedirectPort(): ");
2409 fprintf(stderr
, "only TCP and UDP protocols allowed\n");
2414 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2415 src_port
, dst_port
, alias_port
,
2420 link
->flags
|= LINK_PERMANENT
;
2425 fprintf(stderr
, "PacketAliasRedirectPort(): "
2426 "call to AddLink() failed\n");
2433 /* Add server to the pool of servers */
2435 PacketAliasAddServer(struct alias_link
*link
, struct in_addr addr
, u_short port
)
2437 struct server
*server
;
2439 server
= malloc(sizeof(struct server
));
2441 if (server
!= NULL
) {
2442 struct server
*head
;
2444 server
->addr
= addr
;
2445 server
->port
= port
;
2447 head
= link
->server
;
2449 server
->next
= server
;
2453 for (s
= head
; s
->next
!= head
; s
= s
->next
);
2455 server
->next
= head
;
2457 link
->server
= server
;
2463 /* Redirect packets of a given IP protocol from a specific
2464 public address to a private address */
2466 PacketAliasRedirectProto(struct in_addr src_addr
,
2467 struct in_addr dst_addr
,
2468 struct in_addr alias_addr
,
2471 struct alias_link
*link
;
2473 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2474 NO_SRC_PORT
, NO_DEST_PORT
, 0,
2479 link
->flags
|= LINK_PERMANENT
;
2484 fprintf(stderr
, "PacketAliasRedirectProto(): "
2485 "call to AddLink() failed\n");
2492 /* Static address translation */
2494 PacketAliasRedirectAddr(struct in_addr src_addr
,
2495 struct in_addr alias_addr
)
2497 struct alias_link
*link
;
2499 link
= AddLink(src_addr
, nullAddress
, alias_addr
,
2505 link
->flags
|= LINK_PERMANENT
;
2510 fprintf(stderr
, "PacketAliasRedirectAddr(): "
2511 "call to AddLink() failed\n");
2520 PacketAliasRedirectDelete(struct alias_link
*link
)
2522 /* This is a dangerous function to put in the API,
2523 because an invalid pointer can crash the program. */
2532 PacketAliasSetAddress(struct in_addr addr
)
2534 if (packetAliasMode
& PKT_ALIAS_RESET_ON_ADDR_CHANGE
2535 && aliasAddress
.s_addr
!= addr
.s_addr
)
2538 aliasAddress
= addr
;
2543 PacketAliasSetTarget(struct in_addr target_addr
)
2545 targetAddress
= target_addr
;
2550 PacketAliasInit(void)
2555 static int firstCall
= 1;
2559 gettimeofday(&tv
, &tz
);
2560 timeStamp
= tv
.tv_sec
;
2561 lastCleanupTime
= tv
.tv_sec
;
2562 houseKeepingResidual
= 0;
2564 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
2565 LIST_INIT(&linkTableOut
[i
]);
2566 for (i
=0; i
<LINK_TABLE_IN_SIZE
; i
++)
2567 LIST_INIT(&linkTableIn
[i
]);
2569 atexit(PacketAliasUninit
);
2579 aliasAddress
.s_addr
= INADDR_ANY
;
2580 targetAddress
.s_addr
= INADDR_ANY
;
2587 fragmentIdLinkCount
= 0;
2588 fragmentPtrLinkCount
= 0;
2593 packetAliasMode
= PKT_ALIAS_SAME_PORTS
2594 | PKT_ALIAS_USE_SOCKETS
2595 | PKT_ALIAS_RESET_ON_ADDR_CHANGE
;
2599 PacketAliasUninit(void) {
2603 UninitPacketAliasLog();
2610 /* Change mode for some operations */
2613 unsigned int flags
, /* Which state to bring flags to */
2614 unsigned int mask
/* Mask of which flags to affect (use 0 to do a
2615 probe for flag values) */
2618 /* Enable logging? */
2619 if (flags
& mask
& PKT_ALIAS_LOG
)
2621 InitPacketAliasLog(); /* Do the enable */
2623 /* _Disable_ logging? */
2624 if (~flags
& mask
& PKT_ALIAS_LOG
) {
2625 UninitPacketAliasLog();
2629 /* Start punching holes in the firewall? */
2630 if (flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2633 /* Stop punching holes in the firewall? */
2634 if (~flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2639 /* Other flags can be set/cleared without special action */
2640 packetAliasMode
= (flags
& mask
) | (packetAliasMode
& ~mask
);
2641 return packetAliasMode
;
2646 PacketAliasCheckNewLink(void)
2648 return newDefaultLink
;
2655 Code to support firewall punching. This shouldn't really be in this
2656 file, but making variables global is evil too.
2659 /* Firewall include files */
2661 #include <netinet/ip_fw.h>
2665 static void ClearAllFWHoles(void);
2667 static int fireWallBaseNum
; /* The first firewall entry free for our use */
2668 static int fireWallNumNums
; /* How many entries can we use? */
2669 static int fireWallActiveNum
; /* Which entry did we last use? */
2670 static char *fireWallField
; /* bool array for entries */
2672 #define fw_setfield(field, num) \
2674 (field)[(num) - fireWallBaseNum] = 1; \
2675 } /*lint -save -e717 */ while(0) /*lint -restore */
2676 #define fw_clrfield(field, num) \
2678 (field)[(num) - fireWallBaseNum] = 0; \
2679 } /*lint -save -e717 */ while(0) /*lint -restore */
2680 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2684 fireWallField
= malloc(fireWallNumNums
);
2685 if (fireWallField
) {
2686 memset(fireWallField
, 0, fireWallNumNums
);
2687 if (fireWallFD
< 0) {
2688 fireWallFD
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2691 fireWallActiveNum
= fireWallBaseNum
;
2696 UninitPunchFW(void) {
2698 if (fireWallFD
>= 0)
2702 free(fireWallField
);
2703 fireWallField
= NULL
;
2704 packetAliasMode
&= ~PKT_ALIAS_PUNCH_FW
;
2707 /* Make a certain link go through the firewall */
2709 PunchFWHole(struct alias_link
*link
) {
2710 int r
; /* Result code */
2711 struct ip_fw rule
; /* On-the-fly built rule */
2712 int fwhole
; /* Where to punch hole */
2714 /* Don't do anything unless we are asked to */
2715 if ( !(packetAliasMode
& PKT_ALIAS_PUNCH_FW
) ||
2717 link
->link_type
!= LINK_TCP
)
2720 memset(&rule
, 0, sizeof rule
);
2724 /* Find empty slot */
2725 for (fwhole
= fireWallActiveNum
;
2726 fwhole
< fireWallBaseNum
+ fireWallNumNums
&&
2727 fw_tstfield(fireWallField
, fwhole
);
2730 if (fwhole
== fireWallBaseNum
+ fireWallNumNums
) {
2731 for (fwhole
= fireWallBaseNum
;
2732 fwhole
< fireWallActiveNum
&&
2733 fw_tstfield(fireWallField
, fwhole
);
2736 if (fwhole
== fireWallActiveNum
) {
2737 /* No rule point empty - we can't punch more holes. */
2738 fireWallActiveNum
= fireWallBaseNum
;
2740 fprintf(stderr
, "libalias: Unable to create firewall hole!\n");
2745 /* Start next search at next position */
2746 fireWallActiveNum
= fwhole
+1;
2748 /* Build generic part of the two rules */
2749 rule
.fw_number
= fwhole
;
2750 IP_FW_SETNSRCP(&rule
, 1); /* Number of source ports. */
2751 IP_FW_SETNDSTP(&rule
, 1); /* Number of destination ports. */
2752 rule
.fw_flg
= IP_FW_F_ACCEPT
| IP_FW_F_IN
| IP_FW_F_OUT
;
2753 rule
.fw_prot
= IPPROTO_TCP
;
2754 rule
.fw_smsk
.s_addr
= INADDR_BROADCAST
;
2755 rule
.fw_dmsk
.s_addr
= INADDR_BROADCAST
;
2757 /* Build and apply specific part of the rules */
2758 rule
.fw_src
= GetOriginalAddress(link
);
2759 rule
.fw_dst
= GetDestAddress(link
);
2760 rule
.fw_uar
.fw_pts
[0] = ntohs(GetOriginalPort(link
));
2761 rule
.fw_uar
.fw_pts
[1] = ntohs(GetDestPort(link
));
2763 /* Skip non-bound links - XXX should not be strictly necessary,
2764 but seems to leave hole if not done. Leak of non-bound links?
2765 (Code should be left even if the problem is fixed - it is a
2766 clear optimization) */
2767 if (rule
.fw_uar
.fw_pts
[0] != 0 && rule
.fw_uar
.fw_pts
[1] != 0) {
2768 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, &rule
, sizeof rule
);
2771 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2773 rule
.fw_src
= GetDestAddress(link
);
2774 rule
.fw_dst
= GetOriginalAddress(link
);
2775 rule
.fw_uar
.fw_pts
[0] = ntohs(GetDestPort(link
));
2776 rule
.fw_uar
.fw_pts
[1] = ntohs(GetOriginalPort(link
));
2777 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, &rule
, sizeof rule
);
2780 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2783 /* Indicate hole applied */
2784 link
->data
.tcp
->fwhole
= fwhole
;
2785 fw_setfield(fireWallField
, fwhole
);
2788 /* Remove a hole in a firewall associated with a particular alias
2789 link. Calling this too often is harmless. */
2791 ClearFWHole(struct alias_link
*link
) {
2792 if (link
->link_type
== LINK_TCP
) {
2793 int fwhole
= link
->data
.tcp
->fwhole
; /* Where is the firewall hole? */
2799 memset(&rule
, 0, sizeof rule
);
2800 rule
.fw_number
= fwhole
;
2801 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &rule
, sizeof rule
))
2803 fw_clrfield(fireWallField
, fwhole
);
2804 link
->data
.tcp
->fwhole
= -1;
2808 /* Clear out the entire range dedicated to firewall holes. */
2810 ClearAllFWHoles(void) {
2811 struct ip_fw rule
; /* On-the-fly built rule */
2817 memset(&rule
, 0, sizeof rule
);
2818 for (i
= fireWallBaseNum
; i
< fireWallBaseNum
+ fireWallNumNums
; i
++) {
2820 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &rule
, sizeof rule
))
2823 memset(fireWallField
, 0, fireWallNumNums
);
2828 PacketAliasSetFWBase(unsigned int base
, unsigned int num
) {
2830 fireWallBaseNum
= base
;
2831 fireWallNumNums
= num
;