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 $
29 * $DragonFly: src/lib/libalias/alias_db.c,v 1.6 2007/11/05 08:58:35 sephe Exp $
33 Alias_db.c encapsulates all data structures used for storing
34 packet aliasing data. Other parts of the aliasing software
35 access data through functions provided in this file.
37 Data storage is based on the notion of a "link", which is
38 established for ICMP echo/reply packets, UDP datagrams and
39 TCP stream connections. A link stores the original source
40 and destination addresses. For UDP and TCP, it also stores
41 source and destination port numbers, as well as an alias
42 port number. Links are also used to store information about
45 There is a facility for sweeping through and deleting old
46 links as new packets are sent through. A simple timeout is
47 used for ICMP and UDP links. TCP links are left alone unless
48 there is an incomplete connection, in which case the link
49 can be deleted after a certain amount of time.
52 Initial version: August, 1996 (cjm)
54 Version 1.4: September 16, 1996 (cjm)
55 Facility for handling incoming links added.
57 Version 1.6: September 18, 1996 (cjm)
58 ICMP data handling simplified.
60 Version 1.7: January 9, 1997 (cjm)
61 Fragment handling simplified.
62 Saves pointers for unresolved fragments.
63 Permits links for unspecified remote ports
64 or unspecified remote addresses.
65 Fixed bug which did not properly zero port
66 table entries after a link was deleted.
67 Cleaned up some obsolete comments.
69 Version 1.8: January 14, 1997 (cjm)
70 Fixed data type error in StartPoint().
71 (This error did not exist prior to v1.7
72 and was discovered and fixed by Ari Suutari)
74 Version 1.9: February 1, 1997
75 Optionally, connections initiated from packet aliasing host
76 machine will will not have their port number aliased unless it
77 conflicts with an aliasing port already being used. (cjm)
79 All options earlier being #ifdef'ed are now available through
80 a new interface, SetPacketAliasMode(). This allows run time
81 control (which is now available in PPP+pktAlias through the
82 'alias' keyword). (ee)
84 Added ability to create an alias port without
85 either destination address or port specified.
86 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
88 Removed K&R style function headers
89 and general cleanup. (ee)
91 Added packetAliasMode to replace compiler #defines's (ee)
93 Allocates sockets for partially specified
94 ports if ALIAS_USE_SOCKETS defined. (cjm)
96 Version 2.0: March, 1997
97 SetAliasAddress() will now clean up alias links
98 if the aliasing address is changed. (cjm)
100 PacketAliasPermanentLink() function added to support permanent
101 links. (J. Fortes suggested the need for this.)
104 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
106 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
109 These permanent links allow for incoming connections to
110 machines on the local network. They can be given with a
111 user-chosen amount of specificity, with increasing specificity
112 meaning more security. (cjm)
114 Quite a bit of rework to the basic engine. The portTable[]
115 array, which kept track of which ports were in use was replaced
116 by a table/linked list structure. (cjm)
118 SetExpire() function added. (cjm)
120 DeleteLink() no longer frees memory association with a pointer
121 to a fragment (this bug was first recognized by E. Eklund in
124 Version 2.1: May, 1997 (cjm)
125 Packet aliasing engine reworked so that it can handle
126 multiple external addresses rather than just a single
129 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
130 added to the API. The first function is a more generalized
131 version of PacketAliasPermanentLink(). The second function
132 implements static network address translation.
134 Version 3.2: July, 2000 (salander and satoh)
135 Added FindNewPortGroup to get contiguous range of port values.
137 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
138 link but not actually add one.
140 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
141 except that the alias port (from FindNewPortGroup) is provided
144 See HISTORY file for additional revisions.
148 /* System include files */
149 #include <sys/param.h>
150 #include <sys/queue.h>
151 #include <sys/socket.h>
152 #include <sys/time.h>
159 /* BSD network include files */
160 #include <netinet/in_systm.h>
161 #include <netinet/in.h>
162 #include <netinet/ip.h>
163 #include <netinet/tcp.h>
164 #include <arpa/inet.h>
167 #include "alias_local.h"
172 Constants (note: constants are also defined
173 near relevant functions or structs)
176 /* Sizes of input and output link tables */
177 #define LINK_TABLE_OUT_SIZE 101
178 #define LINK_TABLE_IN_SIZE 4001
180 /* Parameters used for cleanup of expired links */
181 #define ALIAS_CLEANUP_INTERVAL_SECS 60
182 #define ALIAS_CLEANUP_MAX_SPOKES 30
184 /* Timeouts (in seconds) for different link types */
185 #define ICMP_EXPIRE_TIME 60
186 #define UDP_EXPIRE_TIME 60
187 #define PROTO_EXPIRE_TIME 60
188 #define FRAGMENT_ID_EXPIRE_TIME 10
189 #define FRAGMENT_PTR_EXPIRE_TIME 30
191 /* TCP link expire time for different cases */
192 /* When the link has been used and closed - minimal grace time to
193 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
194 #ifndef TCP_EXPIRE_DEAD
195 # define TCP_EXPIRE_DEAD 10
198 /* When the link has been used and closed on one side - the other side
199 is allowed to still send data */
200 #ifndef TCP_EXPIRE_SINGLEDEAD
201 # define TCP_EXPIRE_SINGLEDEAD 90
204 /* When the link isn't yet up */
205 #ifndef TCP_EXPIRE_INITIAL
206 # define TCP_EXPIRE_INITIAL 300
209 /* When the link is up */
210 #ifndef TCP_EXPIRE_CONNECTED
211 # define TCP_EXPIRE_CONNECTED 86400
215 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
216 These constants can be anything except zero, which indicates an
217 unknown port number. */
219 #define NO_DEST_PORT 1
220 #define NO_SRC_PORT 1
226 The fundamental data structure used in this program is
227 "struct alias_link". Whenever a TCP connection is made,
228 a UDP datagram is sent out, or an ICMP echo request is made,
229 a link record is made (if it has not already been created).
230 The link record is identified by the source address/port
231 and the destination address/port. In the case of an ICMP
232 echo request, the source port is treated as being equivalent
233 with the 16-bit ID number of the ICMP packet.
235 The link record also can store some auxiliary data. For
236 TCP connections that have had sequence and acknowledgment
237 modifications, data space is available to track these changes.
238 A state field is used to keep track in changes to the TCP
239 connection state. ID numbers of fragments can also be
240 stored in the auxiliary space. Pointers to unresolved
241 fragments can also be stored.
243 The link records support two independent chainings. Lookup
244 tables for input and out tables hold the initial pointers
245 the link chains. On input, the lookup table indexes on alias
246 port and link type. On output, the lookup table indexes on
247 source address, destination address, source port, destination
251 struct ack_data_record
/* used to save changes to ACK/sequence numbers */
259 struct tcp_state
/* Information about TCP connection */
261 int in
; /* State for outside -> inside */
262 int out
; /* State for inside -> outside */
263 int index
; /* Index to ACK data array */
264 int ack_modified
; /* Indicates whether ACK and sequence numbers */
268 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
269 saved for a modified TCP stream */
272 struct tcp_state state
;
273 struct ack_data_record ack
[N_LINK_TCP_DATA
];
274 int fwhole
; /* Which firewall record is used for this hole? */
277 struct server
/* LSNAT server pool (circular list) */
284 struct alias_link
/* Main data structure */
286 struct in_addr src_addr
; /* Address and port information */
287 struct in_addr dst_addr
;
288 struct in_addr alias_addr
;
289 struct in_addr proxy_addr
;
294 struct server
*server
;
296 int link_type
; /* Type of link: TCP, UDP, ICMP, proto, frag */
298 /* values for link_type */
299 #define LINK_ICMP IPPROTO_ICMP
300 #define LINK_UDP IPPROTO_UDP
301 #define LINK_TCP IPPROTO_TCP
302 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
303 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
304 #define LINK_ADDR (IPPROTO_MAX + 3)
305 #define LINK_PPTP (IPPROTO_MAX + 4)
307 int flags
; /* indicates special characteristics */
310 #define LINK_UNKNOWN_DEST_PORT 0x01
311 #define LINK_UNKNOWN_DEST_ADDR 0x02
312 #define LINK_PERMANENT 0x04
313 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
314 #define LINK_UNFIREWALLED 0x08
315 #define LINK_LAST_LINE_CRLF_TERMED 0x10
317 int timestamp
; /* Time link was last accessed */
318 int expire_time
; /* Expire time for link */
320 int sockfd
; /* socket descriptor */
322 LIST_ENTRY(alias_link
) list_out
; /* Linked list of pointers for */
323 LIST_ENTRY(alias_link
) list_in
; /* input and output lookup tables */
325 union /* Auxiliary data */
328 struct in_addr frag_addr
;
339 The global variables listed here are only accessed from
340 within alias_db.c and so are prefixed with the static
344 int packetAliasMode
; /* Mode flags */
345 /* - documented in alias.h */
347 static struct in_addr aliasAddress
; /* Address written onto source */
348 /* field of IP packet. */
350 static struct in_addr targetAddress
; /* IP address incoming packets */
351 /* are sent to if no aliasing */
352 /* link already exists */
354 static struct in_addr nullAddress
; /* Used as a dummy parameter for */
355 /* some function calls */
356 static LIST_HEAD(, alias_link
)
357 linkTableOut
[LINK_TABLE_OUT_SIZE
]; /* Lookup table of pointers to */
358 /* chains of link records. Each */
359 static LIST_HEAD(, alias_link
) /* link record is doubly indexed */
360 linkTableIn
[LINK_TABLE_IN_SIZE
]; /* into input and output lookup */
363 static int icmpLinkCount
; /* Link statistics */
364 static int udpLinkCount
;
365 static int tcpLinkCount
;
366 static int pptpLinkCount
;
367 static int protoLinkCount
;
368 static int fragmentIdLinkCount
;
369 static int fragmentPtrLinkCount
;
370 static int sockCount
;
372 static int cleanupIndex
; /* Index to chain of link table */
373 /* being inspected for old links */
375 static int timeStamp
; /* System time in seconds for */
378 static int lastCleanupTime
; /* Last time IncrementalCleanup() */
381 static int houseKeepingResidual
; /* used by HouseKeeping() */
383 static int deleteAllLinks
; /* If equal to zero, DeleteLink() */
384 /* will not remove permanent links */
386 static FILE *monitorFile
; /* File descriptor for link */
387 /* statistics monitoring file */
389 static int newDefaultLink
; /* Indicates if a new aliasing */
390 /* link has been created after a */
391 /* call to PacketAliasIn/Out(). */
394 static int fireWallFD
= -1; /* File descriptor to be able to */
395 /* control firewall. Opened by */
396 /* PacketAliasSetMode on first */
397 /* setting the PKT_ALIAS_PUNCH_FW */
407 /* Internal utility routines (used only in alias_db.c)
409 Lookup table starting points:
410 StartPointIn() -- link table initial search point for
412 StartPointOut() -- link table initial search point for
416 SeqDiff() -- difference between two TCP sequences
417 ShowAliasStats() -- send alias statistics to a monitor file
421 /* Local prototypes */
422 static u_int
StartPointIn(struct in_addr
, u_short
, int);
424 static u_int
StartPointOut(struct in_addr
, struct in_addr
,
425 u_short
, u_short
, int);
427 static int SeqDiff(u_long
, u_long
);
429 static void ShowAliasStats(void);
432 /* Firewall control */
433 static void InitPunchFW(void);
434 static void UninitPunchFW(void);
435 static void ClearFWHole(struct alias_link
*link
);
438 /* Log file control */
439 static void InitPacketAliasLog(void);
440 static void UninitPacketAliasLog(void);
443 StartPointIn(struct in_addr alias_addr
,
449 n
= alias_addr
.s_addr
;
450 if (link_type
!= LINK_PPTP
)
453 return(n
% LINK_TABLE_IN_SIZE
);
458 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
459 u_short src_port
, u_short dst_port
, int link_type
)
464 n
+= dst_addr
.s_addr
;
465 if (link_type
!= LINK_PPTP
) {
471 return(n
% LINK_TABLE_OUT_SIZE
);
476 SeqDiff(u_long x
, u_long y
)
478 /* Return the difference between two TCP sequence numbers */
481 This function is encapsulated in case there are any unusual
482 arithmetic conditions that need to be considered.
485 return (ntohl(y
) - ntohl(x
));
492 /* Used for debugging */
496 fprintf(monitorFile
, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
503 fragmentPtrLinkCount
);
505 fprintf(monitorFile
, " / tot=%d (sock=%d)\n",
506 icmpLinkCount
+ udpLinkCount
510 + fragmentIdLinkCount
511 + fragmentPtrLinkCount
,
522 /* Internal routines for finding, deleting and adding links
525 GetNewPort() -- find and reserve new alias port number
526 GetSocket() -- try to allocate a socket for a given port
528 Link creation and deletion:
529 CleanupAliasData() - remove all link chains from lookup table
530 IncrementalCleanup() - look for stale links in a single chain
531 DeleteLink() - remove link
533 ReLink() - change link
536 FindLinkOut() - find link for outgoing packets
537 FindLinkIn() - find link for incoming packets
540 FindNewPortGroup() - find an available group of ports
543 /* Local prototypes */
544 static int GetNewPort(struct alias_link
*, int);
546 static u_short
GetSocket(u_short
, int *, int);
548 static void CleanupAliasData(void);
550 static void IncrementalCleanup(void);
552 static void DeleteLink(struct alias_link
*);
554 static struct alias_link
*
555 AddLink(struct in_addr
, struct in_addr
, struct in_addr
,
556 u_short
, u_short
, int, int);
558 static struct alias_link
*
559 ReLink(struct alias_link
*,
560 struct in_addr
, struct in_addr
, struct in_addr
,
561 u_short
, u_short
, int, int);
563 static struct alias_link
*
564 FindLinkOut(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
566 static struct alias_link
*
567 FindLinkIn(struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
570 #define ALIAS_PORT_BASE 0x08000
571 #define ALIAS_PORT_MASK 0x07fff
572 #define ALIAS_PORT_MASK_EVEN 0x07ffe
573 #define GET_NEW_PORT_MAX_ATTEMPTS 20
575 #define GET_ALIAS_PORT -1
576 #define GET_ALIAS_ID GET_ALIAS_PORT
578 #define FIND_EVEN_ALIAS_BASE 1
580 /* GetNewPort() allocates port numbers. Note that if a port number
581 is already in use, that does not mean that it cannot be used by
582 another link concurrently. This is because GetNewPort() looks for
583 unused triplets: (dest addr, dest port, alias port). */
586 GetNewPort(struct alias_link
*link
, int alias_port_param
)
594 Description of alias_port_param for GetNewPort(). When
595 this parameter is zero or positive, it precisely specifies
596 the port number. GetNewPort() will return this number
597 without check that it is in use.
599 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
600 selected port number.
603 if (alias_port_param
== GET_ALIAS_PORT
)
606 * The aliasing port is automatically selected
607 * by one of two methods below:
609 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
611 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
)
614 * When the PKT_ALIAS_SAME_PORTS option is
615 * chosen, the first try will be the
616 * actual source port. If this is already
617 * in use, the remainder of the trials
620 port_net
= link
->src_port
;
621 port_sys
= ntohs(port_net
);
625 /* First trial and all subsequent are random. */
626 port_sys
= random() & ALIAS_PORT_MASK
;
627 port_sys
+= ALIAS_PORT_BASE
;
628 port_net
= htons(port_sys
);
631 else if (alias_port_param
>= 0 && alias_port_param
< 0x10000)
633 link
->alias_port
= (u_short
) alias_port_param
;
639 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
640 fprintf(stderr
, "input parameter error\n");
646 /* Port number search */
647 for (i
=0; i
<max_trials
; i
++)
650 struct alias_link
*search_result
;
652 search_result
= FindLinkIn(link
->dst_addr
, link
->alias_addr
,
653 link
->dst_port
, port_net
,
656 if (search_result
== NULL
)
658 else if (!(link
->flags
& LINK_PARTIALLY_SPECIFIED
)
659 && (search_result
->flags
& LINK_PARTIALLY_SPECIFIED
))
666 if ((packetAliasMode
& PKT_ALIAS_USE_SOCKETS
)
667 && (link
->flags
& LINK_PARTIALLY_SPECIFIED
)
668 && ((link
->link_type
== LINK_TCP
) ||
669 (link
->link_type
== LINK_UDP
)))
671 if (GetSocket(port_net
, &link
->sockfd
, link
->link_type
))
673 link
->alias_port
= port_net
;
679 link
->alias_port
= port_net
;
684 port_sys
= random() & ALIAS_PORT_MASK
;
685 port_sys
+= ALIAS_PORT_BASE
;
686 port_net
= htons(port_sys
);
690 fprintf(stderr
, "PacketAlias/GetnewPort(): ");
691 fprintf(stderr
, "could not find free port\n");
699 GetSocket(u_short port_net
, int *sockfd
, int link_type
)
703 struct sockaddr_in sock_addr
;
705 if (link_type
== LINK_TCP
)
706 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
707 else if (link_type
== LINK_UDP
)
708 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
712 fprintf(stderr
, "PacketAlias/GetSocket(): ");
713 fprintf(stderr
, "incorrect link type\n");
721 fprintf(stderr
, "PacketAlias/GetSocket(): ");
722 fprintf(stderr
, "socket() error %d\n", *sockfd
);
727 sock_addr
.sin_family
= AF_INET
;
728 sock_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
729 sock_addr
.sin_port
= port_net
;
732 (struct sockaddr
*) &sock_addr
,
748 /* FindNewPortGroup() returns a base port number for an available
749 range of contiguous port numbers. Note that if a port number
750 is already in use, that does not mean that it cannot be used by
751 another link concurrently. This is because FindNewPortGroup()
752 looks for unused triplets: (dest addr, dest port, alias port). */
755 FindNewPortGroup(struct in_addr dst_addr
,
756 struct in_addr alias_addr
,
769 * Get link_type from protocol
775 link_type
= LINK_UDP
;
778 link_type
= LINK_TCP
;
786 * The aliasing port is automatically selected
787 * by one of two methods below:
789 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
791 if (packetAliasMode
& PKT_ALIAS_SAME_PORTS
) {
793 * When the ALIAS_SAME_PORTS option is
794 * chosen, the first try will be the
795 * actual source port. If this is already
796 * in use, the remainder of the trials
799 port_sys
= ntohs(src_port
);
803 /* First trial and all subsequent are random. */
804 if (align
== FIND_EVEN_ALIAS_BASE
)
805 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
807 port_sys
= random() & ALIAS_PORT_MASK
;
809 port_sys
+= ALIAS_PORT_BASE
;
812 /* Port number search */
813 for (i
= 0; i
< max_trials
; i
++) {
815 struct alias_link
*search_result
;
817 for (j
= 0; j
< port_count
; j
++)
818 if (0 != (search_result
= FindLinkIn(dst_addr
, alias_addr
,
819 dst_port
, htons(port_sys
+ j
),
823 /* Found a good range, return base */
825 return (htons(port_sys
));
827 /* Find a new base to try */
828 if (align
== FIND_EVEN_ALIAS_BASE
)
829 port_sys
= random() & ALIAS_PORT_MASK_EVEN
;
831 port_sys
= random() & ALIAS_PORT_MASK
;
833 port_sys
+= ALIAS_PORT_BASE
;
837 fprintf(stderr
, "PacketAlias/FindNewPortGroup(): ");
838 fprintf(stderr
, "could not find free port(s)\n");
845 CleanupAliasData(void)
847 struct alias_link
*link
;
851 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
853 link
= LIST_FIRST(&linkTableOut
[i
]);
856 struct alias_link
*link_next
;
857 link_next
= LIST_NEXT(link
, list_out
);
869 IncrementalCleanup(void)
872 struct alias_link
*link
;
875 link
= LIST_FIRST(&linkTableOut
[cleanupIndex
++]);
879 struct alias_link
*link_next
;
881 link_next
= LIST_NEXT(link
, list_out
);
882 idelta
= timeStamp
- link
->timestamp
;
883 switch (link
->link_type
)
886 if (idelta
> link
->expire_time
)
888 struct tcp_dat
*tcp_aux
;
890 tcp_aux
= link
->data
.tcp
;
891 if (tcp_aux
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
892 || tcp_aux
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
900 if (idelta
> link
->expire_time
)
910 if (cleanupIndex
== LINK_TABLE_OUT_SIZE
)
915 DeleteLink(struct alias_link
*link
)
918 /* Don't do anything if the link is marked permanent */
919 if (deleteAllLinks
== 0 && link
->flags
& LINK_PERMANENT
)
923 /* Delete associated firewall hole, if any */
927 /* Free memory allocated for LSNAT server pool */
928 if (link
->server
!= NULL
) {
929 struct server
*head
, *curr
, *next
;
931 head
= curr
= link
->server
;
935 } while ((curr
= next
) != head
);
938 /* Adjust output table pointers */
939 LIST_REMOVE(link
, list_out
);
941 /* Adjust input table pointers */
942 LIST_REMOVE(link
, list_in
);
944 /* Close socket, if one has been allocated */
945 if (link
->sockfd
!= -1)
951 /* Link-type dependent cleanup */
952 switch(link
->link_type
)
962 free(link
->data
.tcp
);
967 case LINK_FRAGMENT_ID
:
968 fragmentIdLinkCount
--;
970 case LINK_FRAGMENT_PTR
:
971 fragmentPtrLinkCount
--;
972 if (link
->data
.frag_ptr
!= NULL
)
973 free(link
->data
.frag_ptr
);
985 /* Write statistics, if logging enabled */
986 if (packetAliasMode
& PKT_ALIAS_LOG
)
993 static struct alias_link
*
994 AddLink(struct in_addr src_addr
,
995 struct in_addr dst_addr
,
996 struct in_addr alias_addr
,
999 int alias_port_param
, /* if less than zero, alias */
1000 int link_type
) /* port will be automatically */
1001 { /* chosen. If greater than */
1002 u_int start_point
; /* zero, equal to alias port */
1003 struct alias_link
*link
;
1005 link
= malloc(sizeof(struct alias_link
));
1008 /* Basic initialization */
1009 link
->src_addr
= src_addr
;
1010 link
->dst_addr
= dst_addr
;
1011 link
->alias_addr
= alias_addr
;
1012 link
->proxy_addr
.s_addr
= INADDR_ANY
;
1013 link
->src_port
= src_port
;
1014 link
->dst_port
= dst_port
;
1015 link
->proxy_port
= 0;
1016 link
->server
= NULL
;
1017 link
->link_type
= link_type
;
1020 link
->timestamp
= timeStamp
;
1022 /* Expiration time */
1026 link
->expire_time
= ICMP_EXPIRE_TIME
;
1029 link
->expire_time
= UDP_EXPIRE_TIME
;
1032 link
->expire_time
= TCP_EXPIRE_INITIAL
;
1035 link
->flags
|= LINK_PERMANENT
; /* no timeout. */
1037 case LINK_FRAGMENT_ID
:
1038 link
->expire_time
= FRAGMENT_ID_EXPIRE_TIME
;
1040 case LINK_FRAGMENT_PTR
:
1041 link
->expire_time
= FRAGMENT_PTR_EXPIRE_TIME
;
1046 link
->expire_time
= PROTO_EXPIRE_TIME
;
1050 /* Determine alias flags */
1051 if (dst_addr
.s_addr
== INADDR_ANY
)
1052 link
->flags
|= LINK_UNKNOWN_DEST_ADDR
;
1054 link
->flags
|= LINK_UNKNOWN_DEST_PORT
;
1056 /* Determine alias port */
1057 if (GetNewPort(link
, alias_port_param
) != 0)
1063 /* Link-type dependent initialization */
1066 struct tcp_dat
*aux_tcp
;
1075 aux_tcp
= malloc(sizeof(struct tcp_dat
));
1076 if (aux_tcp
!= NULL
)
1081 aux_tcp
->state
.in
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1082 aux_tcp
->state
.out
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1083 aux_tcp
->state
.index
= 0;
1084 aux_tcp
->state
.ack_modified
= 0;
1085 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
1086 aux_tcp
->ack
[i
].active
= 0;
1087 aux_tcp
->fwhole
= -1;
1088 link
->data
.tcp
= aux_tcp
;
1093 fprintf(stderr
, "PacketAlias/AddLink: ");
1094 fprintf(stderr
, " cannot allocate auxiliary TCP data\n");
1103 case LINK_FRAGMENT_ID
:
1104 fragmentIdLinkCount
++;
1106 case LINK_FRAGMENT_PTR
:
1107 fragmentPtrLinkCount
++;
1116 /* Set up pointers for output lookup table */
1117 start_point
= StartPointOut(src_addr
, dst_addr
,
1118 src_port
, dst_port
, link_type
);
1119 LIST_INSERT_HEAD(&linkTableOut
[start_point
], link
, list_out
);
1121 /* Set up pointers for input lookup table */
1122 start_point
= StartPointIn(alias_addr
, link
->alias_port
, link_type
);
1123 LIST_INSERT_HEAD(&linkTableIn
[start_point
], link
, list_in
);
1128 fprintf(stderr
, "PacketAlias/AddLink(): ");
1129 fprintf(stderr
, "malloc() call failed.\n");
1133 if (packetAliasMode
& PKT_ALIAS_LOG
)
1141 static struct alias_link
*
1142 ReLink(struct alias_link
*old_link
,
1143 struct in_addr src_addr
,
1144 struct in_addr dst_addr
,
1145 struct in_addr alias_addr
,
1148 int alias_port_param
, /* if less than zero, alias */
1149 int link_type
) /* port will be automatically */
1150 { /* chosen. If greater than */
1151 struct alias_link
*new_link
; /* zero, equal to alias port */
1153 new_link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1154 src_port
, dst_port
, alias_port_param
,
1157 if (new_link
!= NULL
&&
1158 old_link
->link_type
== LINK_TCP
&&
1159 old_link
->data
.tcp
->fwhole
> 0) {
1160 PunchFWHole(new_link
);
1163 DeleteLink(old_link
);
1167 static struct alias_link
*
1168 _FindLinkOut(struct in_addr src_addr
,
1169 struct in_addr dst_addr
,
1173 int replace_partial_links
)
1176 struct alias_link
*link
;
1178 i
= StartPointOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
);
1179 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1181 if (link
->src_addr
.s_addr
== src_addr
.s_addr
1182 && link
->server
== NULL
1183 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1184 && link
->dst_port
== dst_port
1185 && link
->src_port
== src_port
1186 && link
->link_type
== link_type
)
1188 link
->timestamp
= timeStamp
;
1193 /* Search for partially specified links. */
1194 if (link
== NULL
&& replace_partial_links
)
1196 if (dst_port
!= 0 && dst_addr
.s_addr
!= INADDR_ANY
)
1198 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, 0,
1201 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
,
1202 dst_port
, link_type
, 0);
1205 (dst_port
!= 0 || dst_addr
.s_addr
!= INADDR_ANY
))
1207 link
= _FindLinkOut(src_addr
, nullAddress
, src_port
, 0,
1213 src_addr
, dst_addr
, link
->alias_addr
,
1214 src_port
, dst_port
, link
->alias_port
,
1222 static struct alias_link
*
1223 FindLinkOut(struct in_addr src_addr
,
1224 struct in_addr dst_addr
,
1228 int replace_partial_links
)
1230 struct alias_link
*link
;
1232 link
= _FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
,
1233 link_type
, replace_partial_links
);
1237 /* The following allows permanent links to be
1238 specified as using the default source address
1239 (i.e. device interface address) without knowing
1240 in advance what that address is. */
1241 if (aliasAddress
.s_addr
!= 0 &&
1242 src_addr
.s_addr
== aliasAddress
.s_addr
)
1244 link
= _FindLinkOut(nullAddress
, dst_addr
, src_port
, dst_port
,
1245 link_type
, replace_partial_links
);
1253 static struct alias_link
*
1254 _FindLinkIn(struct in_addr dst_addr
,
1255 struct in_addr alias_addr
,
1259 int replace_partial_links
)
1263 struct alias_link
*link
;
1264 struct alias_link
*link_fully_specified
;
1265 struct alias_link
*link_unknown_all
;
1266 struct alias_link
*link_unknown_dst_addr
;
1267 struct alias_link
*link_unknown_dst_port
;
1269 /* Initialize pointers */
1270 link_fully_specified
= NULL
;
1271 link_unknown_all
= NULL
;
1272 link_unknown_dst_addr
= NULL
;
1273 link_unknown_dst_port
= NULL
;
1275 /* If either the dest addr or port is unknown, the search
1276 loop will have to know about this. */
1279 if (dst_addr
.s_addr
== INADDR_ANY
)
1280 flags_in
|= LINK_UNKNOWN_DEST_ADDR
;
1282 flags_in
|= LINK_UNKNOWN_DEST_PORT
;
1285 start_point
= StartPointIn(alias_addr
, alias_port
, link_type
);
1286 LIST_FOREACH(link
, &linkTableIn
[start_point
], list_in
)
1290 flags
= flags_in
| link
->flags
;
1291 if (!(flags
& LINK_PARTIALLY_SPECIFIED
))
1293 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1294 && link
->alias_port
== alias_port
1295 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
1296 && link
->dst_port
== dst_port
1297 && link
->link_type
== link_type
)
1299 link_fully_specified
= link
;
1303 else if ((flags
& LINK_UNKNOWN_DEST_ADDR
)
1304 && (flags
& LINK_UNKNOWN_DEST_PORT
))
1306 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1307 && link
->alias_port
== alias_port
1308 && link
->link_type
== link_type
)
1310 if (link_unknown_all
== NULL
)
1311 link_unknown_all
= link
;
1314 else if (flags
& LINK_UNKNOWN_DEST_ADDR
)
1316 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1317 && link
->alias_port
== alias_port
1318 && link
->link_type
== link_type
1319 && link
->dst_port
== dst_port
)
1321 if (link_unknown_dst_addr
== NULL
)
1322 link_unknown_dst_addr
= link
;
1325 else if (flags
& LINK_UNKNOWN_DEST_PORT
)
1327 if (link
->alias_addr
.s_addr
== alias_addr
.s_addr
1328 && link
->alias_port
== alias_port
1329 && link
->link_type
== link_type
1330 && link
->dst_addr
.s_addr
== dst_addr
.s_addr
)
1332 if (link_unknown_dst_port
== NULL
)
1333 link_unknown_dst_port
= link
;
1340 if (link_fully_specified
!= NULL
)
1342 link_fully_specified
->timestamp
= timeStamp
;
1343 link
= link_fully_specified
;
1345 else if (link_unknown_dst_port
!= NULL
)
1346 link
= link_unknown_dst_port
;
1347 else if (link_unknown_dst_addr
!= NULL
)
1348 link
= link_unknown_dst_addr
;
1349 else if (link_unknown_all
!= NULL
)
1350 link
= link_unknown_all
;
1354 if (replace_partial_links
&&
1355 (link
->flags
& LINK_PARTIALLY_SPECIFIED
|| link
->server
!= NULL
))
1357 struct in_addr src_addr
;
1360 if (link
->server
!= NULL
) { /* LSNAT link */
1361 src_addr
= link
->server
->addr
;
1362 src_port
= link
->server
->port
;
1363 link
->server
= link
->server
->next
;
1365 src_addr
= link
->src_addr
;
1366 src_port
= link
->src_port
;
1370 src_addr
, dst_addr
, alias_addr
,
1371 src_port
, dst_port
, alias_port
,
1378 static struct alias_link
*
1379 FindLinkIn(struct in_addr dst_addr
,
1380 struct in_addr alias_addr
,
1384 int replace_partial_links
)
1386 struct alias_link
*link
;
1388 link
= _FindLinkIn(dst_addr
, alias_addr
, dst_port
, alias_port
,
1389 link_type
, replace_partial_links
);
1393 /* The following allows permanent links to be
1394 specified as using the default aliasing address
1395 (i.e. device interface address) without knowing
1396 in advance what that address is. */
1397 if (aliasAddress
.s_addr
!= 0 &&
1398 alias_addr
.s_addr
== aliasAddress
.s_addr
)
1400 link
= _FindLinkIn(dst_addr
, nullAddress
, dst_port
, alias_port
,
1401 link_type
, replace_partial_links
);
1411 /* External routines for finding/adding links
1413 -- "external" means outside alias_db.c, but within alias*.c --
1415 FindIcmpIn(), FindIcmpOut()
1416 FindFragmentIn1(), FindFragmentIn2()
1417 AddFragmentPtrLink(), FindFragmentPtr()
1418 FindProtoIn(), FindProtoOut()
1419 FindUdpTcpIn(), FindUdpTcpOut()
1420 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1421 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1422 FindOriginalAddress(), FindAliasAddress()
1424 (prototypes in alias_local.h)
1429 FindIcmpIn(struct in_addr dst_addr
,
1430 struct in_addr alias_addr
,
1434 struct alias_link
*link
;
1436 link
= FindLinkIn(dst_addr
, alias_addr
,
1437 NO_DEST_PORT
, id_alias
,
1439 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1441 struct in_addr target_addr
;
1443 target_addr
= FindOriginalAddress(alias_addr
);
1444 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1445 id_alias
, NO_DEST_PORT
, id_alias
,
1454 FindIcmpOut(struct in_addr src_addr
,
1455 struct in_addr dst_addr
,
1459 struct alias_link
* link
;
1461 link
= FindLinkOut(src_addr
, dst_addr
,
1464 if (link
== NULL
&& create
)
1466 struct in_addr alias_addr
;
1468 alias_addr
= FindAliasAddress(src_addr
);
1469 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1470 id
, NO_DEST_PORT
, GET_ALIAS_ID
,
1479 FindFragmentIn1(struct in_addr dst_addr
,
1480 struct in_addr alias_addr
,
1483 struct alias_link
*link
;
1485 link
= FindLinkIn(dst_addr
, alias_addr
,
1486 NO_DEST_PORT
, ip_id
,
1487 LINK_FRAGMENT_ID
, 0);
1491 link
= AddLink(nullAddress
, dst_addr
, alias_addr
,
1492 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1501 FindFragmentIn2(struct in_addr dst_addr
, /* Doesn't add a link if one */
1502 struct in_addr alias_addr
, /* is not found. */
1505 return FindLinkIn(dst_addr
, alias_addr
,
1506 NO_DEST_PORT
, ip_id
,
1507 LINK_FRAGMENT_ID
, 0);
1512 AddFragmentPtrLink(struct in_addr dst_addr
,
1515 return AddLink(nullAddress
, dst_addr
, nullAddress
,
1516 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1522 FindFragmentPtr(struct in_addr dst_addr
,
1525 return FindLinkIn(dst_addr
, nullAddress
,
1526 NO_DEST_PORT
, ip_id
,
1527 LINK_FRAGMENT_PTR
, 0);
1532 FindProtoIn(struct in_addr dst_addr
,
1533 struct in_addr alias_addr
,
1536 struct alias_link
*link
;
1538 link
= FindLinkIn(dst_addr
, alias_addr
,
1542 if (link
== NULL
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1544 struct in_addr target_addr
;
1546 target_addr
= FindOriginalAddress(alias_addr
);
1547 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1548 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1557 FindProtoOut(struct in_addr src_addr
,
1558 struct in_addr dst_addr
,
1561 struct alias_link
*link
;
1563 link
= FindLinkOut(src_addr
, dst_addr
,
1564 NO_SRC_PORT
, NO_DEST_PORT
,
1569 struct in_addr alias_addr
;
1571 alias_addr
= FindAliasAddress(src_addr
);
1572 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1573 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1582 FindUdpTcpIn(struct in_addr dst_addr
,
1583 struct in_addr alias_addr
,
1590 struct alias_link
*link
;
1595 link_type
= LINK_UDP
;
1598 link_type
= LINK_TCP
;
1605 link
= FindLinkIn(dst_addr
, alias_addr
,
1606 dst_port
, alias_port
,
1609 if (link
== NULL
&& create
&& !(packetAliasMode
& PKT_ALIAS_DENY_INCOMING
))
1611 struct in_addr target_addr
;
1613 target_addr
= FindOriginalAddress(alias_addr
);
1614 link
= AddLink(target_addr
, dst_addr
, alias_addr
,
1615 alias_port
, dst_port
, alias_port
,
1624 FindUdpTcpOut(struct in_addr src_addr
,
1625 struct in_addr dst_addr
,
1632 struct alias_link
*link
;
1637 link_type
= LINK_UDP
;
1640 link_type
= LINK_TCP
;
1647 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
, create
);
1649 if (link
== NULL
&& create
)
1651 struct in_addr alias_addr
;
1653 alias_addr
= FindAliasAddress(src_addr
);
1654 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1655 src_port
, dst_port
, GET_ALIAS_PORT
,
1664 AddPptp(struct in_addr src_addr
,
1665 struct in_addr dst_addr
,
1666 struct in_addr alias_addr
,
1667 u_int16_t src_call_id
)
1669 struct alias_link
*link
;
1671 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1672 src_call_id
, 0, GET_ALIAS_PORT
,
1680 FindPptpOutByCallId(struct in_addr src_addr
,
1681 struct in_addr dst_addr
,
1682 u_int16_t src_call_id
)
1685 struct alias_link
*link
;
1687 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1688 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1689 if (link
->link_type
== LINK_PPTP
&&
1690 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1691 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1692 link
->src_port
== src_call_id
)
1700 FindPptpOutByPeerCallId(struct in_addr src_addr
,
1701 struct in_addr dst_addr
,
1702 u_int16_t dst_call_id
)
1705 struct alias_link
*link
;
1707 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1708 LIST_FOREACH(link
, &linkTableOut
[i
], list_out
)
1709 if (link
->link_type
== LINK_PPTP
&&
1710 link
->src_addr
.s_addr
== src_addr
.s_addr
&&
1711 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1712 link
->dst_port
== dst_call_id
)
1720 FindPptpInByCallId(struct in_addr dst_addr
,
1721 struct in_addr alias_addr
,
1722 u_int16_t dst_call_id
)
1725 struct alias_link
*link
;
1727 i
= StartPointIn(alias_addr
, 0, LINK_PPTP
);
1728 LIST_FOREACH(link
, &linkTableIn
[i
], list_in
)
1729 if (link
->link_type
== LINK_PPTP
&&
1730 link
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1731 link
->alias_addr
.s_addr
== alias_addr
.s_addr
&&
1732 link
->dst_port
== dst_call_id
)
1740 FindPptpInByPeerCallId(struct in_addr dst_addr
,
1741 struct in_addr alias_addr
,
1742 u_int16_t alias_call_id
)
1744 struct alias_link
*link
;
1746 link
= FindLinkIn(dst_addr
, alias_addr
,
1747 0/* any */, alias_call_id
,
1756 FindRtspOut(struct in_addr src_addr
,
1757 struct in_addr dst_addr
,
1763 struct alias_link
*link
;
1768 link_type
= LINK_UDP
;
1771 link_type
= LINK_TCP
;
1778 link
= FindLinkOut(src_addr
, dst_addr
, src_port
, 0, link_type
, 1);
1782 struct in_addr alias_addr
;
1784 alias_addr
= FindAliasAddress(src_addr
);
1785 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
1786 src_port
, 0, alias_port
,
1795 FindOriginalAddress(struct in_addr alias_addr
)
1797 struct alias_link
*link
;
1799 link
= FindLinkIn(nullAddress
, alias_addr
,
1800 0, 0, LINK_ADDR
, 0);
1804 if (targetAddress
.s_addr
== INADDR_ANY
)
1806 else if (targetAddress
.s_addr
== INADDR_NONE
)
1807 return aliasAddress
;
1809 return targetAddress
;
1813 if (link
->server
!= NULL
) { /* LSNAT link */
1814 struct in_addr src_addr
;
1816 src_addr
= link
->server
->addr
;
1817 link
->server
= link
->server
->next
;
1819 } else if (link
->src_addr
.s_addr
== INADDR_ANY
)
1820 return aliasAddress
;
1822 return link
->src_addr
;
1828 FindAliasAddress(struct in_addr original_addr
)
1830 struct alias_link
*link
;
1832 link
= FindLinkOut(original_addr
, nullAddress
,
1833 0, 0, LINK_ADDR
, 0);
1836 return aliasAddress
;
1840 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1841 return aliasAddress
;
1843 return link
->alias_addr
;
1848 /* External routines for getting or changing link data
1849 (external to alias_db.c, but internal to alias*.c)
1851 SetFragmentData(), GetFragmentData()
1852 SetFragmentPtr(), GetFragmentPtr()
1853 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1854 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1855 GetOriginalPort(), GetAliasPort()
1856 SetAckModified(), GetAckModified()
1857 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1858 SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
1864 SetFragmentAddr(struct alias_link
*link
, struct in_addr src_addr
)
1866 link
->data
.frag_addr
= src_addr
;
1871 GetFragmentAddr(struct alias_link
*link
, struct in_addr
*src_addr
)
1873 *src_addr
= link
->data
.frag_addr
;
1878 SetFragmentPtr(struct alias_link
*link
, char *fptr
)
1880 link
->data
.frag_ptr
= fptr
;
1885 GetFragmentPtr(struct alias_link
*link
, char **fptr
)
1887 *fptr
= link
->data
.frag_ptr
;
1892 SetStateIn(struct alias_link
*link
, int state
)
1894 /* TCP input state */
1896 case ALIAS_TCP_STATE_DISCONNECTED
:
1897 if (link
->data
.tcp
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
1898 link
->expire_time
= TCP_EXPIRE_DEAD
;
1900 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1902 case ALIAS_TCP_STATE_CONNECTED
:
1903 if (link
->data
.tcp
->state
.out
== ALIAS_TCP_STATE_CONNECTED
)
1904 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
1909 link
->data
.tcp
->state
.in
= state
;
1914 SetStateOut(struct alias_link
*link
, int state
)
1916 /* TCP output state */
1918 case ALIAS_TCP_STATE_DISCONNECTED
:
1919 if (link
->data
.tcp
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
)
1920 link
->expire_time
= TCP_EXPIRE_DEAD
;
1922 link
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1924 case ALIAS_TCP_STATE_CONNECTED
:
1925 if (link
->data
.tcp
->state
.in
== ALIAS_TCP_STATE_CONNECTED
)
1926 link
->expire_time
= TCP_EXPIRE_CONNECTED
;
1931 link
->data
.tcp
->state
.out
= state
;
1936 GetStateIn(struct alias_link
*link
)
1938 /* TCP input state */
1939 return link
->data
.tcp
->state
.in
;
1944 GetStateOut(struct alias_link
*link
)
1946 /* TCP output state */
1947 return link
->data
.tcp
->state
.out
;
1952 GetOriginalAddress(struct alias_link
*link
)
1954 if (link
->src_addr
.s_addr
== INADDR_ANY
)
1955 return aliasAddress
;
1957 return(link
->src_addr
);
1962 GetDestAddress(struct alias_link
*link
)
1964 return(link
->dst_addr
);
1969 GetAliasAddress(struct alias_link
*link
)
1971 if (link
->alias_addr
.s_addr
== INADDR_ANY
)
1972 return aliasAddress
;
1974 return link
->alias_addr
;
1979 GetDefaultAliasAddress()
1981 return aliasAddress
;
1986 SetDefaultAliasAddress(struct in_addr alias_addr
)
1988 aliasAddress
= alias_addr
;
1993 GetOriginalPort(struct alias_link
*link
)
1995 return(link
->src_port
);
2000 GetAliasPort(struct alias_link
*link
)
2002 return(link
->alias_port
);
2007 GetDestPort(struct alias_link
*link
)
2009 return(link
->dst_port
);
2014 SetAckModified(struct alias_link
*link
)
2016 /* Indicate that ACK numbers have been modified in a TCP connection */
2017 link
->data
.tcp
->state
.ack_modified
= 1;
2022 GetProxyAddress(struct alias_link
*link
)
2024 return link
->proxy_addr
;
2029 SetProxyAddress(struct alias_link
*link
, struct in_addr addr
)
2031 link
->proxy_addr
= addr
;
2036 GetProxyPort(struct alias_link
*link
)
2038 return link
->proxy_port
;
2043 SetProxyPort(struct alias_link
*link
, u_short port
)
2045 link
->proxy_port
= port
;
2050 GetAckModified(struct alias_link
*link
)
2052 /* See if ACK numbers have been modified */
2053 return link
->data
.tcp
->state
.ack_modified
;
2058 GetDeltaAckIn(struct ip
*pip
, struct alias_link
*link
)
2061 Find out how much the ACK number has been altered for an incoming
2062 TCP packet. To do this, a circular list of ACK numbers where the TCP
2063 packet size was altered is searched.
2068 int delta
, ack_diff_min
;
2071 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2076 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2078 struct ack_data_record x
;
2080 x
= link
->data
.tcp
->ack
[i
];
2085 ack_diff
= SeqDiff(x
.ack_new
, ack
);
2088 if (ack_diff_min
>= 0)
2090 if (ack_diff
< ack_diff_min
)
2093 ack_diff_min
= ack_diff
;
2099 ack_diff_min
= ack_diff
;
2109 GetDeltaSeqOut(struct ip
*pip
, struct alias_link
*link
)
2112 Find out how much the sequence number has been altered for an outgoing
2113 TCP packet. To do this, a circular list of ACK numbers where the TCP
2114 packet size was altered is searched.
2119 int delta
, seq_diff_min
;
2122 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2127 for (i
=0; i
<N_LINK_TCP_DATA
; i
++)
2129 struct ack_data_record x
;
2131 x
= link
->data
.tcp
->ack
[i
];
2136 seq_diff
= SeqDiff(x
.ack_old
, seq
);
2139 if (seq_diff_min
>= 0)
2141 if (seq_diff
< seq_diff_min
)
2144 seq_diff_min
= seq_diff
;
2150 seq_diff_min
= seq_diff
;
2160 AddSeq(struct ip
*pip
, struct alias_link
*link
, int delta
)
2163 When a TCP packet has been altered in length, save this
2164 information in a circular list. If enough packets have
2165 been altered, then this list will begin to overwrite itself.
2169 struct ack_data_record x
;
2170 int hlen
, tlen
, dlen
;
2173 tc
= (struct tcphdr
*) ((char *) pip
+ (pip
->ip_hl
<< 2));
2175 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
2176 tlen
= ntohs(pip
->ip_len
);
2179 x
.ack_old
= htonl(ntohl(tc
->th_seq
) + dlen
);
2180 x
.ack_new
= htonl(ntohl(tc
->th_seq
) + dlen
+ delta
);
2184 i
= link
->data
.tcp
->state
.index
;
2185 link
->data
.tcp
->ack
[i
] = x
;
2188 if (i
== N_LINK_TCP_DATA
)
2189 link
->data
.tcp
->state
.index
= 0;
2191 link
->data
.tcp
->state
.index
= i
;
2195 SetExpire(struct alias_link
*link
, int expire
)
2199 link
->flags
&= ~LINK_PERMANENT
;
2202 else if (expire
== -1)
2204 link
->flags
|= LINK_PERMANENT
;
2206 else if (expire
> 0)
2208 link
->expire_time
= expire
;
2213 fprintf(stderr
, "PacketAlias/SetExpire(): ");
2214 fprintf(stderr
, "error in expire parameter\n");
2220 ClearCheckNewLink(void)
2226 SetLastLineCrlfTermed(struct alias_link
*link
, int yes
)
2230 link
->flags
|= LINK_LAST_LINE_CRLF_TERMED
;
2232 link
->flags
&= ~LINK_LAST_LINE_CRLF_TERMED
;
2236 GetLastLineCrlfTermed(struct alias_link
*link
)
2239 return (link
->flags
& LINK_LAST_LINE_CRLF_TERMED
);
2243 SetDestCallId(struct alias_link
*link
, u_int16_t cid
)
2247 link
= ReLink(link
, link
->src_addr
, link
->dst_addr
, link
->alias_addr
,
2248 link
->src_port
, cid
, link
->alias_port
, link
->link_type
);
2253 /* Miscellaneous Functions
2256 InitPacketAliasLog()
2257 UninitPacketAliasLog()
2261 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2262 is called to find and remove timed-out aliasing links. Logic exists
2263 to sweep through the entire table and linked list structure
2266 (prototype in alias_local.h)
2277 * Save system time (seconds) in global variable timeStamp for
2278 * use by other functions. This is done so as not to unnecessarily
2279 * waste timeline by making system calls.
2281 gettimeofday(&tv
, &tz
);
2282 timeStamp
= tv
.tv_sec
;
2284 /* Compute number of spokes (output table link chains) to cover */
2285 n100
= LINK_TABLE_OUT_SIZE
* 100 + houseKeepingResidual
;
2286 n100
*= timeStamp
- lastCleanupTime
;
2287 n100
/= ALIAS_CLEANUP_INTERVAL_SECS
;
2291 /* Handle different cases */
2292 if (n
> ALIAS_CLEANUP_MAX_SPOKES
)
2294 n
= ALIAS_CLEANUP_MAX_SPOKES
;
2295 lastCleanupTime
= timeStamp
;
2296 houseKeepingResidual
= 0;
2299 IncrementalCleanup();
2303 lastCleanupTime
= timeStamp
;
2304 houseKeepingResidual
= n100
- 100*n
;
2307 IncrementalCleanup();
2312 fprintf(stderr
, "PacketAlias/HouseKeeping(): ");
2313 fprintf(stderr
, "something unexpected in time values\n");
2315 lastCleanupTime
= timeStamp
;
2316 houseKeepingResidual
= 0;
2321 /* Init the log file and enable logging */
2323 InitPacketAliasLog(void)
2325 if ((~packetAliasMode
& PKT_ALIAS_LOG
)
2326 && (monitorFile
= fopen("/var/log/alias.log", "w")))
2328 packetAliasMode
|= PKT_ALIAS_LOG
;
2329 fprintf(monitorFile
,
2330 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2335 /* Close the log-file and disable logging. */
2337 UninitPacketAliasLog(void)
2340 fclose(monitorFile
);
2343 packetAliasMode
&= ~PKT_ALIAS_LOG
;
2351 /* Outside world interfaces
2353 -- "outside world" means other than alias*.c routines --
2355 PacketAliasRedirectPort()
2356 PacketAliasAddServer()
2357 PacketAliasRedirectProto()
2358 PacketAliasRedirectAddr()
2359 PacketAliasRedirectDelete()
2360 PacketAliasSetAddress()
2363 PacketAliasSetMode()
2365 (prototypes in alias.h)
2368 /* Redirection from a specific public addr:port to a
2369 private addr:port */
2371 PacketAliasRedirectPort(struct in_addr src_addr
, u_short src_port
,
2372 struct in_addr dst_addr
, u_short dst_port
,
2373 struct in_addr alias_addr
, u_short alias_port
,
2377 struct alias_link
*link
;
2382 link_type
= LINK_UDP
;
2385 link_type
= LINK_TCP
;
2389 fprintf(stderr
, "PacketAliasRedirectPort(): ");
2390 fprintf(stderr
, "only TCP and UDP protocols allowed\n");
2395 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2396 src_port
, dst_port
, alias_port
,
2401 link
->flags
|= LINK_PERMANENT
;
2406 fprintf(stderr
, "PacketAliasRedirectPort(): "
2407 "call to AddLink() failed\n");
2414 /* Add server to the pool of servers */
2416 PacketAliasAddServer(struct alias_link
*link
, struct in_addr addr
, u_short port
)
2418 struct server
*server
;
2420 server
= malloc(sizeof(struct server
));
2422 if (server
!= NULL
) {
2423 struct server
*head
;
2425 server
->addr
= addr
;
2426 server
->port
= port
;
2428 head
= link
->server
;
2430 server
->next
= server
;
2434 for (s
= head
; s
->next
!= head
; s
= s
->next
);
2436 server
->next
= head
;
2438 link
->server
= server
;
2444 /* Redirect packets of a given IP protocol from a specific
2445 public address to a private address */
2447 PacketAliasRedirectProto(struct in_addr src_addr
,
2448 struct in_addr dst_addr
,
2449 struct in_addr alias_addr
,
2452 struct alias_link
*link
;
2454 link
= AddLink(src_addr
, dst_addr
, alias_addr
,
2455 NO_SRC_PORT
, NO_DEST_PORT
, 0,
2460 link
->flags
|= LINK_PERMANENT
;
2465 fprintf(stderr
, "PacketAliasRedirectProto(): "
2466 "call to AddLink() failed\n");
2473 /* Static address translation */
2475 PacketAliasRedirectAddr(struct in_addr src_addr
,
2476 struct in_addr alias_addr
)
2478 struct alias_link
*link
;
2480 link
= AddLink(src_addr
, nullAddress
, alias_addr
,
2486 link
->flags
|= LINK_PERMANENT
;
2491 fprintf(stderr
, "PacketAliasRedirectAddr(): "
2492 "call to AddLink() failed\n");
2501 PacketAliasRedirectDelete(struct alias_link
*link
)
2503 /* This is a dangerous function to put in the API,
2504 because an invalid pointer can crash the program. */
2513 PacketAliasSetAddress(struct in_addr addr
)
2515 if (packetAliasMode
& PKT_ALIAS_RESET_ON_ADDR_CHANGE
2516 && aliasAddress
.s_addr
!= addr
.s_addr
)
2519 aliasAddress
= addr
;
2524 PacketAliasSetTarget(struct in_addr target_addr
)
2526 targetAddress
= target_addr
;
2531 PacketAliasInit(void)
2536 static int firstCall
= 1;
2540 gettimeofday(&tv
, &tz
);
2541 timeStamp
= tv
.tv_sec
;
2542 lastCleanupTime
= tv
.tv_sec
;
2543 houseKeepingResidual
= 0;
2545 for (i
=0; i
<LINK_TABLE_OUT_SIZE
; i
++)
2546 LIST_INIT(&linkTableOut
[i
]);
2547 for (i
=0; i
<LINK_TABLE_IN_SIZE
; i
++)
2548 LIST_INIT(&linkTableIn
[i
]);
2550 atexit(PacketAliasUninit
);
2560 aliasAddress
.s_addr
= INADDR_ANY
;
2561 targetAddress
.s_addr
= INADDR_ANY
;
2568 fragmentIdLinkCount
= 0;
2569 fragmentPtrLinkCount
= 0;
2574 packetAliasMode
= PKT_ALIAS_SAME_PORTS
2575 | PKT_ALIAS_USE_SOCKETS
2576 | PKT_ALIAS_RESET_ON_ADDR_CHANGE
;
2580 PacketAliasUninit(void) {
2584 UninitPacketAliasLog();
2591 /* Change mode for some operations */
2594 unsigned int flags
, /* Which state to bring flags to */
2595 unsigned int mask
/* Mask of which flags to affect (use 0 to do a
2596 probe for flag values) */
2599 /* Enable logging? */
2600 if (flags
& mask
& PKT_ALIAS_LOG
)
2602 InitPacketAliasLog(); /* Do the enable */
2604 /* _Disable_ logging? */
2605 if (~flags
& mask
& PKT_ALIAS_LOG
) {
2606 UninitPacketAliasLog();
2610 /* Start punching holes in the firewall? */
2611 if (flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2614 /* Stop punching holes in the firewall? */
2615 if (~flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2620 /* Other flags can be set/cleared without special action */
2621 packetAliasMode
= (flags
& mask
) | (packetAliasMode
& ~mask
);
2622 return packetAliasMode
;
2627 PacketAliasCheckNewLink(void)
2629 return newDefaultLink
;
2636 Code to support firewall punching. This shouldn't really be in this
2637 file, but making variables global is evil too.
2640 /* Firewall include files */
2642 #include <net/ipfw/ip_fw.h>
2647 * helper function, updates the pointer to cmd with the length
2648 * of the current command, and also cleans up the first word of
2649 * the new command in case it has been clobbered before.
2652 next_cmd(ipfw_insn
*cmd
)
2655 bzero(cmd
, sizeof(*cmd
));
2660 * A function to fill simple commands of size 1.
2661 * Existing flags are preserved.
2664 fill_cmd(ipfw_insn
*cmd
, enum ipfw_opcodes opcode
, int size
,
2665 int flags
, u_int16_t arg
)
2667 cmd
->opcode
= opcode
;
2668 cmd
->len
= ((cmd
->len
| flags
) & (F_NOT
| F_OR
)) | (size
& F_LEN_MASK
);
2670 return next_cmd(cmd
);
2674 fill_ip(ipfw_insn
*cmd1
, enum ipfw_opcodes opcode
, u_int32_t addr
)
2676 ipfw_insn_ip
*cmd
= (ipfw_insn_ip
*)cmd1
;
2678 cmd
->addr
.s_addr
= addr
;
2679 return fill_cmd(cmd1
, opcode
, F_INSN_SIZE(ipfw_insn_u32
), 0, 0);
2683 fill_one_port(ipfw_insn
*cmd1
, enum ipfw_opcodes opcode
, u_int16_t port
)
2685 ipfw_insn_u16
*cmd
= (ipfw_insn_u16
*)cmd1
;
2687 cmd
->ports
[0] = cmd
->ports
[1] = port
;
2688 return fill_cmd(cmd1
, opcode
, F_INSN_SIZE(ipfw_insn_u16
), 0, 0);
2692 fill_rule(void *buf
, int bufsize
, int rulenum
,
2693 enum ipfw_opcodes action
, int proto
,
2694 struct in_addr sa
, u_int16_t sp
, struct in_addr da
, u_int16_t dp
)
2696 struct ipfw_ioc_rule
*rule
= buf
;
2697 ipfw_insn
*cmd
= (ipfw_insn
*)rule
->cmd
;
2699 bzero(buf
, bufsize
);
2700 rule
->rulenum
= rulenum
;
2702 cmd
= fill_cmd(cmd
, O_PROTO
, F_INSN_SIZE(ipfw_insn
), 0, proto
);
2703 cmd
= fill_ip(cmd
, O_IP_SRC
, sa
.s_addr
);
2704 cmd
= fill_one_port(cmd
, O_IP_SRCPORT
, sp
);
2705 cmd
= fill_ip(cmd
, O_IP_DST
, da
.s_addr
);
2706 cmd
= fill_one_port(cmd
, O_IP_DSTPORT
, dp
);
2708 rule
->act_ofs
= (u_int32_t
*)cmd
- (u_int32_t
*)rule
->cmd
;
2709 cmd
= fill_cmd(cmd
, action
, F_INSN_SIZE(ipfw_insn
), 0, 0);
2711 rule
->cmd_len
= (u_int32_t
*)cmd
- (u_int32_t
*)rule
->cmd
;
2713 return ((void *)cmd
- buf
);
2716 static void ClearAllFWHoles(void);
2718 static int fireWallBaseNum
; /* The first firewall entry free for our use */
2719 static int fireWallNumNums
; /* How many entries can we use? */
2720 static int fireWallActiveNum
; /* Which entry did we last use? */
2721 static char *fireWallField
; /* bool array for entries */
2723 #define fw_setfield(field, num) \
2725 (field)[(num) - fireWallBaseNum] = 1; \
2726 } /*lint -save -e717 */ while(0) /*lint -restore */
2727 #define fw_clrfield(field, num) \
2729 (field)[(num) - fireWallBaseNum] = 0; \
2730 } /*lint -save -e717 */ while(0) /*lint -restore */
2731 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2735 fireWallField
= malloc(fireWallNumNums
);
2736 if (fireWallField
) {
2737 memset(fireWallField
, 0, fireWallNumNums
);
2738 if (fireWallFD
< 0) {
2739 fireWallFD
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2742 fireWallActiveNum
= fireWallBaseNum
;
2747 UninitPunchFW(void) {
2749 if (fireWallFD
>= 0)
2753 free(fireWallField
);
2754 fireWallField
= NULL
;
2755 packetAliasMode
&= ~PKT_ALIAS_PUNCH_FW
;
2758 /* Make a certain link go through the firewall */
2760 PunchFWHole(struct alias_link
*link
) {
2761 int r
; /* Result code */
2762 int fwhole
; /* Where to punch hole */
2764 /* Don't do anything unless we are asked to */
2765 if ( !(packetAliasMode
& PKT_ALIAS_PUNCH_FW
) ||
2767 link
->link_type
!= LINK_TCP
)
2772 /* Find empty slot */
2773 for (fwhole
= fireWallActiveNum
;
2774 fwhole
< fireWallBaseNum
+ fireWallNumNums
&&
2775 fw_tstfield(fireWallField
, fwhole
);
2778 if (fwhole
== fireWallBaseNum
+ fireWallNumNums
) {
2779 for (fwhole
= fireWallBaseNum
;
2780 fwhole
< fireWallActiveNum
&&
2781 fw_tstfield(fireWallField
, fwhole
);
2784 if (fwhole
== fireWallActiveNum
) {
2785 /* No rule point empty - we can't punch more holes. */
2786 fireWallActiveNum
= fireWallBaseNum
;
2788 fprintf(stderr
, "libalias: Unable to create firewall hole!\n");
2793 /* Start next search at next position */
2794 fireWallActiveNum
= fwhole
+1;
2797 * generate two rules of the form
2799 * add fwhole accept tcp from OAddr OPort to DAddr DPort
2800 * add fwhole accept tcp from DAddr DPort to OAddr OPort
2802 if (GetOriginalPort(link
) != 0 && GetDestPort(link
) != 0) {
2803 u_int32_t rulebuf
[IPFW_RULE_SIZE_MAX
];
2806 i
= fill_rule(rulebuf
, sizeof(rulebuf
), fwhole
,
2807 O_ACCEPT
, IPPROTO_TCP
,
2808 GetOriginalAddress(link
), ntohs(GetOriginalPort(link
)),
2809 GetDestAddress(link
), ntohs(GetDestPort(link
)) );
2810 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, rulebuf
, i
);
2812 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2814 i
= fill_rule(rulebuf
, sizeof(rulebuf
), fwhole
,
2815 O_ACCEPT
, IPPROTO_TCP
,
2816 GetDestAddress(link
), ntohs(GetDestPort(link
)),
2817 GetOriginalAddress(link
), ntohs(GetOriginalPort(link
)) );
2818 r
= setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, rulebuf
, i
);
2820 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2822 /* Indicate hole applied */
2823 link
->data
.tcp
->fwhole
= fwhole
;
2824 fw_setfield(fireWallField
, fwhole
);
2827 /* Remove a hole in a firewall associated with a particular alias
2828 link. Calling this too often is harmless. */
2830 ClearFWHole(struct alias_link
*link
) {
2831 if (link
->link_type
== LINK_TCP
) {
2832 int fwhole
= link
->data
.tcp
->fwhole
; /* Where is the firewall hole? */
2837 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
,
2838 &fwhole
, sizeof fwhole
))
2840 fw_clrfield(fireWallField
, fwhole
);
2841 link
->data
.tcp
->fwhole
= -1;
2845 /* Clear out the entire range dedicated to firewall holes. */
2847 ClearAllFWHoles(void) {
2853 for (i
= fireWallBaseNum
; i
< fireWallBaseNum
+ fireWallNumNums
; i
++) {
2855 while (!setsockopt(fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &r
, sizeof r
))
2858 memset(fireWallField
, 0, fireWallNumNums
);
2863 PacketAliasSetFWBase(unsigned int base
, unsigned int num
) {
2865 fireWallBaseNum
= base
;
2866 fireWallNumNums
= num
;