1 /* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * $FreeBSD: src/lib/libalias/alias_db.c,v 1.21.2.14 2002/07/24 03:21:24 luigi Exp $
32 Alias_db.c encapsulates all data structures used for storing
33 packet aliasing data. Other parts of the aliasing software
34 access data through functions provided in this file.
36 Data storage is based on the notion of a "link", which is
37 established for ICMP echo/reply packets, UDP datagrams and
38 TCP stream connections. A link stores the original source
39 and destination addresses. For UDP and TCP, it also stores
40 source and destination port numbers, as well as an alias
41 port number. Links are also used to store information about
44 There is a facility for sweeping through and deleting old
45 links as new packets are sent through. A simple timeout is
46 used for ICMP and UDP links. TCP links are left alone unless
47 there is an incomplete connection, in which case the link
48 can be deleted after a certain amount of time.
51 Initial version: August, 1996 (cjm)
53 Version 1.4: September 16, 1996 (cjm)
54 Facility for handling incoming links added.
56 Version 1.6: September 18, 1996 (cjm)
57 ICMP data handling simplified.
59 Version 1.7: January 9, 1997 (cjm)
60 Fragment handling simplified.
61 Saves pointers for unresolved fragments.
62 Permits links for unspecified remote ports
63 or unspecified remote addresses.
64 Fixed bug which did not properly zero port
65 table entries after a link was deleted.
66 Cleaned up some obsolete comments.
68 Version 1.8: January 14, 1997 (cjm)
69 Fixed data type error in StartPoint().
70 (This error did not exist prior to v1.7
71 and was discovered and fixed by Ari Suutari)
73 Version 1.9: February 1, 1997
74 Optionally, connections initiated from packet aliasing host
75 machine will will not have their port number aliased unless it
76 conflicts with an aliasing port already being used. (cjm)
78 All options earlier being #ifdef'ed are now available through
79 a new interface, SetPacketAliasMode(). This allows run time
80 control (which is now available in PPP+pktAlias through the
81 'alias' keyword). (ee)
83 Added ability to create an alias port without
84 either destination address or port specified.
85 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
87 Removed K&R style function headers
88 and general cleanup. (ee)
90 Added packetAliasMode to replace compiler #defines's (ee)
92 Allocates sockets for partially specified
93 ports if ALIAS_USE_SOCKETS defined. (cjm)
95 Version 2.0: March, 1997
96 SetAliasAddress() will now clean up alias links
97 if the aliasing address is changed. (cjm)
99 PacketAliasPermanentLink() function added to support permanent
100 links. (J. Fortes suggested the need for this.)
103 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
105 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
108 These permanent links allow for incoming connections to
109 machines on the local network. They can be given with a
110 user-chosen amount of specificity, with increasing specificity
111 meaning more security. (cjm)
113 Quite a bit of rework to the basic engine. The portTable[]
114 array, which kept track of which ports were in use was replaced
115 by a table/linked list structure. (cjm)
117 SetExpire() function added. (cjm)
119 DeleteLink() no longer frees memory association with a pointer
120 to a fragment (this bug was first recognized by E. Eklund in
123 Version 2.1: May, 1997 (cjm)
124 Packet aliasing engine reworked so that it can handle
125 multiple external addresses rather than just a single
128 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
129 added to the API. The first function is a more generalized
130 version of PacketAliasPermanentLink(). The second function
131 implements static network address translation.
133 Version 3.2: July, 2000 (salander and satoh)
134 Added FindNewPortGroup to get contiguous range of port values.
136 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
137 link but not actually add one.
139 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
140 except that the alias port (from FindNewPortGroup) is provided
143 See HISTORY file for additional revisions.
147 /* System include files */
148 #include <sys/param.h>
149 #include <sys/queue.h>
150 #include <sys/socket.h>
151 #include <sys/time.h>
158 /* BSD network include files */
159 #include <netinet/in_systm.h>
160 #include <netinet/in.h>
161 #include <netinet/ip.h>
162 #include <netinet/tcp.h>
163 #include <arpa/inet.h>
166 #include "alias_local.h"
171 Constants (note: constants are also defined
172 near relevant functions or structs)
175 /* Sizes of input and output link tables */
176 #define LINK_TABLE_OUT_SIZE 101
177 #define LINK_TABLE_IN_SIZE 4001
179 /* Parameters used for cleanup of expired links */
180 #define ALIAS_CLEANUP_INTERVAL_SECS 60
181 #define ALIAS_CLEANUP_MAX_SPOKES 30
183 /* Timeouts (in seconds) for different link types */
184 #define ICMP_EXPIRE_TIME 60
185 #define UDP_EXPIRE_TIME 60
186 #define PROTO_EXPIRE_TIME 60
187 #define FRAGMENT_ID_EXPIRE_TIME 10
188 #define FRAGMENT_PTR_EXPIRE_TIME 30
190 /* TCP link expire time for different cases */
191 /* When the link has been used and closed - minimal grace time to
192 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
193 #ifndef TCP_EXPIRE_DEAD
194 # define TCP_EXPIRE_DEAD 10
197 /* When the link has been used and closed on one side - the other side
198 is allowed to still send data */
199 #ifndef TCP_EXPIRE_SINGLEDEAD
200 # define TCP_EXPIRE_SINGLEDEAD 90
203 /* When the link isn't yet up */
204 #ifndef TCP_EXPIRE_INITIAL
205 # define TCP_EXPIRE_INITIAL 300
208 /* When the link is up */
209 #ifndef TCP_EXPIRE_CONNECTED
210 # define TCP_EXPIRE_CONNECTED 86400
214 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
215 These constants can be anything except zero, which indicates an
216 unknown port number. */
218 #define NO_DEST_PORT 1
219 #define NO_SRC_PORT 1
225 The fundamental data structure used in this program is
226 "struct alias_link". Whenever a TCP connection is made,
227 a UDP datagram is sent out, or an ICMP echo request is made,
228 a link record is made (if it has not already been created).
229 The link record is identified by the source address/port
230 and the destination address/port. In the case of an ICMP
231 echo request, the source port is treated as being equivalent
232 with the 16-bit ID number of the ICMP packet.
234 The link record also can store some auxiliary data. For
235 TCP connections that have had sequence and acknowledgment
236 modifications, data space is available to track these changes.
237 A state field is used to keep track in changes to the TCP
238 connection state. ID numbers of fragments can also be
239 stored in the auxiliary space. Pointers to unresolved
240 fragments can also be stored.
242 The link records support two independent chainings. Lookup
243 tables for input and out tables hold the initial pointers
244 the link chains. On input, the lookup table indexes on alias
245 port and link type. On output, the lookup table indexes on
246 source address, destination address, source port, destination
250 struct ack_data_record
/* used to save changes to ACK/sequence numbers */
258 struct tcp_state
/* Information about TCP connection */
260 int in
; /* State for outside -> inside */
261 int out
; /* State for inside -> outside */
262 int index
; /* Index to ACK data array */
263 int ack_modified
; /* Indicates whether ACK and sequence numbers */
267 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
268 saved for a modified TCP stream */
271 struct tcp_state state
;
272 struct ack_data_record ack
[N_LINK_TCP_DATA
];
273 int fwhole
; /* Which firewall record is used for this hole? */
276 struct server
/* LSNAT server pool (circular list) */
283 struct alias_link
/* Main data structure */
285 struct in_addr src_addr
; /* Address and port information */
286 struct in_addr dst_addr
;
287 struct in_addr alias_addr
;
288 struct in_addr proxy_addr
;
293 struct server
*server
;
295 int link_type
; /* Type of link: TCP, UDP, ICMP, proto, frag */
297 /* values for link_type */
298 #define LINK_ICMP IPPROTO_ICMP
299 #define LINK_UDP IPPROTO_UDP
300 #define LINK_TCP IPPROTO_TCP
301 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
302 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
303 #define LINK_ADDR (IPPROTO_MAX + 3)
304 #define LINK_PPTP (IPPROTO_MAX + 4)
306 int flags
; /* indicates special characteristics */
309 #define LINK_UNKNOWN_DEST_PORT 0x01
310 #define LINK_UNKNOWN_DEST_ADDR 0x02
311 #define LINK_PERMANENT 0x04
312 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
313 #define LINK_UNFIREWALLED 0x08
314 #define LINK_LAST_LINE_CRLF_TERMED 0x10
316 int timestamp
; /* Time link was last accessed */
317 int expire_time
; /* Expire time for link */
319 int sockfd
; /* socket descriptor */
321 LIST_ENTRY(alias_link
) list_out
; /* Linked list of pointers for */
322 LIST_ENTRY(alias_link
) list_in
; /* input and output lookup tables */
324 union /* Auxiliary data */
327 struct in_addr frag_addr
;
338 The global variables listed here are only accessed from
339 within alias_db.c and so are prefixed with the static
343 int packetAliasMode
; /* Mode flags */
344 /* - documented in alias.h */
346 static struct in_addr aliasAddress
; /* Address written onto source */
347 /* field of IP packet. */
349 static struct in_addr targetAddress
; /* IP address incoming packets */
350 /* are sent to if no aliasing */
351 /* link already exists */
353 static struct in_addr nullAddress
; /* Used as a dummy parameter for */
354 /* some function calls */
355 static LIST_HEAD(, alias_link
)
356 linkTableOut
[LINK_TABLE_OUT_SIZE
]; /* Lookup table of pointers to */
357 /* chains of link records. Each */
358 static LIST_HEAD(, alias_link
) /* link record is doubly indexed */
359 linkTableIn
[LINK_TABLE_IN_SIZE
]; /* into input and output lookup */
362 static int icmpLinkCount
; /* Link statistics */
363 static int udpLinkCount
;
364 static int tcpLinkCount
;
365 static int pptpLinkCount
;
366 static int protoLinkCount
;
367 static int fragmentIdLinkCount
;
368 static int fragmentPtrLinkCount
;
369 static int sockCount
;
371 static int cleanupIndex
; /* Index to chain of link table */
372 /* being inspected for old links */
374 static int timeStamp
; /* System time in seconds for */
377 static int lastCleanupTime
; /* Last time IncrementalCleanup() */
380 static int houseKeepingResidual
; /* used by HouseKeeping() */
382 static int deleteAllLinks
; /* If equal to zero, DeleteLink() */
383 /* will not remove permanent links */
385 static FILE *monitorFile
; /* File descriptor for link */
386 /* statistics monitoring file */
388 static int newDefaultLink
; /* Indicates if a new aliasing */
389 /* link has been created after a */
390 /* call to PacketAliasIn/Out(). */
393 static int fireWallFD
= -1; /* File descriptor to be able to */
394 /* control firewall. Opened by */
395 /* PacketAliasSetMode on first */
396 /* setting the PKT_ALIAS_PUNCH_FW */
406 /* Internal utility routines (used only in alias_db.c)
408 Lookup table starting points:
409 StartPointIn() -- link table initial search point for
411 StartPointOut() -- link table initial search point for
415 SeqDiff() -- difference between two TCP sequences
416 ShowAliasStats() -- send alias statistics to a monitor file
420 /* Local prototypes */
421 static u_int
StartPointIn(struct in_addr
, u_short
, int);
423 static u_int
StartPointOut(struct in_addr
, struct in_addr
,
424 u_short
, u_short
, int);
426 static int SeqDiff(u_long
, u_long
);
428 static void ShowAliasStats(void);
431 /* Firewall control */
432 static void InitPunchFW(void);
433 static void UninitPunchFW(void);
434 static void ClearFWHole(struct alias_link
*link
);
437 /* Log file control */
438 static void InitPacketAliasLog(void);
439 static void UninitPacketAliasLog(void);
442 StartPointIn(struct in_addr alias_addr
,
448 n
= alias_addr
.s_addr
;
449 if (link_type
!= LINK_PPTP
)
452 return(n
% LINK_TABLE_IN_SIZE
);
457 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
458 u_short src_port
, u_short dst_port
, int link_type
)
463 n
+= dst_addr
.s_addr
;
464 if (link_type
!= LINK_PPTP
) {
470 return(n
% LINK_TABLE_OUT_SIZE
);
475 SeqDiff(u_long x
, u_long y
)
477 /* Return the difference between two TCP sequence numbers */
480 This function is encapsulated in case there are any unusual
481 arithmetic conditions that need to be considered.
484 return (ntohl(y
) - ntohl(x
));
491 /* Used for debugging */
495 fprintf(monitorFile
, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
502 fragmentPtrLinkCount
);
504 fprintf(monitorFile
, " / tot=%d (sock=%d)\n",
505 icmpLinkCount
+ udpLinkCount
509 + fragmentIdLinkCount
510 + fragmentPtrLinkCount
,
521 /* Internal routines for finding, deleting and adding links
524 GetNewPort() -- find and reserve new alias port number
525 GetSocket() -- try to allocate a socket for a given port
527 Link creation and deletion:
528 CleanupAliasData() - remove all link chains from lookup table
529 IncrementalCleanup() - look for stale links in a single chain
530 DeleteLink() - remove link
532 ReLink() - change link
535 FindLinkOut() - find link for outgoing packets
536 FindLinkIn() - find link for incoming packets
539 FindNewPortGroup() - find an available group of ports
542 /* Local prototypes */
543 static int GetNewPort(struct alias_link
*, int);
545 static u_short
GetSocket(u_short
, int *, int);
547 static void CleanupAliasData(void);
549 static void IncrementalCleanup(void);
551 static void DeleteLink(struct alias_link
*);
553 static struct alias_link
*
554 AddLink(struct in_addr
, struct in_addr
, struct in_addr
,
555 u_short
, u_short
, int, int);
557 static struct alias_link
*
558 ReLink(struct alias_link
*,
559 struct in_addr
, struct in_addr
, struct in_addr
,
560 u_short
, u_short
, int, int);
562 static struct alias_link
*
563 FindLinkOut(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
565 static struct alias_link
*
566 FindLinkIn(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
569 #define ALIAS_PORT_BASE 0x08000
570 #define ALIAS_PORT_MASK 0x07fff
571 #define ALIAS_PORT_MASK_EVEN 0x07ffe
572 #define GET_NEW_PORT_MAX_ATTEMPTS 20
574 #define GET_ALIAS_PORT -1
575 #define GET_ALIAS_ID GET_ALIAS_PORT
577 #define FIND_EVEN_ALIAS_BASE 1
579 /* GetNewPort() allocates port numbers. Note that if a port number
580 is already in use, that does not mean that it cannot be used by
581 another link concurrently. This is because GetNewPort() looks for
582 unused triplets: (dest addr, dest port, alias port). */
585 GetNewPort(struct alias_link
*link
, int alias_port_param
)
593 Description of alias_port_param for GetNewPort(). When
594 this parameter is zero or positive, it precisely specifies
595 the port number. GetNewPort() will return this number
596 without check that it is in use.
598 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
599 selected port number.
602 if (alias_port_param
== GET_ALIAS_PORT
)
605 * The aliasing port is automatically selected
606 * by one of two methods below:
608 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
610 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
)
613 * When the PKT_ALIAS_SAME_PORTS option is
614 * chosen, the first try will be the
615 * actual source port. If this is already
616 * in use, the remainder of the trials
619 port_net
= link
->src_port
;
620 port_sys
= ntohs(port_net
);
624 /* First trial and all subsequent are random. */
625 port_sys
= random() & ALIAS_PORT_MASK
;
626 port_sys
+= ALIAS_PORT_BASE
;
627 port_net
= htons(port_sys
);
630 else if (alias_port_param
>= 0 && alias_port_param
< 0x10000)
632 link
->alias_port
= (u_short
) alias_port_param
;
638 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
639 fprintf(stderr
, "input parameter error\n");
645 /* Port number search */
646 for (i
=0; i
<max_trials
; i
++)
649 struct alias_link
*search_result
;
651 search_result
= FindLinkIn(link
->dst_addr
, link
->alias_addr
,
652 link
->dst_port
, port_net
,
655 if (search_result
== NULL
)
657 else if (!(link
->flags
& LINK_PARTIALLY_SPECIFIED
)
658 && (search_result
->flags
& LINK_PARTIALLY_SPECIFIED
))
665 if ((packetAliasMode
& PKT_ALIAS_USE_SOCKETS
)
666 && (link
->flags
& LINK_PARTIALLY_SPECIFIED
)
667 && ((link
->link_type
== LINK_TCP
) ||
668 (link
->link_type
== LINK_UDP
)))
670 if (GetSocket(port_net
, &link
->sockfd
, link
->link_type
))
672 link
->alias_port
= port_net
;
678 link
->alias_port
= port_net
;
683 port_sys
= random() & ALIAS_PORT_MASK
;
684 port_sys
+= ALIAS_PORT_BASE
;
685 port_net
= htons(port_sys
);
689 fprintf(stderr
, "PacketAlias/GetnewPort(): ");
690 fprintf(stderr
, "could not find free port\n");
698 GetSocket(u_short port_net
, int *sockfd
, int link_type
)
702 struct sockaddr_in sock_addr
;
704 if (link_type
== LINK_TCP
)
705 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
706 else if (link_type
== LINK_UDP
)
707 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
711 fprintf(stderr
, "PacketAlias/GetSocket(): ");
712 fprintf(stderr
, "incorrect link type\n");
720 fprintf(stderr
, "PacketAlias/GetSocket(): ");
721 fprintf(stderr
, "socket() error %d\n", *sockfd
);
726 sock_addr
.sin_family
= AF_INET
;
727 sock_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
728 sock_addr
.sin_port
= port_net
;
731 (struct sockaddr
*) &sock_addr
,
747 /* FindNewPortGroup() returns a base port number for an available
748 range of contiguous port numbers. Note that if a port number
749 is already in use, that does not mean that it cannot be used by
750 another link concurrently. This is because FindNewPortGroup()
751 looks for unused triplets: (dest addr, dest port, alias port). */
754 FindNewPortGroup(struct in_addr dst_addr
,
755 struct in_addr alias_addr
,
768 * Get link_type from protocol
774 link_type
= LINK_UDP
;
777 link_type
= LINK_TCP
;
785 * The aliasing port is automatically selected
786 * by one of two methods below:
788 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
790 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
) {
792 * When the ALIAS_SAME_PORTS option is
793 * chosen, the first try will be the
794 * actual source port. If this is already
795 * in use, the remainder of the trials
798 port_sys
= ntohs(src_port
);
802 /* First trial and all subsequent are random. */
803 if (align
== FIND_EVEN_ALIAS_BASE
)
804 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
806 port_sys
= random() & ALIAS_PORT_MASK
;
808 port_sys
+= ALIAS_PORT_BASE
;
811 /* Port number search */
812 for (i
= 0; i
< max_trials
; i
++) {
814 struct alias_link
*search_result
;
816 for (j
= 0; j
< port_count
; j
++)
817 if (NULL
!= (search_result
= FindLinkIn(dst_addr
, alias_addr
,
818 dst_port
, htons(port_sys
+ j
),
822 /* Found a good range, return base */
824 return (htons(port_sys
));
826 /* Find a new base to try */
827 if (align
== FIND_EVEN_ALIAS_BASE
)
828 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
830 port_sys
= random() & ALIAS_PORT_MASK
;
832 port_sys
+= ALIAS_PORT_BASE
;
836 fprintf(stderr
, "PacketAlias/FindNewPortGroup(): ");
837 fprintf(stderr
, "could not find free port(s)\n");
844 CleanupAliasData(void)
846 struct alias_link
*link
;
850 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
852 link
= LIST_FIRST(&linkTableOut
[i
]);
855 struct alias_link
*link_next
;
856 link_next
= LIST_NEXT(link
, list_out
);
868 IncrementalCleanup(void)
871 struct alias_link
*link
;
874 link
= LIST_FIRST(&linkTableOut
[cleanupIndex
++]);
878 struct alias_link
*link_next
;
880 link_next
= LIST_NEXT(link
, list_out
);
881 idelta
= timeStamp
- link
->timestamp
;
882 switch (link
->link_type
)
885 if (idelta
> link
->expire_time
)
887 struct tcp_dat
*tcp_aux
;
889 tcp_aux
= link
->data
.tcp
;
890 if (tcp_aux
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
891 || tcp_aux
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
899 if (idelta
> link
->expire_time
)
909 if (cleanupIndex
== LINK_TABLE_OUT_SIZE
)
914 DeleteLink(struct alias_link
*link
)
917 /* Don't do anything if the link is marked permanent */
918 if (deleteAllLinks
== 0 && link
->flags
& LINK_PERMANENT
)
922 /* Delete associated firewall hole, if any */
926 /* Free memory allocated for LSNAT server pool */
927 if (link
->server
!= NULL
) {
928 struct server
*head
, *curr
, *next
;
930 head
= curr
= link
->server
;
934 } while ((curr
= next
) != head
);
937 /* Adjust output table pointers */
938 LIST_REMOVE(link
, list_out
);
940 /* Adjust input table pointers */
941 LIST_REMOVE(link
, list_in
);
943 /* Close socket, if one has been allocated */
944 if (link
->sockfd
!= -1)
950 /* Link-type dependent cleanup */
951 switch(link
->link_type
)
961 free(link
->data
.tcp
);
966 case LINK_FRAGMENT_ID
:
967 fragmentIdLinkCount
--;
969 case LINK_FRAGMENT_PTR
:
970 fragmentPtrLinkCount
--;
971 if (link
->data
.frag_ptr
!= NULL
)
972 free(link
->data
.frag_ptr
);
984 /* Write statistics, if logging enabled */
985 if (packetAliasMode
& PKT_ALIAS_LOG
)
992 static struct alias_link
*
993 AddLink(struct in_addr src_addr
,
994 struct in_addr dst_addr
,
995 struct in_addr alias_addr
,
998 int alias_port_param
, /* if less than zero, alias */
999 int link_type
) /* port will be automatically */
1000 { /* chosen. If greater than */
1001 u_int start_point
; /* zero, equal to alias port */
1002 struct alias_link
*link
;
1004 link
= malloc(sizeof(struct alias_link
));
1007 /* Basic initialization */
1008 link
->src_addr
= src_addr
;
1009 link
->dst_addr
= dst_addr
;
1010 link
->alias_addr
= alias_addr
;
1011 link
->proxy_addr
.s_addr
= INADDR_ANY
;
1012 link
->src_port
= src_port
;
1013 link
->dst_port
= dst_port
;
1014 link
->proxy_port
= 0;
1015 link
->server
= NULL
;
1016 link
->link_type
= link_type
;
1019 link
->timestamp
= timeStamp
;
1021 /* Expiration time */
1025 link
->expire_time
= ICMP_EXPIRE_TIME
;
1028 link
->expire_time
= UDP_EXPIRE_TIME
;
1031 link
->expire_time
= TCP_EXPIRE_INITIAL
;
1034 link
->flags
|= LINK_PERMANENT
; /* no timeout. */
1036 case LINK_FRAGMENT_ID
:
1037 link
->expire_time
= FRAGMENT_ID_EXPIRE_TIME
;
1039 case LINK_FRAGMENT_PTR
:
1040 link
->expire_time
= FRAGMENT_PTR_EXPIRE_TIME
;
1045 link
->expire_time
= PROTO_EXPIRE_TIME
;
1049 /* Determine alias flags */
1050 if (dst_addr
.s_addr
== INADDR_ANY
)
1051 link
->flags
|= LINK_UNKNOWN_DEST_ADDR
;
1053 link
->flags
|= LINK_UNKNOWN_DEST_PORT
;
1055 /* Determine alias port */
1056 if (GetNewPort(link
, alias_port_param
) != 0)
1062 /* Link-type dependent initialization */
1065 struct tcp_dat
*aux_tcp
;
1074 aux_tcp
= malloc(sizeof(struct tcp_dat
));
1075 if (aux_tcp
!= NULL
)
1080 aux_tcp
->state
.in
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1081 aux_tcp
->state
.out
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1082 aux_tcp
->state
.index
= 0;
1083 aux_tcp
->state
.ack_modified
= 0;
1084 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
1085 aux_tcp
->ack
[i
].active
= 0;
1086 aux_tcp
->fwhole
= -1;
1087 link
->data
.tcp
= aux_tcp
;
1092 fprintf(stderr
, "PacketAlias/AddLink: ");
1093 fprintf(stderr
, " cannot allocate auxiliary TCP data\n");
1102 case LINK_FRAGMENT_ID
:
1103 fragmentIdLinkCount
++;
1105 case LINK_FRAGMENT_PTR
:
1106 fragmentPtrLinkCount
++;
1115 /* Set up pointers for output lookup table */
1116 start_point
= StartPointOut(src_addr
, dst_addr
,
1117 src_port
, dst_port
, link_type
);
1118 LIST_INSERT_HEAD(&linkTableOut
[start_point
], link
, list_out
);
1120 /* Set up pointers for input lookup table */
1121 start_point
= StartPointIn(alias_addr
, link
->alias_port
, link_type
);
1122 LIST_INSERT_HEAD(&linkTableIn
[start_point
], link
, list_in
);
1127 fprintf(stderr
, "PacketAlias/AddLink(): ");
1128 fprintf(stderr
, "malloc() call failed.\n");
1132 if (packetAliasMode
& PKT_ALIAS_LOG
)
1140 static struct alias_link
*
1141 ReLink(struct alias_link
*old_link
,
1142 struct in_addr src_addr
,
1143 struct in_addr dst_addr
,
1144 struct in_addr alias_addr
,
1147 int alias_port_param
, /* if less than zero, alias */
1148 int link_type
) /* port will be automatically */
1149 { /* chosen. If greater than */
1150 struct alias_link
*new_link
; /* zero, equal to alias port */
1152 new_link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1153 src_port
, dst_port
, alias_port_param
,
1156 if (new_link
!= NULL
&&
1157 old_link
->link_type
== LINK_TCP
&&
1158 old_link
->data
.tcp
->fwhole
> 0) {
1159 PunchFWHole(new_link
);
1162 DeleteLink(old_link
);
1166 static struct alias_link
*
1167 _FindLinkOut(struct in_addr src_addr
,
1168 struct in_addr dst_addr
,
1172 int replace_partial_links
)
1175 struct alias_link
*link
;
1177 i
= StartPointOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
);
1178 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1180 if (link
->src_addr
.s_addr
== src_addr
.s_addr
1181 && link
->server
== NULL
1182 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1183 && link
->dst_port
== dst_port
1184 && link
->src_port
== src_port
1185 && link
->link_type
== link_type
)
1187 link
->timestamp
= timeStamp
;
1192 /* Search for partially specified links. */
1193 if (link
== NULL
&& replace_partial_links
)
1195 if (dst_port
!= 0 && dst_addr
.s_addr
!= INADDR_ANY
)
1197 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, 0,
1200 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
,
1201 dst_port
, link_type
, 0);
1204 (dst_port
!= 0 || dst_addr
.s_addr
!= INADDR_ANY
))
1206 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
, 0,
1212 src_addr
, dst_addr
, link
->alias_addr
,
1213 src_port
, dst_port
, link
->alias_port
,
1221 static struct alias_link
*
1222 FindLinkOut(struct in_addr src_addr
,
1223 struct in_addr dst_addr
,
1227 int replace_partial_links
)
1229 struct alias_link
*link
;
1231 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
,
1232 link_type
, replace_partial_links
);
1236 /* The following allows permanent links to be
1237 specified as using the default source address
1238 (i.e. device interface address) without knowing
1239 in advance what that address is. */
1240 if (aliasAddress
.s_addr
!= 0 &&
1241 src_addr
.s_addr
== aliasAddress
.s_addr
)
1243 link
= _FindLinkOut(nullAddress
, dst_addr
, src_port
, dst_port
,
1244 link_type
, replace_partial_links
);
1252 static struct alias_link
*
1253 _FindLinkIn(struct in_addr dst_addr
,
1254 struct in_addr alias_addr
,
1258 int replace_partial_links
)
1262 struct alias_link
*link
;
1263 struct alias_link
*link_fully_specified
;
1264 struct alias_link
*link_unknown_all
;
1265 struct alias_link
*link_unknown_dst_addr
;
1266 struct alias_link
*link_unknown_dst_port
;
1268 /* Initialize pointers */
1269 link_fully_specified
= NULL
;
1270 link_unknown_all
= NULL
;
1271 link_unknown_dst_addr
= NULL
;
1272 link_unknown_dst_port
= NULL
;
1274 /* If either the dest addr or port is unknown, the search
1275 loop will have to know about this. */
1278 if (dst_addr
.s_addr
== INADDR_ANY
)
1279 flags_in
|= LINK_UNKNOWN_DEST_ADDR
;
1281 flags_in
|= LINK_UNKNOWN_DEST_PORT
;
1284 start_point
= StartPointIn(alias_addr
, alias_port
, link_type
);
1285 LIST_FOREACH(link
, &linkTableIn
[start_point
], list_in
)
1289 flags
= flags_in
| link
->flags
;
1290 if (!(flags
& LINK_PARTIALLY_SPECIFIED
))
1292 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1293 && link
->alias_port
== alias_port
1294 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1295 && link
->dst_port
== dst_port
1296 && link
->link_type
== link_type
)
1298 link_fully_specified
= link
;
1302 else if ((flags
& LINK_UNKNOWN_DEST_ADDR
)
1303 && (flags
& LINK_UNKNOWN_DEST_PORT
))
1305 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1306 && link
->alias_port
== alias_port
1307 && link
->link_type
== link_type
)
1309 if (link_unknown_all
== NULL
)
1310 link_unknown_all
= link
;
1313 else if (flags
& LINK_UNKNOWN_DEST_ADDR
)
1315 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1316 && link
->alias_port
== alias_port
1317 && link
->link_type
== link_type
1318 && link
->dst_port
== dst_port
)
1320 if (link_unknown_dst_addr
== NULL
)
1321 link_unknown_dst_addr
= link
;
1324 else if (flags
& LINK_UNKNOWN_DEST_PORT
)
1326 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1327 && link
->alias_port
== alias_port
1328 && link
->link_type
== link_type
1329 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
)
1331 if (link_unknown_dst_port
== NULL
)
1332 link_unknown_dst_port
= link
;
1339 if (link_fully_specified
!= NULL
)
1341 link_fully_specified
->timestamp
= timeStamp
;
1342 link
= link_fully_specified
;
1344 else if (link_unknown_dst_port
!= NULL
)
1345 link
= link_unknown_dst_port
;
1346 else if (link_unknown_dst_addr
!= NULL
)
1347 link
= link_unknown_dst_addr
;
1348 else if (link_unknown_all
!= NULL
)
1349 link
= link_unknown_all
;
1353 if (replace_partial_links
&&
1354 (link
->flags
& LINK_PARTIALLY_SPECIFIED
|| link
->server
!= NULL
))
1356 struct in_addr src_addr
;
1359 if (link
->server
!= NULL
) { /* LSNAT link */
1360 src_addr
= link
->server
->addr
;
1361 src_port
= link
->server
->port
;
1362 link
->server
= link
->server
->next
;
1364 src_addr
= link
->src_addr
;
1365 src_port
= link
->src_port
;
1369 src_addr
, dst_addr
, alias_addr
,
1370 src_port
, dst_port
, alias_port
,
1377 static struct alias_link
*
1378 FindLinkIn(struct in_addr dst_addr
,
1379 struct in_addr alias_addr
,
1383 int replace_partial_links
)
1385 struct alias_link
*link
;
1387 link
= _FindLinkIn(dst_addr
, alias_addr
, dst_port
, alias_port
,
1388 link_type
, replace_partial_links
);
1392 /* The following allows permanent links to be
1393 specified as using the default aliasing address
1394 (i.e. device interface address) without knowing
1395 in advance what that address is. */
1396 if (aliasAddress
.s_addr
!= 0 &&
1397 alias_addr
.s_addr
== aliasAddress
.s_addr
)
1399 link
= _FindLinkIn(dst_addr
, nullAddress
, dst_port
, alias_port
,
1400 link_type
, replace_partial_links
);
1410 /* External routines for finding/adding links
1412 -- "external" means outside alias_db.c, but within alias*.c --
1414 FindIcmpIn(), FindIcmpOut()
1415 FindFragmentIn1(), FindFragmentIn2()
1416 AddFragmentPtrLink(), FindFragmentPtr()
1417 FindProtoIn(), FindProtoOut()
1418 FindUdpTcpIn(), FindUdpTcpOut()
1419 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1420 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1421 FindOriginalAddress(), FindAliasAddress()
1423 (prototypes in alias_local.h)
1428 FindIcmpIn(struct in_addr dst_addr
,
1429 struct in_addr alias_addr
,
1433 struct alias_link
*link
;
1435 link
= FindLinkIn(dst_addr
, alias_addr
,
1436 NO_DEST_PORT
, id_alias
,
1438 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1440 struct in_addr target_addr
;
1442 target_addr
= FindOriginalAddress(alias_addr
);
1443 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1444 id_alias
, NO_DEST_PORT
, id_alias
,
1453 FindIcmpOut(struct in_addr src_addr
,
1454 struct in_addr dst_addr
,
1458 struct alias_link
* link
;
1460 link
= FindLinkOut(src_addr
, dst_addr
,
1463 if (link
== NULL
&& create
)
1465 struct in_addr alias_addr
;
1467 alias_addr
= FindAliasAddress(src_addr
);
1468 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1469 id
, NO_DEST_PORT
, GET_ALIAS_ID
,
1478 FindFragmentIn1(struct in_addr dst_addr
,
1479 struct in_addr alias_addr
,
1482 struct alias_link
*link
;
1484 link
= FindLinkIn(dst_addr
, alias_addr
,
1485 NO_DEST_PORT
, ip_id
,
1486 LINK_FRAGMENT_ID
, 0);
1490 link
= AddLink(nullAddress
, dst_addr
, alias_addr
,
1491 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1500 FindFragmentIn2(struct in_addr dst_addr
, /* Doesn't add a link if one */
1501 struct in_addr alias_addr
, /* is not found. */
1504 return FindLinkIn(dst_addr
, alias_addr
,
1505 NO_DEST_PORT
, ip_id
,
1506 LINK_FRAGMENT_ID
, 0);
1511 AddFragmentPtrLink(struct in_addr dst_addr
,
1514 return AddLink(nullAddress
, dst_addr
, nullAddress
,
1515 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1521 FindFragmentPtr(struct in_addr dst_addr
,
1524 return FindLinkIn(dst_addr
, nullAddress
,
1525 NO_DEST_PORT
, ip_id
,
1526 LINK_FRAGMENT_PTR
, 0);
1531 FindProtoIn(struct in_addr dst_addr
,
1532 struct in_addr alias_addr
,
1535 struct alias_link
*link
;
1537 link
= FindLinkIn(dst_addr
, alias_addr
,
1541 if (link
== NULL
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1543 struct in_addr target_addr
;
1545 target_addr
= FindOriginalAddress(alias_addr
);
1546 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1547 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1556 FindProtoOut(struct in_addr src_addr
,
1557 struct in_addr dst_addr
,
1560 struct alias_link
*link
;
1562 link
= FindLinkOut(src_addr
, dst_addr
,
1563 NO_SRC_PORT
, NO_DEST_PORT
,
1568 struct in_addr alias_addr
;
1570 alias_addr
= FindAliasAddress(src_addr
);
1571 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1572 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1581 FindUdpTcpIn(struct in_addr dst_addr
,
1582 struct in_addr alias_addr
,
1589 struct alias_link
*link
;
1594 link_type
= LINK_UDP
;
1597 link_type
= LINK_TCP
;
1604 link
= FindLinkIn(dst_addr
, alias_addr
,
1605 dst_port
, alias_port
,
1608 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1610 struct in_addr target_addr
;
1612 target_addr
= FindOriginalAddress(alias_addr
);
1613 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1614 alias_port
, dst_port
, alias_port
,
1623 FindUdpTcpOut(struct in_addr src_addr
,
1624 struct in_addr dst_addr
,
1631 struct alias_link
*link
;
1636 link_type
= LINK_UDP
;
1639 link_type
= LINK_TCP
;
1646 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
, create
);
1648 if (link
== NULL
&& create
)
1650 struct in_addr alias_addr
;
1652 alias_addr
= FindAliasAddress(src_addr
);
1653 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1654 src_port
, dst_port
, GET_ALIAS_PORT
,
1663 AddPptp(struct in_addr src_addr
,
1664 struct in_addr dst_addr
,
1665 struct in_addr alias_addr
,
1666 u_int16_t src_call_id
)
1668 struct alias_link
*link
;
1670 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1671 src_call_id
, 0, GET_ALIAS_PORT
,
1679 FindPptpOutByCallId(struct in_addr src_addr
,
1680 struct in_addr dst_addr
,
1681 u_int16_t src_call_id
)
1684 struct alias_link
*link
;
1686 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1687 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1688 if (link
->link_type
== LINK_PPTP
&&
1689 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1690 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1691 link
->src_port
== src_call_id
)
1699 FindPptpOutByPeerCallId(struct in_addr src_addr
,
1700 struct in_addr dst_addr
,
1701 u_int16_t dst_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
->dst_port
== dst_call_id
)
1719 FindPptpInByCallId(struct in_addr dst_addr
,
1720 struct in_addr alias_addr
,
1721 u_int16_t dst_call_id
)
1724 struct alias_link
*link
;
1726 i
= StartPointIn(alias_addr
, 0, LINK_PPTP
);
1727 LIST_FOREACH(link
, &linkTableIn
[i
], list_in
)
1728 if (link
->link_type
== LINK_PPTP
&&
1729 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1730 link
->alias_addr
.s_addr
== alias_addr
.s_addr
&&
1731 link
->dst_port
== dst_call_id
)
1739 FindPptpInByPeerCallId(struct in_addr dst_addr
,
1740 struct in_addr alias_addr
,
1741 u_int16_t alias_call_id
)
1743 struct alias_link
*link
;
1745 link
= FindLinkIn(dst_addr
, alias_addr
,
1746 0/* any */, alias_call_id
,
1755 FindRtspOut(struct in_addr src_addr
,
1756 struct in_addr dst_addr
,
1762 struct alias_link
*link
;
1767 link_type
= LINK_UDP
;
1770 link_type
= LINK_TCP
;
1777 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, 0, link_type
, 1);
1781 struct in_addr alias_addr
;
1783 alias_addr
= FindAliasAddress(src_addr
);
1784 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1785 src_port
, 0, alias_port
,
1794 FindOriginalAddress(struct in_addr alias_addr
)
1796 struct alias_link
*link
;
1798 link
= FindLinkIn(nullAddress
, alias_addr
,
1799 0, 0, LINK_ADDR
, 0);
1803 if (targetAddress
.s_addr
== INADDR_ANY
)
1805 else if (targetAddress
.s_addr
== INADDR_NONE
)
1806 return aliasAddress
;
1808 return targetAddress
;
1812 if (link
->server
!= NULL
) { /* LSNAT link */
1813 struct in_addr src_addr
;
1815 src_addr
= link
->server
->addr
;
1816 link
->server
= link
->server
->next
;
1818 } else if (link
->src_addr
.s_addr
== INADDR_ANY
)
1819 return aliasAddress
;
1821 return link
->src_addr
;
1827 FindAliasAddress(struct in_addr original_addr
)
1829 struct alias_link
*link
;
1831 link
= FindLinkOut(original_addr
, nullAddress
,
1832 0, 0, LINK_ADDR
, 0);
1835 return aliasAddress
;
1839 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1840 return aliasAddress
;
1842 return link
->alias_addr
;
1847 /* External routines for getting or changing link data
1848 (external to alias_db.c, but internal to alias*.c)
1850 SetFragmentData(), GetFragmentData()
1851 SetFragmentPtr(), GetFragmentPtr()
1852 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1853 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1854 GetOriginalPort(), GetAliasPort()
1855 SetAckModified(), GetAckModified()
1856 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1857 SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
1863 SetFragmentAddr(struct alias_link
*link
, struct in_addr src_addr
)
1865 link
->data
.frag_addr
= src_addr
;
1870 GetFragmentAddr(struct alias_link
*link
, struct in_addr
*src_addr
)
1872 *src_addr
= link
->data
.frag_addr
;
1877 SetFragmentPtr(struct alias_link
*link
, char *fptr
)
1879 link
->data
.frag_ptr
= fptr
;
1884 GetFragmentPtr(struct alias_link
*link
, char **fptr
)
1886 *fptr
= link
->data
.frag_ptr
;
1891 SetStateIn(struct alias_link
*link
, int state
)
1893 /* TCP input state */
1895 case ALIAS_TCP_STATE_DISCONNECTED
:
1896 if (link
->data
.tcp
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
1897 link
->expire_time
= TCP_EXPIRE_DEAD
;
1899 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1901 case ALIAS_TCP_STATE_CONNECTED
:
1902 if (link
->data
.tcp
->state
.out
== ALIAS_TCP_STATE_CONNECTED
)
1903 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
1908 link
->data
.tcp
->state
.in
= state
;
1913 SetStateOut(struct alias_link
*link
, int state
)
1915 /* TCP output state */
1917 case ALIAS_TCP_STATE_DISCONNECTED
:
1918 if (link
->data
.tcp
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
)
1919 link
->expire_time
= TCP_EXPIRE_DEAD
;
1921 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1923 case ALIAS_TCP_STATE_CONNECTED
:
1924 if (link
->data
.tcp
->state
.in
== ALIAS_TCP_STATE_CONNECTED
)
1925 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
1930 link
->data
.tcp
->state
.out
= state
;
1935 GetStateIn(struct alias_link
*link
)
1937 /* TCP input state */
1938 return link
->data
.tcp
->state
.in
;
1943 GetStateOut(struct alias_link
*link
)
1945 /* TCP output state */
1946 return link
->data
.tcp
->state
.out
;
1951 GetOriginalAddress(struct alias_link
*link
)
1953 if (link
->src_addr
.s_addr
== INADDR_ANY
)
1954 return aliasAddress
;
1956 return(link
->src_addr
);
1961 GetDestAddress(struct alias_link
*link
)
1963 return(link
->dst_addr
);
1968 GetAliasAddress(struct alias_link
*link
)
1970 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1971 return aliasAddress
;
1973 return link
->alias_addr
;
1978 GetDefaultAliasAddress(void)
1980 return aliasAddress
;
1985 SetDefaultAliasAddress(struct in_addr alias_addr
)
1987 aliasAddress
= alias_addr
;
1992 GetOriginalPort(struct alias_link
*link
)
1994 return(link
->src_port
);
1999 GetAliasPort(struct alias_link
*link
)
2001 return(link
->alias_port
);
2006 GetDestPort(struct alias_link
*link
)
2008 return(link
->dst_port
);
2013 SetAckModified(struct alias_link
*link
)
2015 /* Indicate that ACK numbers have been modified in a TCP connection */
2016 link
->data
.tcp
->state
.ack_modified
= 1;
2021 GetProxyAddress(struct alias_link
*link
)
2023 return link
->proxy_addr
;
2028 SetProxyAddress(struct alias_link
*link
, struct in_addr addr
)
2030 link
->proxy_addr
= addr
;
2035 GetProxyPort(struct alias_link
*link
)
2037 return link
->proxy_port
;
2042 SetProxyPort(struct alias_link
*link
, u_short port
)
2044 link
->proxy_port
= port
;
2049 GetAckModified(struct alias_link
*link
)
2051 /* See if ACK numbers have been modified */
2052 return link
->data
.tcp
->state
.ack_modified
;
2057 GetDeltaAckIn(struct ip
*pip
, struct alias_link
*link
)
2060 Find out how much the ACK number has been altered for an incoming
2061 TCP packet. To do this, a circular list of ACK numbers where the TCP
2062 packet size was altered is searched.
2067 int delta
, ack_diff_min
;
2070 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2075 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2077 struct ack_data_record x
;
2079 x
= link
->data
.tcp
->ack
[i
];
2084 ack_diff
= SeqDiff(x
.ack_new
, ack
);
2087 if (ack_diff_min
>= 0)
2089 if (ack_diff
< ack_diff_min
)
2092 ack_diff_min
= ack_diff
;
2098 ack_diff_min
= ack_diff
;
2108 GetDeltaSeqOut(struct ip
*pip
, struct alias_link
*link
)
2111 Find out how much the sequence number has been altered for an outgoing
2112 TCP packet. To do this, a circular list of ACK numbers where the TCP
2113 packet size was altered is searched.
2118 int delta
, seq_diff_min
;
2121 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2126 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2128 struct ack_data_record x
;
2130 x
= link
->data
.tcp
->ack
[i
];
2135 seq_diff
= SeqDiff(x
.ack_old
, seq
);
2138 if (seq_diff_min
>= 0)
2140 if (seq_diff
< seq_diff_min
)
2143 seq_diff_min
= seq_diff
;
2149 seq_diff_min
= seq_diff
;
2159 AddSeq(struct ip
*pip
, struct alias_link
*link
, int delta
)
2162 When a TCP packet has been altered in length, save this
2163 information in a circular list. If enough packets have
2164 been altered, then this list will begin to overwrite itself.
2168 struct ack_data_record x
;
2169 int hlen
, tlen
, dlen
;
2172 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2174 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
2175 tlen
= ntohs(pip
->ip_len
);
2178 x
.ack_old
= htonl(ntohl(tc
->th_seq
) + dlen
);
2179 x
.ack_new
= htonl(ntohl(tc
->th_seq
) + dlen
+ delta
);
2183 i
= link
->data
.tcp
->state
.index
;
2184 link
->data
.tcp
->ack
[i
] = x
;
2187 if (i
== N_LINK_TCP_DATA
)
2188 link
->data
.tcp
->state
.index
= 0;
2190 link
->data
.tcp
->state
.index
= i
;
2194 SetExpire(struct alias_link
*link
, int expire
)
2198 link
->flags
&= ~LINK_PERMANENT
;
2201 else if (expire
== -1)
2203 link
->flags
|= LINK_PERMANENT
;
2205 else if (expire
> 0)
2207 link
->expire_time
= expire
;
2212 fprintf(stderr
, "PacketAlias/SetExpire(): ");
2213 fprintf(stderr
, "error in expire parameter\n");
2219 ClearCheckNewLink(void)
2225 SetLastLineCrlfTermed(struct alias_link
*link
, int yes
)
2229 link
->flags
|= LINK_LAST_LINE_CRLF_TERMED
;
2231 link
->flags
&= ~LINK_LAST_LINE_CRLF_TERMED
;
2235 GetLastLineCrlfTermed(struct alias_link
*link
)
2238 return (link
->flags
& LINK_LAST_LINE_CRLF_TERMED
);
2242 SetDestCallId(struct alias_link
*link
, u_int16_t cid
)
2246 link
= ReLink(link
, link
->src_addr
, link
->dst_addr
, link
->alias_addr
,
2247 link
->src_port
, cid
, link
->alias_port
, link
->link_type
);
2252 /* Miscellaneous Functions
2255 InitPacketAliasLog()
2256 UninitPacketAliasLog()
2260 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2261 is called to find and remove timed-out aliasing links. Logic exists
2262 to sweep through the entire table and linked list structure
2265 (prototype in alias_local.h)
2276 * Save system time (seconds) in global variable timeStamp for
2277 * use by other functions. This is done so as not to unnecessarily
2278 * waste timeline by making system calls.
2280 gettimeofday(&tv
, &tz
);
2281 timeStamp
= tv
.tv_sec
;
2283 /* Compute number of spokes (output table link chains) to cover */
2284 n100
= LINK_TABLE_OUT_SIZE
* 100 + houseKeepingResidual
;
2285 n100
*= timeStamp
- lastCleanupTime
;
2286 n100
/= ALIAS_CLEANUP_INTERVAL_SECS
;
2290 /* Handle different cases */
2291 if (n
> ALIAS_CLEANUP_MAX_SPOKES
)
2293 n
= ALIAS_CLEANUP_MAX_SPOKES
;
2294 lastCleanupTime
= timeStamp
;
2295 houseKeepingResidual
= 0;
2298 IncrementalCleanup();
2302 lastCleanupTime
= timeStamp
;
2303 houseKeepingResidual
= n100
- 100*n
;
2306 IncrementalCleanup();
2311 fprintf(stderr
, "PacketAlias/HouseKeeping(): ");
2312 fprintf(stderr
, "something unexpected in time values\n");
2314 lastCleanupTime
= timeStamp
;
2315 houseKeepingResidual
= 0;
2320 /* Init the log file and enable logging */
2322 InitPacketAliasLog(void)
2324 if ((~packetAliasMode
& PKT_ALIAS_LOG
)
2325 && (monitorFile
= fopen("/var/log/alias.log", "w")))
2327 packetAliasMode
|= PKT_ALIAS_LOG
;
2328 fprintf(monitorFile
,
2329 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2334 /* Close the log-file and disable logging. */
2336 UninitPacketAliasLog(void)
2339 fclose(monitorFile
);
2342 packetAliasMode
&= ~PKT_ALIAS_LOG
;
2350 /* Outside world interfaces
2352 -- "outside world" means other than alias*.c routines --
2354 PacketAliasRedirectPort()
2355 PacketAliasAddServer()
2356 PacketAliasRedirectProto()
2357 PacketAliasRedirectAddr()
2358 PacketAliasRedirectDelete()
2359 PacketAliasSetAddress()
2362 PacketAliasSetMode()
2364 (prototypes in alias.h)
2367 /* Redirection from a specific public addr:port to a
2368 private addr:port */
2370 PacketAliasRedirectPort(struct in_addr src_addr
, u_short src_port
,
2371 struct in_addr dst_addr
, u_short dst_port
,
2372 struct in_addr alias_addr
, u_short alias_port
,
2376 struct alias_link
*link
;
2381 link_type
= LINK_UDP
;
2384 link_type
= LINK_TCP
;
2388 fprintf(stderr
, "PacketAliasRedirectPort(): ");
2389 fprintf(stderr
, "only TCP and UDP protocols allowed\n");
2394 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2395 src_port
, dst_port
, alias_port
,
2400 link
->flags
|= LINK_PERMANENT
;
2405 fprintf(stderr
, "PacketAliasRedirectPort(): "
2406 "call to AddLink() failed\n");
2413 /* Add server to the pool of servers */
2415 PacketAliasAddServer(struct alias_link
*link
, struct in_addr addr
, u_short port
)
2417 struct server
*server
;
2419 server
= malloc(sizeof(struct server
));
2421 if (server
!= NULL
) {
2422 struct server
*head
;
2424 server
->addr
= addr
;
2425 server
->port
= port
;
2427 head
= link
->server
;
2429 server
->next
= server
;
2433 for (s
= head
; s
->next
!= head
; s
= s
->next
);
2435 server
->next
= head
;
2437 link
->server
= server
;
2443 /* Redirect packets of a given IP protocol from a specific
2444 public address to a private address */
2446 PacketAliasRedirectProto(struct in_addr src_addr
,
2447 struct in_addr dst_addr
,
2448 struct in_addr alias_addr
,
2451 struct alias_link
*link
;
2453 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2454 NO_SRC_PORT
, NO_DEST_PORT
, 0,
2459 link
->flags
|= LINK_PERMANENT
;
2464 fprintf(stderr
, "PacketAliasRedirectProto(): "
2465 "call to AddLink() failed\n");
2472 /* Static address translation */
2474 PacketAliasRedirectAddr(struct in_addr src_addr
,
2475 struct in_addr alias_addr
)
2477 struct alias_link
*link
;
2479 link
= AddLink(src_addr
, nullAddress
, alias_addr
,
2485 link
->flags
|= LINK_PERMANENT
;
2490 fprintf(stderr
, "PacketAliasRedirectAddr(): "
2491 "call to AddLink() failed\n");
2500 PacketAliasRedirectDelete(struct alias_link
*link
)
2502 /* This is a dangerous function to put in the API,
2503 because an invalid pointer can crash the program. */
2512 PacketAliasSetAddress(struct in_addr addr
)
2514 if (packetAliasMode
& PKT_ALIAS_RESET_ON_ADDR_CHANGE
2515 && aliasAddress
.s_addr
!= addr
.s_addr
)
2518 aliasAddress
= addr
;
2523 PacketAliasSetTarget(struct in_addr target_addr
)
2525 targetAddress
= target_addr
;
2530 PacketAliasInit(void)
2535 static int firstCall
= 1;
2539 gettimeofday(&tv
, &tz
);
2540 timeStamp
= tv
.tv_sec
;
2541 lastCleanupTime
= tv
.tv_sec
;
2542 houseKeepingResidual
= 0;
2544 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
2545 LIST_INIT(&linkTableOut
[i
]);
2546 for (i
=0; i
<LINK_TABLE_IN_SIZE
; i
++)
2547 LIST_INIT(&linkTableIn
[i
]);
2549 atexit(PacketAliasUninit
);
2559 aliasAddress
.s_addr
= INADDR_ANY
;
2560 targetAddress
.s_addr
= INADDR_ANY
;
2567 fragmentIdLinkCount
= 0;
2568 fragmentPtrLinkCount
= 0;
2573 packetAliasMode
= PKT_ALIAS_SAME_PORTS
2574 | PKT_ALIAS_USE_SOCKETS
2575 | PKT_ALIAS_RESET_ON_ADDR_CHANGE
;
2579 PacketAliasUninit(void) {
2583 UninitPacketAliasLog();
2590 /* Change mode for some operations */
2593 unsigned int flags
, /* Which state to bring flags to */
2594 unsigned int mask
/* Mask of which flags to affect (use 0 to do a
2595 probe for flag values) */
2598 /* Enable logging? */
2599 if (flags
& mask
& PKT_ALIAS_LOG
)
2601 InitPacketAliasLog(); /* Do the enable */
2603 /* _Disable_ logging? */
2604 if (~flags
& mask
& PKT_ALIAS_LOG
) {
2605 UninitPacketAliasLog();
2609 /* Start punching holes in the firewall? */
2610 if (flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2613 /* Stop punching holes in the firewall? */
2614 if (~flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2619 /* Other flags can be set/cleared without special action */
2620 packetAliasMode
= (flags
& mask
) | (packetAliasMode
& ~mask
);
2621 return packetAliasMode
;
2626 PacketAliasCheckNewLink(void)
2628 return newDefaultLink
;
2635 Code to support firewall punching. This shouldn't really be in this
2636 file, but making variables global is evil too.
2639 /* Firewall include files */
2641 #include <net/ipfw/ip_fw.h>
2646 * helper function, updates the pointer to cmd with the length
2647 * of the current command, and also cleans up the first word of
2648 * the new command in case it has been clobbered before.
2651 next_cmd(ipfw_insn
*cmd
)
2654 bzero(cmd
, sizeof(*cmd
));
2659 * A function to fill simple commands of size 1.
2660 * Existing flags are preserved.
2663 fill_cmd(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
, int size
,
2664 int flags
, u_int16_t arg
)
2666 cmd
->opcode
= opcode
;
2667 cmd
->len
= ((cmd
->len
| flags
) & (F_NOT
| F_OR
)) | (size
& F_LEN_MASK
);
2669 return next_cmd(cmd
);
2673 fill_ip(ipfw_insn
*cmd1
, enum ipfw_opcodes opcode
, u_int32_t addr
)
2675 ipfw_insn_ip
*cmd
= (ipfw_insn_ip
*)cmd1
;
2677 cmd
->addr
.s_addr
= addr
;
2678 return fill_cmd(cmd1
, opcode
, F_INSN_SIZE(ipfw_insn_u32
), 0, 0);
2682 fill_one_port(ipfw_insn
*cmd1
, enum ipfw_opcodes opcode
, u_int16_t port
)
2684 ipfw_insn_u16
*cmd
= (ipfw_insn_u16
*)cmd1
;
2686 cmd
->ports
[0] = cmd
->ports
[1] = port
;
2687 return fill_cmd(cmd1
, opcode
, F_INSN_SIZE(ipfw_insn_u16
), 0, 0);
2691 fill_rule(void *buf
, int bufsize
, int rulenum
,
2692 enum ipfw_opcodes action
, int proto
,
2693 struct in_addr sa
, u_int16_t sp
, struct in_addr da
, u_int16_t dp
)
2695 struct ipfw_ioc_rule
*rule
= buf
;
2696 ipfw_insn
*cmd
= (ipfw_insn
*)rule
->cmd
;
2698 bzero(buf
, bufsize
);
2699 rule
->rulenum
= rulenum
;
2701 cmd
= fill_cmd(cmd
, O_PROTO
, F_INSN_SIZE(ipfw_insn
), 0, proto
);
2702 cmd
= fill_ip(cmd
, O_IP_SRC
, sa
.s_addr
);
2703 cmd
= fill_one_port(cmd
, O_IP_SRCPORT
, sp
);
2704 cmd
= fill_ip(cmd
, O_IP_DST
, da
.s_addr
);
2705 cmd
= fill_one_port(cmd
, O_IP_DSTPORT
, dp
);
2707 rule
->act_ofs
= (u_int32_t
*)cmd
- (u_int32_t
*)rule
->cmd
;
2708 cmd
= fill_cmd(cmd
, action
, F_INSN_SIZE(ipfw_insn
), 0, 0);
2710 rule
->cmd_len
= (u_int32_t
*)cmd
- (u_int32_t
*)rule
->cmd
;
2712 return ((void *)cmd
- buf
);
2715 static void ClearAllFWHoles(void);
2717 static int fireWallBaseNum
; /* The first firewall entry free for our use */
2718 static int fireWallNumNums
; /* How many entries can we use? */
2719 static int fireWallActiveNum
; /* Which entry did we last use? */
2720 static char *fireWallField
; /* bool array for entries */
2722 #define fw_setfield(field, num) \
2724 (field)[(num) - fireWallBaseNum] = 1; \
2725 } /*lint -save -e717 */ while(0) /*lint -restore */
2726 #define fw_clrfield(field, num) \
2728 (field)[(num) - fireWallBaseNum] = 0; \
2729 } /*lint -save -e717 */ while(0) /*lint -restore */
2730 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2734 fireWallField
= malloc(fireWallNumNums
);
2735 if (fireWallField
) {
2736 memset(fireWallField
, 0, fireWallNumNums
);
2737 if (fireWallFD
< 0) {
2738 fireWallFD
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2741 fireWallActiveNum
= fireWallBaseNum
;
2746 UninitPunchFW(void) {
2748 if (fireWallFD
>= 0)
2752 free(fireWallField
);
2753 fireWallField
= NULL
;
2754 packetAliasMode
&= ~PKT_ALIAS_PUNCH_FW
;
2757 /* Make a certain link go through the firewall */
2759 PunchFWHole(struct alias_link
*link
) {
2760 int r
; /* Result code */
2761 int fwhole
; /* Where to punch hole */
2763 /* Don't do anything unless we are asked to */
2764 if ( !(packetAliasMode
& PKT_ALIAS_PUNCH_FW
) ||
2766 link
->link_type
!= LINK_TCP
)
2771 /* Find empty slot */
2772 for (fwhole
= fireWallActiveNum
;
2773 fwhole
< fireWallBaseNum
+ fireWallNumNums
&&
2774 fw_tstfield(fireWallField
, fwhole
);
2777 if (fwhole
== fireWallBaseNum
+ fireWallNumNums
) {
2778 for (fwhole
= fireWallBaseNum
;
2779 fwhole
< fireWallActiveNum
&&
2780 fw_tstfield(fireWallField
, fwhole
);
2783 if (fwhole
== fireWallActiveNum
) {
2784 /* No rule point empty - we can't punch more holes. */
2785 fireWallActiveNum
= fireWallBaseNum
;
2787 fprintf(stderr
, "libalias: Unable to create firewall hole!\n");
2792 /* Start next search at next position */
2793 fireWallActiveNum
= fwhole
+1;
2796 * generate two rules of the form
2798 * add fwhole accept tcp from OAddr OPort to DAddr DPort
2799 * add fwhole accept tcp from DAddr DPort to OAddr OPort
2801 if (GetOriginalPort(link
) != 0 && GetDestPort(link
) != 0) {
2802 u_int32_t rulebuf
[IPFW_RULE_SIZE_MAX
];
2805 i
= fill_rule(rulebuf
, sizeof(rulebuf
), fwhole
,
2806 O_ACCEPT
, IPPROTO_TCP
,
2807 GetOriginalAddress(link
), ntohs(GetOriginalPort(link
)),
2808 GetDestAddress(link
), ntohs(GetDestPort(link
)) );
2809 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, rulebuf
, i
);
2811 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2813 i
= fill_rule(rulebuf
, sizeof(rulebuf
), fwhole
,
2814 O_ACCEPT
, IPPROTO_TCP
,
2815 GetDestAddress(link
), ntohs(GetDestPort(link
)),
2816 GetOriginalAddress(link
), ntohs(GetOriginalPort(link
)) );
2817 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, rulebuf
, i
);
2819 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2821 /* Indicate hole applied */
2822 link
->data
.tcp
->fwhole
= fwhole
;
2823 fw_setfield(fireWallField
, fwhole
);
2826 /* Remove a hole in a firewall associated with a particular alias
2827 link. Calling this too often is harmless. */
2829 ClearFWHole(struct alias_link
*link
) {
2830 if (link
->link_type
== LINK_TCP
) {
2831 int fwhole
= link
->data
.tcp
->fwhole
; /* Where is the firewall hole? */
2836 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
,
2837 &fwhole
, sizeof fwhole
))
2839 fw_clrfield(fireWallField
, fwhole
);
2840 link
->data
.tcp
->fwhole
= -1;
2844 /* Clear out the entire range dedicated to firewall holes. */
2846 ClearAllFWHoles(void) {
2852 for (i
= fireWallBaseNum
; i
< fireWallBaseNum
+ fireWallNumNums
; i
++) {
2854 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &r
, sizeof r
))
2857 memset(fireWallField
, 0, fireWallNumNums
);
2862 PacketAliasSetFWBase(unsigned int base
, unsigned int num
) {
2864 fireWallBaseNum
= base
;
2865 fireWallNumNums
= num
;