2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: src/sys/netinet/libalias/alias_db.c,v 1.71.2.2.2.1 2008/11/25 02:59:29 kensmith Exp $");
31 Alias_db.c encapsulates all data structures used for storing
32 packet aliasing data. Other parts of the aliasing software
33 access data through functions provided in this file.
35 Data storage is based on the notion of a "link", which is
36 established for ICMP echo/reply packets, UDP datagrams and
37 TCP stream connections. A link stores the original source
38 and destination addresses. For UDP and TCP, it also stores
39 source and destination port numbers, as well as an alias
40 port number. Links are also used to store information about
43 There is a facility for sweeping through and deleting old
44 links as new packets are sent through. A simple timeout is
45 used for ICMP and UDP links. TCP links are left alone unless
46 there is an incomplete connection, in which case the link
47 can be deleted after a certain amount of time.
50 Initial version: August, 1996 (cjm)
52 Version 1.4: September 16, 1996 (cjm)
53 Facility for handling incoming links added.
55 Version 1.6: September 18, 1996 (cjm)
56 ICMP data handling simplified.
58 Version 1.7: January 9, 1997 (cjm)
59 Fragment handling simplified.
60 Saves pointers for unresolved fragments.
61 Permits links for unspecified remote ports
62 or unspecified remote addresses.
63 Fixed bug which did not properly zero port
64 table entries after a link was deleted.
65 Cleaned up some obsolete comments.
67 Version 1.8: January 14, 1997 (cjm)
68 Fixed data type error in StartPoint().
69 (This error did not exist prior to v1.7
70 and was discovered and fixed by Ari Suutari)
72 Version 1.9: February 1, 1997
73 Optionally, connections initiated from packet aliasing host
74 machine will will not have their port number aliased unless it
75 conflicts with an aliasing port already being used. (cjm)
77 All options earlier being #ifdef'ed are now available through
78 a new interface, SetPacketAliasMode(). This allows run time
79 control (which is now available in PPP+pktAlias through the
80 'alias' keyword). (ee)
82 Added ability to create an alias port without
83 either destination address or port specified.
84 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
86 Removed K&R style function headers
87 and general cleanup. (ee)
89 Added packetAliasMode to replace compiler #defines's (ee)
91 Allocates sockets for partially specified
92 ports if ALIAS_USE_SOCKETS defined. (cjm)
94 Version 2.0: March, 1997
95 SetAliasAddress() will now clean up alias links
96 if the aliasing address is changed. (cjm)
98 PacketAliasPermanentLink() function added to support permanent
99 links. (J. Fortes suggested the need for this.)
102 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
104 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
107 These permanent links allow for incoming connections to
108 machines on the local network. They can be given with a
109 user-chosen amount of specificity, with increasing specificity
110 meaning more security. (cjm)
112 Quite a bit of rework to the basic engine. The portTable[]
113 array, which kept track of which ports were in use was replaced
114 by a table/linked list structure. (cjm)
116 SetExpire() function added. (cjm)
118 DeleteLink() no longer frees memory association with a pointer
119 to a fragment (this bug was first recognized by E. Eklund in
122 Version 2.1: May, 1997 (cjm)
123 Packet aliasing engine reworked so that it can handle
124 multiple external addresses rather than just a single
127 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
128 added to the API. The first function is a more generalized
129 version of PacketAliasPermanentLink(). The second function
130 implements static network address translation.
132 Version 3.2: July, 2000 (salander and satoh)
133 Added FindNewPortGroup to get contiguous range of port values.
135 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
136 link but not actually add one.
138 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
139 except that the alias port (from FindNewPortGroup) is provided
142 See HISTORY file for additional revisions.
146 #include <sys/param.h>
147 #include <sys/kernel.h>
148 #include <sys/module.h>
149 #include <sys/syslog.h>
150 #include <sys/queue.h>
155 #include <sys/errno.h>
156 #include <sys/time.h>
160 #include <sys/socket.h>
161 #include <netinet/tcp.h>
164 #include "alias_local.h"
165 #include "alias_mod.h"
168 static LIST_HEAD(, libalias
) instancehead
= LIST_HEAD_INITIALIZER(instancehead
);
172 Constants (note: constants are also defined
173 near relevant functions or structs)
176 /* Parameters used for cleanup of expired links */
177 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
178 #define ALIAS_CLEANUP_INTERVAL_SECS 64
179 #define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
181 /* Timeouts (in seconds) for different link types */
182 #define ICMP_EXPIRE_TIME 60
183 #define UDP_EXPIRE_TIME 60
184 #define PROTO_EXPIRE_TIME 60
185 #define FRAGMENT_ID_EXPIRE_TIME 10
186 #define FRAGMENT_PTR_EXPIRE_TIME 30
188 /* TCP link expire time for different cases */
189 /* When the link has been used and closed - minimal grace time to
190 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
191 #ifndef TCP_EXPIRE_DEAD
192 #define TCP_EXPIRE_DEAD 10
195 /* When the link has been used and closed on one side - the other side
196 is allowed to still send data */
197 #ifndef TCP_EXPIRE_SINGLEDEAD
198 #define TCP_EXPIRE_SINGLEDEAD 90
201 /* When the link isn't yet up */
202 #ifndef TCP_EXPIRE_INITIAL
203 #define TCP_EXPIRE_INITIAL 300
206 /* When the link is up */
207 #ifndef TCP_EXPIRE_CONNECTED
208 #define TCP_EXPIRE_CONNECTED 86400
212 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
213 These constants can be anything except zero, which indicates an
214 unknown port number. */
216 #define NO_DEST_PORT 1
217 #define NO_SRC_PORT 1
222 The fundamental data structure used in this program is
223 "struct alias_link". Whenever a TCP connection is made,
224 a UDP datagram is sent out, or an ICMP echo request is made,
225 a link record is made (if it has not already been created).
226 The link record is identified by the source address/port
227 and the destination address/port. In the case of an ICMP
228 echo request, the source port is treated as being equivalent
229 with the 16-bit ID number of the ICMP packet.
231 The link record also can store some auxiliary data. For
232 TCP connections that have had sequence and acknowledgment
233 modifications, data space is available to track these changes.
234 A state field is used to keep track in changes to the TCP
235 connection state. ID numbers of fragments can also be
236 stored in the auxiliary space. Pointers to unresolved
237 fragments can also be stored.
239 The link records support two independent chainings. Lookup
240 tables for input and out tables hold the initial pointers
241 the link chains. On input, the lookup table indexes on alias
242 port and link type. On output, the lookup table indexes on
243 source address, destination address, source port, destination
247 struct ack_data_record
{ /* used to save changes to ACK/sequence
255 struct tcp_state
{ /* Information about TCP connection */
256 int in
; /* State for outside -> inside */
257 int out
; /* State for inside -> outside */
258 int index
; /* Index to ACK data array */
259 int ack_modified
; /* Indicates whether ACK and
260 * sequence numbers */
264 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
265 * saved for a modified TCP stream */
267 struct tcp_state state
;
268 struct ack_data_record ack
[N_LINK_TCP_DATA
];
269 int fwhole
; /* Which firewall record is used for this
273 struct server
{ /* LSNAT server pool (circular list) */
279 struct alias_link
{ /* Main data structure */
281 struct in_addr src_addr
; /* Address and port information */
282 struct in_addr dst_addr
;
283 struct in_addr alias_addr
;
284 struct in_addr proxy_addr
;
289 struct server
*server
;
291 int link_type
; /* Type of link: TCP, UDP, ICMP,
294 /* values for link_type */
295 #define LINK_ICMP IPPROTO_ICMP
296 #define LINK_UDP IPPROTO_UDP
297 #define LINK_TCP IPPROTO_TCP
298 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
299 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
300 #define LINK_ADDR (IPPROTO_MAX + 3)
301 #define LINK_PPTP (IPPROTO_MAX + 4)
303 int flags
; /* indicates special characteristics */
304 int pflags
; /* protocol-specific flags */
307 #define LINK_UNKNOWN_DEST_PORT 0x01
308 #define LINK_UNKNOWN_DEST_ADDR 0x02
309 #define LINK_PERMANENT 0x04
310 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
311 #define LINK_UNFIREWALLED 0x08
313 int timestamp
; /* Time link was last accessed */
314 int expire_time
; /* Expire time for link */
315 #ifndef NO_USE_SOCKETS
316 int sockfd
; /* socket descriptor */
318 LIST_ENTRY (alias_link
) list_out
; /* Linked list of
320 LIST_ENTRY (alias_link
) list_in
; /* input and output
323 union { /* Auxiliary data */
325 struct in_addr frag_addr
;
330 /* Clean up procedure. */
331 static void finishoff(void);
333 /* Kernel module definition. */
335 MALLOC_DEFINE(M_ALIAS
, "libalias", "packet aliasing");
337 MODULE_VERSION(libalias
, 1);
340 alias_mod_handler(module_t mod
, int type
, void *data
)
347 handler_chain_init();
350 handler_chain_destroy();
361 static moduledata_t alias_mod
= {
362 "alias", alias_mod_handler
, NULL
365 DECLARE_MODULE(alias
, alias_mod
, SI_SUB_DRIVERS
, SI_ORDER_SECOND
);
368 /* Internal utility routines (used only in alias_db.c)
370 Lookup table starting points:
371 StartPointIn() -- link table initial search point for
373 StartPointOut() -- link table initial search point for
377 SeqDiff() -- difference between two TCP sequences
378 ShowAliasStats() -- send alias statistics to a monitor file
382 /* Local prototypes */
383 static u_int
StartPointIn(struct in_addr
, u_short
, int);
386 StartPointOut(struct in_addr
, struct in_addr
,
387 u_short
, u_short
, int);
389 static int SeqDiff(u_long
, u_long
);
392 /* Firewall control */
393 static void InitPunchFW(struct libalias
*);
394 static void UninitPunchFW(struct libalias
*);
395 static void ClearFWHole(struct alias_link
*);
399 /* Log file control */
400 static void ShowAliasStats(struct libalias
*);
401 static int InitPacketAliasLog(struct libalias
*);
402 static void UninitPacketAliasLog(struct libalias
*);
405 StartPointIn(struct in_addr alias_addr
,
411 n
= alias_addr
.s_addr
;
412 if (link_type
!= LINK_PPTP
)
415 return (n
% LINK_TABLE_IN_SIZE
);
420 StartPointOut(struct in_addr src_addr
, struct in_addr dst_addr
,
421 u_short src_port
, u_short dst_port
, int link_type
)
426 n
+= dst_addr
.s_addr
;
427 if (link_type
!= LINK_PPTP
) {
433 return (n
% LINK_TABLE_OUT_SIZE
);
438 SeqDiff(u_long x
, u_long y
)
440 /* Return the difference between two TCP sequence numbers */
443 This function is encapsulated in case there are any unusual
444 arithmetic conditions that need to be considered.
447 return (ntohl(y
) - ntohl(x
));
453 AliasLog(char *str
, const char *format
, ...)
457 va_start(ap
, format
);
458 kvsnprintf(str
, LIBALIAS_BUF_SIZE
, format
, ap
);
463 AliasLog(FILE *stream
, const char *format
, ...)
467 va_start(ap
, format
);
468 vfprintf(stream
, format
, ap
);
475 ShowAliasStats(struct libalias
*la
)
478 LIBALIAS_LOCK_ASSERT(la
);
479 /* Used for debugging */
481 int tot
= la
->icmpLinkCount
+ la
->udpLinkCount
+
482 la
->tcpLinkCount
+ la
->pptpLinkCount
+
483 la
->protoLinkCount
+ la
->fragmentIdLinkCount
+
484 la
->fragmentPtrLinkCount
;
486 AliasLog(la
->logDesc
,
487 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
493 la
->fragmentIdLinkCount
,
494 la
->fragmentPtrLinkCount
, tot
);
496 AliasLog(la
->logDesc
, " (sock=%u)\n", la
->sockCount
);
501 /* Internal routines for finding, deleting and adding links
504 GetNewPort() -- find and reserve new alias port number
505 GetSocket() -- try to allocate a socket for a given port
507 Link creation and deletion:
508 CleanupAliasData() - remove all link chains from lookup table
509 IncrementalCleanup() - look for stale links in a single chain
510 DeleteLink() - remove link
512 ReLink() - change link
515 FindLinkOut() - find link for outgoing packets
516 FindLinkIn() - find link for incoming packets
519 FindNewPortGroup() - find an available group of ports
522 /* Local prototypes */
523 static int GetNewPort(struct libalias
*, struct alias_link
*, int);
524 #ifndef NO_USE_SOCKETS
525 static u_short
GetSocket(struct libalias
*, u_short
, int *, int);
527 static void CleanupAliasData(struct libalias
*);
529 static void IncrementalCleanup(struct libalias
*);
531 static void DeleteLink(struct alias_link
*);
533 static struct alias_link
*
534 AddLink(struct libalias
*, struct in_addr
, struct in_addr
, struct in_addr
,
535 u_short
, u_short
, int, int);
537 static struct alias_link
*
538 ReLink(struct alias_link
*,
539 struct in_addr
, struct in_addr
, struct in_addr
,
540 u_short
, u_short
, int, int);
542 static struct alias_link
*
543 FindLinkOut (struct libalias
*, struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
545 static struct alias_link
*
546 FindLinkIn (struct libalias
*, struct in_addr
, struct in_addr
, u_short
, u_short
, int, int);
549 #define ALIAS_PORT_BASE 0x08000
550 #define ALIAS_PORT_MASK 0x07fff
551 #define ALIAS_PORT_MASK_EVEN 0x07ffe
552 #define GET_NEW_PORT_MAX_ATTEMPTS 20
554 #define GET_ALIAS_PORT -1
555 #define GET_ALIAS_ID GET_ALIAS_PORT
557 #define FIND_EVEN_ALIAS_BASE 1
559 /* GetNewPort() allocates port numbers. Note that if a port number
560 is already in use, that does not mean that it cannot be used by
561 another link concurrently. This is because GetNewPort() looks for
562 unused triplets: (dest addr, dest port, alias port). */
565 GetNewPort(struct libalias
*la
, struct alias_link
*lnk
, int alias_port_param
)
572 LIBALIAS_LOCK_ASSERT(la
);
574 Description of alias_port_param for GetNewPort(). When
575 this parameter is zero or positive, it precisely specifies
576 the port number. GetNewPort() will return this number
577 without check that it is in use.
579 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
580 selected port number.
583 if (alias_port_param
== GET_ALIAS_PORT
) {
585 * The aliasing port is automatically selected by one of
588 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
590 if (la
->packetAliasMode
& PKT_ALIAS_SAME_PORTS
) {
592 * When the PKT_ALIAS_SAME_PORTS option is chosen,
593 * the first try will be the actual source port. If
594 * this is already in use, the remainder of the
595 * trials will be random.
597 port_net
= lnk
->src_port
;
598 port_sys
= ntohs(port_net
);
600 /* First trial and all subsequent are random. */
601 port_sys
= krandom() & ALIAS_PORT_MASK
;
602 port_sys
+= ALIAS_PORT_BASE
;
603 port_net
= htons(port_sys
);
605 } else if (alias_port_param
>= 0 && alias_port_param
< 0x10000) {
606 lnk
->alias_port
= (u_short
) alias_port_param
;
609 #ifdef LIBALIAS_DEBUG
610 fprintf(stderr
, "PacketAlias/GetNewPort(): ");
611 fprintf(stderr
, "input parameter error\n");
617 /* Port number search */
618 for (i
= 0; i
< max_trials
; i
++) {
620 struct alias_link
*search_result
;
622 search_result
= FindLinkIn(la
, lnk
->dst_addr
, lnk
->alias_addr
,
623 lnk
->dst_port
, port_net
,
626 if (search_result
== NULL
)
628 else if (!(lnk
->flags
& LINK_PARTIALLY_SPECIFIED
)
629 && (search_result
->flags
& LINK_PARTIALLY_SPECIFIED
))
635 #ifndef NO_USE_SOCKETS
636 if ((la
->packetAliasMode
& PKT_ALIAS_USE_SOCKETS
)
637 && (lnk
->flags
& LINK_PARTIALLY_SPECIFIED
)
638 && ((lnk
->link_type
== LINK_TCP
) ||
639 (lnk
->link_type
== LINK_UDP
))) {
640 if (GetSocket(la
, port_net
, &lnk
->sockfd
, lnk
->link_type
)) {
641 lnk
->alias_port
= port_net
;
646 lnk
->alias_port
= port_net
;
648 #ifndef NO_USE_SOCKETS
652 port_sys
= krandom() & ALIAS_PORT_MASK
;
653 port_sys
+= ALIAS_PORT_BASE
;
654 port_net
= htons(port_sys
);
657 #ifdef LIBALIAS_DEBUG
658 fprintf(stderr
, "PacketAlias/GetnewPort(): ");
659 fprintf(stderr
, "could not find free port\n");
665 #ifndef NO_USE_SOCKETS
667 GetSocket(struct libalias
*la
, u_short port_net
, int *sockfd
, int link_type
)
671 struct sockaddr_in sock_addr
;
673 LIBALIAS_LOCK_ASSERT(la
);
674 if (link_type
== LINK_TCP
)
675 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
676 else if (link_type
== LINK_UDP
)
677 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
679 #ifdef LIBALIAS_DEBUG
680 fprintf(stderr
, "PacketAlias/GetSocket(): ");
681 fprintf(stderr
, "incorrect link type\n");
687 #ifdef LIBALIAS_DEBUG
688 fprintf(stderr
, "PacketAlias/GetSocket(): ");
689 fprintf(stderr
, "socket() error %d\n", *sockfd
);
693 sock_addr
.sin_family
= AF_INET
;
694 sock_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
695 sock_addr
.sin_port
= port_net
;
698 (struct sockaddr
*)&sock_addr
,
711 /* FindNewPortGroup() returns a base port number for an available
712 range of contiguous port numbers. Note that if a port number
713 is already in use, that does not mean that it cannot be used by
714 another link concurrently. This is because FindNewPortGroup()
715 looks for unused triplets: (dest addr, dest port, alias port). */
718 FindNewPortGroup(struct libalias
*la
,
719 struct in_addr dst_addr
,
720 struct in_addr alias_addr
,
732 LIBALIAS_LOCK_ASSERT(la
);
734 * Get link_type from protocol
739 link_type
= LINK_UDP
;
742 link_type
= LINK_TCP
;
750 * The aliasing port is automatically selected by one of two
753 max_trials
= GET_NEW_PORT_MAX_ATTEMPTS
;
755 if (la
->packetAliasMode
& PKT_ALIAS_SAME_PORTS
) {
757 * When the ALIAS_SAME_PORTS option is chosen, the first
758 * try will be the actual source port. If this is already
759 * in use, the remainder of the trials will be random.
761 port_sys
= ntohs(src_port
);
765 /* First trial and all subsequent are random. */
766 if (align
== FIND_EVEN_ALIAS_BASE
)
767 port_sys
= krandom() & ALIAS_PORT_MASK_EVEN
;
769 port_sys
= krandom() & ALIAS_PORT_MASK
;
771 port_sys
+= ALIAS_PORT_BASE
;
774 /* Port number search */
775 for (i
= 0; i
< max_trials
; i
++) {
777 struct alias_link
*search_result
;
779 for (j
= 0; j
< port_count
; j
++)
780 if (0 != (search_result
= FindLinkIn(la
, dst_addr
, alias_addr
,
781 dst_port
, htons(port_sys
+ j
),
785 /* Found a good range, return base */
787 return (htons(port_sys
));
789 /* Find a new base to try */
790 if (align
== FIND_EVEN_ALIAS_BASE
)
791 port_sys
= krandom() & ALIAS_PORT_MASK_EVEN
;
793 port_sys
= krandom() & ALIAS_PORT_MASK
;
795 port_sys
+= ALIAS_PORT_BASE
;
798 #ifdef LIBALIAS_DEBUG
799 fprintf(stderr
, "PacketAlias/FindNewPortGroup(): ");
800 fprintf(stderr
, "could not find free port(s)\n");
807 CleanupAliasData(struct libalias
*la
)
809 struct alias_link
*lnk
;
812 LIBALIAS_LOCK_ASSERT(la
);
813 for (i
= 0; i
< LINK_TABLE_OUT_SIZE
; i
++) {
814 lnk
= LIST_FIRST(&la
->linkTableOut
[i
]);
815 while (lnk
!= NULL
) {
816 struct alias_link
*link_next
= LIST_NEXT(lnk
, list_out
);
822 la
->cleanupIndex
= 0;
827 IncrementalCleanup(struct libalias
*la
)
829 struct alias_link
*lnk
, *lnk_tmp
;
831 LIBALIAS_LOCK_ASSERT(la
);
833 LIST_FOREACH_MUTABLE(lnk
, &la
->linkTableOut
[la
->cleanupIndex
++],list_out
, lnk_tmp
) {
834 if (la
->timeStamp
- lnk
->timestamp
> lnk
->expire_time
)
838 if (la
->cleanupIndex
== LINK_TABLE_OUT_SIZE
)
839 la
->cleanupIndex
= 0;
843 DeleteLink(struct alias_link
*lnk
)
845 struct libalias
*la
= lnk
->la
;
847 LIBALIAS_LOCK_ASSERT(la
);
848 /* Don't do anything if the link is marked permanent */
849 if (la
->deleteAllLinks
== 0 && lnk
->flags
& LINK_PERMANENT
)
853 /* Delete associated firewall hole, if any */
857 /* Free memory allocated for LSNAT server pool */
858 if (lnk
->server
!= NULL
) {
859 struct server
*head
, *curr
, *next
;
861 head
= curr
= lnk
->server
;
865 } while ((curr
= next
) != head
);
867 /* Adjust output table pointers */
868 LIST_REMOVE(lnk
, list_out
);
870 /* Adjust input table pointers */
871 LIST_REMOVE(lnk
, list_in
);
872 #ifndef NO_USE_SOCKETS
873 /* Close socket, if one has been allocated */
874 if (lnk
->sockfd
!= -1) {
879 /* Link-type dependent cleanup */
880 switch (lnk
->link_type
) {
889 kfree(lnk
->data
.tcp
,M_ALIAS
);
894 case LINK_FRAGMENT_ID
:
895 la
->fragmentIdLinkCount
--;
897 case LINK_FRAGMENT_PTR
:
898 la
->fragmentPtrLinkCount
--;
899 if (lnk
->data
.frag_ptr
!= NULL
)
900 kfree(lnk
->data
.frag_ptr
,M_ALIAS
);
905 la
->protoLinkCount
--;
912 /* Write statistics, if logging enabled */
913 if (la
->packetAliasMode
& PKT_ALIAS_LOG
) {
919 static struct alias_link
*
920 AddLink(struct libalias
*la
, struct in_addr src_addr
,
921 struct in_addr dst_addr
,
922 struct in_addr alias_addr
,
925 int alias_port_param
, /* if less than zero, alias */
927 { /* port will be automatically *//* chosen.
929 u_int start_point
; /* zero, equal to alias port */
930 struct alias_link
*lnk
;
932 LIBALIAS_LOCK_ASSERT(la
);
933 lnk
= kmalloc(sizeof(struct alias_link
),M_ALIAS
, M_WAITOK
| M_ZERO
);
935 /* Basic initialization */
937 lnk
->src_addr
= src_addr
;
938 lnk
->dst_addr
= dst_addr
;
939 lnk
->alias_addr
= alias_addr
;
940 lnk
->proxy_addr
.s_addr
= INADDR_ANY
;
941 lnk
->src_port
= src_port
;
942 lnk
->dst_port
= dst_port
;
945 lnk
->link_type
= link_type
;
946 #ifndef NO_USE_SOCKETS
951 lnk
->timestamp
= la
->timeStamp
;
953 /* Expiration time */
956 lnk
->expire_time
= ICMP_EXPIRE_TIME
;
959 lnk
->expire_time
= UDP_EXPIRE_TIME
;
962 lnk
->expire_time
= TCP_EXPIRE_INITIAL
;
965 lnk
->flags
|= LINK_PERMANENT
; /* no timeout. */
967 case LINK_FRAGMENT_ID
:
968 lnk
->expire_time
= FRAGMENT_ID_EXPIRE_TIME
;
970 case LINK_FRAGMENT_PTR
:
971 lnk
->expire_time
= FRAGMENT_PTR_EXPIRE_TIME
;
976 lnk
->expire_time
= PROTO_EXPIRE_TIME
;
980 /* Determine alias flags */
981 if (dst_addr
.s_addr
== INADDR_ANY
)
982 lnk
->flags
|= LINK_UNKNOWN_DEST_ADDR
;
984 lnk
->flags
|= LINK_UNKNOWN_DEST_PORT
;
986 /* Determine alias port */
987 if (GetNewPort(la
, lnk
, alias_port_param
) != 0) {
991 /* Link-type dependent initialization */
993 struct tcp_dat
*aux_tcp
;
1002 aux_tcp
= kmalloc(sizeof(struct tcp_dat
),M_ALIAS
, M_WAITOK
| M_ZERO
);
1003 if (aux_tcp
!= NULL
) {
1007 aux_tcp
->state
.in
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1008 aux_tcp
->state
.out
= ALIAS_TCP_STATE_NOT_CONNECTED
;
1009 aux_tcp
->state
.index
= 0;
1010 aux_tcp
->state
.ack_modified
= 0;
1011 for (i
= 0; i
< N_LINK_TCP_DATA
; i
++)
1012 aux_tcp
->ack
[i
].active
= 0;
1013 aux_tcp
->fwhole
= -1;
1014 lnk
->data
.tcp
= aux_tcp
;
1016 #ifdef LIBALIAS_DEBUG
1017 fprintf(stderr
, "PacketAlias/AddLink: ");
1018 fprintf(stderr
, " cannot allocate auxiliary TCP data\n");
1025 la
->pptpLinkCount
++;
1027 case LINK_FRAGMENT_ID
:
1028 la
->fragmentIdLinkCount
++;
1030 case LINK_FRAGMENT_PTR
:
1031 la
->fragmentPtrLinkCount
++;
1036 la
->protoLinkCount
++;
1040 /* Set up pointers for output lookup table */
1041 start_point
= StartPointOut(src_addr
, dst_addr
,
1042 src_port
, dst_port
, link_type
);
1043 LIST_INSERT_HEAD(&la
->linkTableOut
[start_point
], lnk
, list_out
);
1045 /* Set up pointers for input lookup table */
1046 start_point
= StartPointIn(alias_addr
, lnk
->alias_port
, link_type
);
1047 LIST_INSERT_HEAD(&la
->linkTableIn
[start_point
], lnk
, list_in
);
1049 #ifdef LIBALIAS_DEBUG
1050 fprintf(stderr
, "PacketAlias/AddLink(): ");
1051 fprintf(stderr
, "kmalloc() call failed.\n");
1054 if (la
->packetAliasMode
& PKT_ALIAS_LOG
) {
1060 static struct alias_link
*
1061 ReLink(struct alias_link
*old_lnk
,
1062 struct in_addr src_addr
,
1063 struct in_addr dst_addr
,
1064 struct in_addr alias_addr
,
1067 int alias_port_param
, /* if less than zero, alias */
1069 { /* port will be automatically *//* chosen.
1070 * If greater than */
1071 struct alias_link
*new_lnk
; /* zero, equal to alias port */
1072 struct libalias
*la
= old_lnk
->la
;
1074 LIBALIAS_LOCK_ASSERT(la
);
1075 new_lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
1076 src_port
, dst_port
, alias_port_param
,
1079 if (new_lnk
!= NULL
&&
1080 old_lnk
->link_type
== LINK_TCP
&&
1081 old_lnk
->data
.tcp
->fwhole
> 0) {
1082 PunchFWHole(new_lnk
);
1085 DeleteLink(old_lnk
);
1089 static struct alias_link
*
1090 _FindLinkOut(struct libalias
*la
, struct in_addr src_addr
,
1091 struct in_addr dst_addr
,
1095 int replace_partial_links
)
1098 struct alias_link
*lnk
;
1100 LIBALIAS_LOCK_ASSERT(la
);
1101 i
= StartPointOut(src_addr
, dst_addr
, src_port
, dst_port
, link_type
);
1102 LIST_FOREACH(lnk
, &la
->linkTableOut
[i
], list_out
) {
1103 if (lnk
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1104 lnk
->src_addr
.s_addr
== src_addr
.s_addr
&&
1105 lnk
->src_port
== src_port
&&
1106 lnk
->dst_port
== dst_port
&&
1107 lnk
->link_type
== link_type
&&
1108 lnk
->server
== NULL
) {
1109 lnk
->timestamp
= la
->timeStamp
;
1114 /* Search for partially specified links. */
1115 if (lnk
== NULL
&& replace_partial_links
) {
1116 if (dst_port
!= 0 && dst_addr
.s_addr
!= INADDR_ANY
) {
1117 lnk
= _FindLinkOut(la
, src_addr
, dst_addr
, src_port
, 0,
1120 lnk
= _FindLinkOut(la
, src_addr
, la
->nullAddress
, src_port
,
1121 dst_port
, link_type
, 0);
1124 (dst_port
!= 0 || dst_addr
.s_addr
!= INADDR_ANY
)) {
1125 lnk
= _FindLinkOut(la
, src_addr
, la
->nullAddress
, src_port
, 0,
1130 src_addr
, dst_addr
, lnk
->alias_addr
,
1131 src_port
, dst_port
, lnk
->alias_port
,
1138 static struct alias_link
*
1139 FindLinkOut(struct libalias
*la
, struct in_addr src_addr
,
1140 struct in_addr dst_addr
,
1144 int replace_partial_links
)
1146 struct alias_link
*lnk
;
1148 LIBALIAS_LOCK_ASSERT(la
);
1149 lnk
= _FindLinkOut(la
, src_addr
, dst_addr
, src_port
, dst_port
,
1150 link_type
, replace_partial_links
);
1154 * The following allows permanent links to be specified as
1155 * using the default source address (i.e. device interface
1156 * address) without knowing in advance what that address
1159 if (la
->aliasAddress
.s_addr
!= INADDR_ANY
&&
1160 src_addr
.s_addr
== la
->aliasAddress
.s_addr
) {
1161 lnk
= _FindLinkOut(la
, la
->nullAddress
, dst_addr
, src_port
, dst_port
,
1162 link_type
, replace_partial_links
);
1169 static struct alias_link
*
1170 _FindLinkIn(struct libalias
*la
, struct in_addr dst_addr
,
1171 struct in_addr alias_addr
,
1175 int replace_partial_links
)
1179 struct alias_link
*lnk
;
1180 struct alias_link
*lnk_fully_specified
;
1181 struct alias_link
*lnk_unknown_all
;
1182 struct alias_link
*lnk_unknown_dst_addr
;
1183 struct alias_link
*lnk_unknown_dst_port
;
1185 LIBALIAS_LOCK_ASSERT(la
);
1186 /* Initialize pointers */
1187 lnk_fully_specified
= NULL
;
1188 lnk_unknown_all
= NULL
;
1189 lnk_unknown_dst_addr
= NULL
;
1190 lnk_unknown_dst_port
= NULL
;
1192 /* If either the dest addr or port is unknown, the search
1193 loop will have to know about this. */
1196 if (dst_addr
.s_addr
== INADDR_ANY
)
1197 flags_in
|= LINK_UNKNOWN_DEST_ADDR
;
1199 flags_in
|= LINK_UNKNOWN_DEST_PORT
;
1202 start_point
= StartPointIn(alias_addr
, alias_port
, link_type
);
1203 LIST_FOREACH(lnk
, &la
->linkTableIn
[start_point
], list_in
) {
1206 flags
= flags_in
| lnk
->flags
;
1207 if (!(flags
& LINK_PARTIALLY_SPECIFIED
)) {
1208 if (lnk
->alias_addr
.s_addr
== alias_addr
.s_addr
1209 && lnk
->alias_port
== alias_port
1210 && lnk
->dst_addr
.s_addr
== dst_addr
.s_addr
1211 && lnk
->dst_port
== dst_port
1212 && lnk
->link_type
== link_type
) {
1213 lnk_fully_specified
= lnk
;
1216 } else if ((flags
& LINK_UNKNOWN_DEST_ADDR
)
1217 && (flags
& LINK_UNKNOWN_DEST_PORT
)) {
1218 if (lnk
->alias_addr
.s_addr
== alias_addr
.s_addr
1219 && lnk
->alias_port
== alias_port
1220 && lnk
->link_type
== link_type
) {
1221 if (lnk_unknown_all
== NULL
)
1222 lnk_unknown_all
= lnk
;
1224 } else if (flags
& LINK_UNKNOWN_DEST_ADDR
) {
1225 if (lnk
->alias_addr
.s_addr
== alias_addr
.s_addr
1226 && lnk
->alias_port
== alias_port
1227 && lnk
->link_type
== link_type
1228 && lnk
->dst_port
== dst_port
) {
1229 if (lnk_unknown_dst_addr
== NULL
)
1230 lnk_unknown_dst_addr
= lnk
;
1232 } else if (flags
& LINK_UNKNOWN_DEST_PORT
) {
1233 if (lnk
->alias_addr
.s_addr
== alias_addr
.s_addr
1234 && lnk
->alias_port
== alias_port
1235 && lnk
->link_type
== link_type
1236 && lnk
->dst_addr
.s_addr
== dst_addr
.s_addr
) {
1237 if (lnk_unknown_dst_port
== NULL
)
1238 lnk_unknown_dst_port
= lnk
;
1245 if (lnk_fully_specified
!= NULL
) {
1246 lnk_fully_specified
->timestamp
= la
->timeStamp
;
1247 lnk
= lnk_fully_specified
;
1248 } else if (lnk_unknown_dst_port
!= NULL
)
1249 lnk
= lnk_unknown_dst_port
;
1250 else if (lnk_unknown_dst_addr
!= NULL
)
1251 lnk
= lnk_unknown_dst_addr
;
1252 else if (lnk_unknown_all
!= NULL
)
1253 lnk
= lnk_unknown_all
;
1257 if (replace_partial_links
&&
1258 (lnk
->flags
& LINK_PARTIALLY_SPECIFIED
|| lnk
->server
!= NULL
)) {
1259 struct in_addr src_addr
;
1262 if (lnk
->server
!= NULL
) { /* LSNAT link */
1263 src_addr
= lnk
->server
->addr
;
1264 src_port
= lnk
->server
->port
;
1265 lnk
->server
= lnk
->server
->next
;
1267 src_addr
= lnk
->src_addr
;
1268 src_port
= lnk
->src_port
;
1272 src_addr
, dst_addr
, alias_addr
,
1273 src_port
, dst_port
, alias_port
,
1279 static struct alias_link
*
1280 FindLinkIn(struct libalias
*la
, struct in_addr dst_addr
,
1281 struct in_addr alias_addr
,
1285 int replace_partial_links
)
1287 struct alias_link
*lnk
;
1289 LIBALIAS_LOCK_ASSERT(la
);
1290 lnk
= _FindLinkIn(la
, dst_addr
, alias_addr
, dst_port
, alias_port
,
1291 link_type
, replace_partial_links
);
1295 * The following allows permanent links to be specified as
1296 * using the default aliasing address (i.e. device
1297 * interface address) without knowing in advance what that
1300 if (la
->aliasAddress
.s_addr
!= INADDR_ANY
&&
1301 alias_addr
.s_addr
== la
->aliasAddress
.s_addr
) {
1302 lnk
= _FindLinkIn(la
, dst_addr
, la
->nullAddress
, dst_port
, alias_port
,
1303 link_type
, replace_partial_links
);
1312 /* External routines for finding/adding links
1314 -- "external" means outside alias_db.c, but within alias*.c --
1316 FindIcmpIn(), FindIcmpOut()
1317 FindFragmentIn1(), FindFragmentIn2()
1318 AddFragmentPtrLink(), FindFragmentPtr()
1319 FindProtoIn(), FindProtoOut()
1320 FindUdpTcpIn(), FindUdpTcpOut()
1321 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1322 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1323 FindOriginalAddress(), FindAliasAddress()
1325 (prototypes in alias_local.h)
1330 FindIcmpIn(struct libalias
*la
, struct in_addr dst_addr
,
1331 struct in_addr alias_addr
,
1335 struct alias_link
*lnk
;
1337 LIBALIAS_LOCK_ASSERT(la
);
1338 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
1339 NO_DEST_PORT
, id_alias
,
1341 if (lnk
== NULL
&& create
&& !(la
->packetAliasMode
& PKT_ALIAS_DENY_INCOMING
)) {
1342 struct in_addr target_addr
;
1344 target_addr
= FindOriginalAddress(la
, alias_addr
);
1345 lnk
= AddLink(la
, target_addr
, dst_addr
, alias_addr
,
1346 id_alias
, NO_DEST_PORT
, id_alias
,
1354 FindIcmpOut(struct libalias
*la
, struct in_addr src_addr
,
1355 struct in_addr dst_addr
,
1359 struct alias_link
*lnk
;
1361 LIBALIAS_LOCK_ASSERT(la
);
1362 lnk
= FindLinkOut(la
, src_addr
, dst_addr
,
1365 if (lnk
== NULL
&& create
) {
1366 struct in_addr alias_addr
;
1368 alias_addr
= FindAliasAddress(la
, src_addr
);
1369 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
1370 id
, NO_DEST_PORT
, GET_ALIAS_ID
,
1378 FindFragmentIn1(struct libalias
*la
, struct in_addr dst_addr
,
1379 struct in_addr alias_addr
,
1382 struct alias_link
*lnk
;
1384 LIBALIAS_LOCK_ASSERT(la
);
1385 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
1386 NO_DEST_PORT
, ip_id
,
1387 LINK_FRAGMENT_ID
, 0);
1390 lnk
= AddLink(la
, la
->nullAddress
, dst_addr
, alias_addr
,
1391 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1399 FindFragmentIn2(struct libalias
*la
, struct in_addr dst_addr
, /* Doesn't add a link if
1401 struct in_addr alias_addr
, /* is not found. */
1405 LIBALIAS_LOCK_ASSERT(la
);
1406 return FindLinkIn(la
, dst_addr
, alias_addr
,
1407 NO_DEST_PORT
, ip_id
,
1408 LINK_FRAGMENT_ID
, 0);
1413 AddFragmentPtrLink(struct libalias
*la
, struct in_addr dst_addr
,
1417 LIBALIAS_LOCK_ASSERT(la
);
1418 return AddLink(la
, la
->nullAddress
, dst_addr
, la
->nullAddress
,
1419 NO_SRC_PORT
, NO_DEST_PORT
, ip_id
,
1425 FindFragmentPtr(struct libalias
*la
, struct in_addr dst_addr
,
1429 LIBALIAS_LOCK_ASSERT(la
);
1430 return FindLinkIn(la
, dst_addr
, la
->nullAddress
,
1431 NO_DEST_PORT
, ip_id
,
1432 LINK_FRAGMENT_PTR
, 0);
1437 FindProtoIn(struct libalias
*la
, struct in_addr dst_addr
,
1438 struct in_addr alias_addr
,
1441 struct alias_link
*lnk
;
1443 LIBALIAS_LOCK_ASSERT(la
);
1444 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
1448 if (lnk
== NULL
&& !(la
->packetAliasMode
& PKT_ALIAS_DENY_INCOMING
)) {
1449 struct in_addr target_addr
;
1451 target_addr
= FindOriginalAddress(la
, alias_addr
);
1452 lnk
= AddLink(la
, target_addr
, dst_addr
, alias_addr
,
1453 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1461 FindProtoOut(struct libalias
*la
, struct in_addr src_addr
,
1462 struct in_addr dst_addr
,
1465 struct alias_link
*lnk
;
1467 LIBALIAS_LOCK_ASSERT(la
);
1468 lnk
= FindLinkOut(la
, src_addr
, dst_addr
,
1469 NO_SRC_PORT
, NO_DEST_PORT
,
1473 struct in_addr alias_addr
;
1475 alias_addr
= FindAliasAddress(la
, src_addr
);
1476 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
1477 NO_SRC_PORT
, NO_DEST_PORT
, 0,
1485 FindUdpTcpIn(struct libalias
*la
, struct in_addr dst_addr
,
1486 struct in_addr alias_addr
,
1493 struct alias_link
*lnk
;
1495 LIBALIAS_LOCK_ASSERT(la
);
1498 link_type
= LINK_UDP
;
1501 link_type
= LINK_TCP
;
1508 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
1509 dst_port
, alias_port
,
1512 if (lnk
== NULL
&& create
&& !(la
->packetAliasMode
& PKT_ALIAS_DENY_INCOMING
)) {
1513 struct in_addr target_addr
;
1515 target_addr
= FindOriginalAddress(la
, alias_addr
);
1516 lnk
= AddLink(la
, target_addr
, dst_addr
, alias_addr
,
1517 alias_port
, dst_port
, alias_port
,
1525 FindUdpTcpOut(struct libalias
*la
, struct in_addr src_addr
,
1526 struct in_addr dst_addr
,
1533 struct alias_link
*lnk
;
1535 LIBALIAS_LOCK_ASSERT(la
);
1538 link_type
= LINK_UDP
;
1541 link_type
= LINK_TCP
;
1548 lnk
= FindLinkOut(la
, src_addr
, dst_addr
, src_port
, dst_port
, link_type
, create
);
1550 if (lnk
== NULL
&& create
) {
1551 struct in_addr alias_addr
;
1553 alias_addr
= FindAliasAddress(la
, src_addr
);
1554 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
1555 src_port
, dst_port
, GET_ALIAS_PORT
,
1563 AddPptp(struct libalias
*la
, struct in_addr src_addr
,
1564 struct in_addr dst_addr
,
1565 struct in_addr alias_addr
,
1566 u_int16_t src_call_id
)
1568 struct alias_link
*lnk
;
1570 LIBALIAS_LOCK_ASSERT(la
);
1571 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
1572 src_call_id
, 0, GET_ALIAS_PORT
,
1580 FindPptpOutByCallId(struct libalias
*la
, struct in_addr src_addr
,
1581 struct in_addr dst_addr
,
1582 u_int16_t src_call_id
)
1585 struct alias_link
*lnk
;
1587 LIBALIAS_LOCK_ASSERT(la
);
1588 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1589 LIST_FOREACH(lnk
, &la
->linkTableOut
[i
], list_out
)
1590 if (lnk
->link_type
== LINK_PPTP
&&
1591 lnk
->src_addr
.s_addr
== src_addr
.s_addr
&&
1592 lnk
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1593 lnk
->src_port
== src_call_id
)
1601 FindPptpOutByPeerCallId(struct libalias
*la
, struct in_addr src_addr
,
1602 struct in_addr dst_addr
,
1603 u_int16_t dst_call_id
)
1606 struct alias_link
*lnk
;
1608 LIBALIAS_LOCK_ASSERT(la
);
1609 i
= StartPointOut(src_addr
, dst_addr
, 0, 0, LINK_PPTP
);
1610 LIST_FOREACH(lnk
, &la
->linkTableOut
[i
], list_out
)
1611 if (lnk
->link_type
== LINK_PPTP
&&
1612 lnk
->src_addr
.s_addr
== src_addr
.s_addr
&&
1613 lnk
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1614 lnk
->dst_port
== dst_call_id
)
1622 FindPptpInByCallId(struct libalias
*la
, struct in_addr dst_addr
,
1623 struct in_addr alias_addr
,
1624 u_int16_t dst_call_id
)
1627 struct alias_link
*lnk
;
1629 LIBALIAS_LOCK_ASSERT(la
);
1630 i
= StartPointIn(alias_addr
, 0, LINK_PPTP
);
1631 LIST_FOREACH(lnk
, &la
->linkTableIn
[i
], list_in
)
1632 if (lnk
->link_type
== LINK_PPTP
&&
1633 lnk
->dst_addr
.s_addr
== dst_addr
.s_addr
&&
1634 lnk
->alias_addr
.s_addr
== alias_addr
.s_addr
&&
1635 lnk
->dst_port
== dst_call_id
)
1643 FindPptpInByPeerCallId(struct libalias
*la
, struct in_addr dst_addr
,
1644 struct in_addr alias_addr
,
1645 u_int16_t alias_call_id
)
1647 struct alias_link
*lnk
;
1649 LIBALIAS_LOCK_ASSERT(la
);
1650 lnk
= FindLinkIn(la
, dst_addr
, alias_addr
,
1651 0 /* any */ , alias_call_id
,
1660 FindRtspOut(struct libalias
*la
, struct in_addr src_addr
,
1661 struct in_addr dst_addr
,
1667 struct alias_link
*lnk
;
1669 LIBALIAS_LOCK_ASSERT(la
);
1672 link_type
= LINK_UDP
;
1675 link_type
= LINK_TCP
;
1682 lnk
= FindLinkOut(la
, src_addr
, dst_addr
, src_port
, 0, link_type
, 1);
1685 struct in_addr alias_addr
;
1687 alias_addr
= FindAliasAddress(la
, src_addr
);
1688 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
1689 src_port
, 0, alias_port
,
1697 FindOriginalAddress(struct libalias
*la
, struct in_addr alias_addr
)
1699 struct alias_link
*lnk
;
1701 LIBALIAS_LOCK_ASSERT(la
);
1702 lnk
= FindLinkIn(la
, la
->nullAddress
, alias_addr
,
1703 0, 0, LINK_ADDR
, 0);
1705 la
->newDefaultLink
= 1;
1706 if (la
->targetAddress
.s_addr
== INADDR_ANY
)
1707 return (alias_addr
);
1708 else if (la
->targetAddress
.s_addr
== INADDR_NONE
)
1709 return (la
->aliasAddress
.s_addr
!= INADDR_ANY
) ?
1710 la
->aliasAddress
: alias_addr
;
1712 return (la
->targetAddress
);
1714 if (lnk
->server
!= NULL
) { /* LSNAT link */
1715 struct in_addr src_addr
;
1717 src_addr
= lnk
->server
->addr
;
1718 lnk
->server
= lnk
->server
->next
;
1720 } else if (lnk
->src_addr
.s_addr
== INADDR_ANY
)
1721 return (la
->aliasAddress
.s_addr
!= INADDR_ANY
) ?
1722 la
->aliasAddress
: alias_addr
;
1724 return (lnk
->src_addr
);
1730 FindAliasAddress(struct libalias
*la
, struct in_addr original_addr
)
1732 struct alias_link
*lnk
;
1734 LIBALIAS_LOCK_ASSERT(la
);
1735 lnk
= FindLinkOut(la
, original_addr
, la
->nullAddress
,
1736 0, 0, LINK_ADDR
, 0);
1738 return (la
->aliasAddress
.s_addr
!= INADDR_ANY
) ?
1739 la
->aliasAddress
: original_addr
;
1741 if (lnk
->alias_addr
.s_addr
== INADDR_ANY
)
1742 return (la
->aliasAddress
.s_addr
!= INADDR_ANY
) ?
1743 la
->aliasAddress
: original_addr
;
1745 return (lnk
->alias_addr
);
1750 /* External routines for getting or changing link data
1751 (external to alias_db.c, but internal to alias*.c)
1753 SetFragmentData(), GetFragmentData()
1754 SetFragmentPtr(), GetFragmentPtr()
1755 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1756 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1757 GetOriginalPort(), GetAliasPort()
1758 SetAckModified(), GetAckModified()
1759 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1760 SetProtocolFlags(), GetProtocolFlags()
1766 SetFragmentAddr(struct alias_link
*lnk
, struct in_addr src_addr
)
1768 lnk
->data
.frag_addr
= src_addr
;
1773 GetFragmentAddr(struct alias_link
*lnk
, struct in_addr
*src_addr
)
1775 *src_addr
= lnk
->data
.frag_addr
;
1780 SetFragmentPtr(struct alias_link
*lnk
, char *fptr
)
1782 lnk
->data
.frag_ptr
= fptr
;
1787 GetFragmentPtr(struct alias_link
*lnk
, char **fptr
)
1789 *fptr
= lnk
->data
.frag_ptr
;
1794 SetStateIn(struct alias_link
*lnk
, int state
)
1796 /* TCP input state */
1798 case ALIAS_TCP_STATE_DISCONNECTED
:
1799 if (lnk
->data
.tcp
->state
.out
!= ALIAS_TCP_STATE_CONNECTED
)
1800 lnk
->expire_time
= TCP_EXPIRE_DEAD
;
1802 lnk
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1804 case ALIAS_TCP_STATE_CONNECTED
:
1805 if (lnk
->data
.tcp
->state
.out
== ALIAS_TCP_STATE_CONNECTED
)
1806 lnk
->expire_time
= TCP_EXPIRE_CONNECTED
;
1810 panic("libalias:SetStateIn() unknown state");
1815 lnk
->data
.tcp
->state
.in
= state
;
1820 SetStateOut(struct alias_link
*lnk
, int state
)
1822 /* TCP output state */
1824 case ALIAS_TCP_STATE_DISCONNECTED
:
1825 if (lnk
->data
.tcp
->state
.in
!= ALIAS_TCP_STATE_CONNECTED
)
1826 lnk
->expire_time
= TCP_EXPIRE_DEAD
;
1828 lnk
->expire_time
= TCP_EXPIRE_SINGLEDEAD
;
1830 case ALIAS_TCP_STATE_CONNECTED
:
1831 if (lnk
->data
.tcp
->state
.in
== ALIAS_TCP_STATE_CONNECTED
)
1832 lnk
->expire_time
= TCP_EXPIRE_CONNECTED
;
1836 panic("libalias:SetStateOut() unknown state");
1841 lnk
->data
.tcp
->state
.out
= state
;
1846 GetStateIn(struct alias_link
*lnk
)
1848 /* TCP input state */
1849 return (lnk
->data
.tcp
->state
.in
);
1854 GetStateOut(struct alias_link
*lnk
)
1856 /* TCP output state */
1857 return (lnk
->data
.tcp
->state
.out
);
1862 GetOriginalAddress(struct alias_link
*lnk
)
1864 if (lnk
->src_addr
.s_addr
== INADDR_ANY
)
1865 return (lnk
->la
->aliasAddress
);
1867 return (lnk
->src_addr
);
1872 GetDestAddress(struct alias_link
*lnk
)
1874 return (lnk
->dst_addr
);
1879 GetAliasAddress(struct alias_link
*lnk
)
1881 if (lnk
->alias_addr
.s_addr
== INADDR_ANY
)
1882 return (lnk
->la
->aliasAddress
);
1884 return (lnk
->alias_addr
);
1889 GetDefaultAliasAddress(struct libalias
*la
)
1892 LIBALIAS_LOCK_ASSERT(la
);
1893 return (la
->aliasAddress
);
1898 SetDefaultAliasAddress(struct libalias
*la
, struct in_addr alias_addr
)
1901 LIBALIAS_LOCK_ASSERT(la
);
1902 la
->aliasAddress
= alias_addr
;
1907 GetOriginalPort(struct alias_link
*lnk
)
1909 return (lnk
->src_port
);
1914 GetAliasPort(struct alias_link
*lnk
)
1916 return (lnk
->alias_port
);
1921 GetDestPort(struct alias_link
*lnk
)
1923 return (lnk
->dst_port
);
1929 SetAckModified(struct alias_link
*lnk
)
1931 /* Indicate that ACK numbers have been modified in a TCP connection */
1932 lnk
->data
.tcp
->state
.ack_modified
= 1;
1937 GetProxyAddress(struct alias_link
*lnk
)
1939 return (lnk
->proxy_addr
);
1944 SetProxyAddress(struct alias_link
*lnk
, struct in_addr addr
)
1946 lnk
->proxy_addr
= addr
;
1951 GetProxyPort(struct alias_link
*lnk
)
1953 return (lnk
->proxy_port
);
1958 SetProxyPort(struct alias_link
*lnk
, u_short port
)
1960 lnk
->proxy_port
= port
;
1965 GetAckModified(struct alias_link
*lnk
)
1967 /* See if ACK numbers have been modified */
1968 return (lnk
->data
.tcp
->state
.ack_modified
);
1973 GetDeltaAckIn(struct ip
*pip
, struct alias_link
*lnk
)
1976 Find out how much the ACK number has been altered for an incoming
1977 TCP packet. To do this, a circular list of ACK numbers where the TCP
1978 packet size was altered is searched.
1983 int delta
, ack_diff_min
;
1991 for (i
= 0; i
< N_LINK_TCP_DATA
; i
++) {
1992 struct ack_data_record x
;
1994 x
= lnk
->data
.tcp
->ack
[i
];
1995 if (x
.active
== 1) {
1998 ack_diff
= SeqDiff(x
.ack_new
, ack
);
1999 if (ack_diff
>= 0) {
2000 if (ack_diff_min
>= 0) {
2001 if (ack_diff
< ack_diff_min
) {
2003 ack_diff_min
= ack_diff
;
2007 ack_diff_min
= ack_diff
;
2017 GetDeltaSeqOut(struct ip
*pip
, struct alias_link
*lnk
)
2020 Find out how much the sequence number has been altered for an outgoing
2021 TCP packet. To do this, a circular list of ACK numbers where the TCP
2022 packet size was altered is searched.
2027 int delta
, seq_diff_min
;
2035 for (i
= 0; i
< N_LINK_TCP_DATA
; i
++) {
2036 struct ack_data_record x
;
2038 x
= lnk
->data
.tcp
->ack
[i
];
2039 if (x
.active
== 1) {
2042 seq_diff
= SeqDiff(x
.ack_old
, seq
);
2043 if (seq_diff
>= 0) {
2044 if (seq_diff_min
>= 0) {
2045 if (seq_diff
< seq_diff_min
) {
2047 seq_diff_min
= seq_diff
;
2051 seq_diff_min
= seq_diff
;
2061 AddSeq(struct ip
*pip
, struct alias_link
*lnk
, int delta
)
2064 When a TCP packet has been altered in length, save this
2065 information in a circular list. If enough packets have
2066 been altered, then this list will begin to overwrite itself.
2070 struct ack_data_record x
;
2071 int hlen
, tlen
, dlen
;
2076 hlen
= (pip
->ip_hl
+ tc
->th_off
) << 2;
2077 tlen
= ntohs(pip
->ip_len
);
2080 x
.ack_old
= htonl(ntohl(tc
->th_seq
) + dlen
);
2081 x
.ack_new
= htonl(ntohl(tc
->th_seq
) + dlen
+ delta
);
2085 i
= lnk
->data
.tcp
->state
.index
;
2086 lnk
->data
.tcp
->ack
[i
] = x
;
2089 if (i
== N_LINK_TCP_DATA
)
2090 lnk
->data
.tcp
->state
.index
= 0;
2092 lnk
->data
.tcp
->state
.index
= i
;
2096 SetExpire(struct alias_link
*lnk
, int expire
)
2099 lnk
->flags
&= ~LINK_PERMANENT
;
2101 } else if (expire
== -1) {
2102 lnk
->flags
|= LINK_PERMANENT
;
2103 } else if (expire
> 0) {
2104 lnk
->expire_time
= expire
;
2106 #ifdef LIBALIAS_DEBUG
2107 fprintf(stderr
, "PacketAlias/SetExpire(): ");
2108 fprintf(stderr
, "error in expire parameter\n");
2114 ClearCheckNewLink(struct libalias
*la
)
2117 LIBALIAS_LOCK_ASSERT(la
);
2118 la
->newDefaultLink
= 0;
2122 SetProtocolFlags(struct alias_link
*lnk
, int pflags
)
2125 lnk
->pflags
= pflags
;;
2129 GetProtocolFlags(struct alias_link
*lnk
)
2132 return (lnk
->pflags
);
2136 SetDestCallId(struct alias_link
*lnk
, u_int16_t cid
)
2138 struct libalias
*la
= lnk
->la
;
2140 LIBALIAS_LOCK_ASSERT(la
);
2141 la
->deleteAllLinks
= 1;
2142 ReLink(lnk
, lnk
->src_addr
, lnk
->dst_addr
, lnk
->alias_addr
,
2143 lnk
->src_port
, cid
, lnk
->alias_port
, lnk
->link_type
);
2144 la
->deleteAllLinks
= 0;
2148 /* Miscellaneous Functions
2151 InitPacketAliasLog()
2152 UninitPacketAliasLog()
2156 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2157 is called to find and remove timed-out aliasing links. Logic exists
2158 to sweep through the entire table and linked list structure
2161 (prototype in alias_local.h)
2165 HouseKeeping(struct libalias
*la
)
2173 LIBALIAS_LOCK_ASSERT(la
);
2175 * Save system time (seconds) in global variable timeStamp for use
2176 * by other functions. This is done so as not to unnecessarily
2177 * waste timeline by making system calls.
2180 la
->timeStamp
= time_uptime
;
2182 gettimeofday(&tv
, &tz
);
2183 la
->timeStamp
= tv
.tv_sec
;
2186 /* Compute number of spokes (output table link chains) to cover */
2187 n
= LINK_TABLE_OUT_SIZE
* (la
->timeStamp
- la
->lastCleanupTime
);
2188 n
/= ALIAS_CLEANUP_INTERVAL_SECS
;
2190 /* Handle different cases */
2192 if (n
> ALIAS_CLEANUP_MAX_SPOKES
)
2193 n
= ALIAS_CLEANUP_MAX_SPOKES
;
2194 la
->lastCleanupTime
= la
->timeStamp
;
2195 for (i
= 0; i
< n
; i
++)
2196 IncrementalCleanup(la
);
2198 #ifdef LIBALIAS_DEBUG
2199 fprintf(stderr
, "PacketAlias/HouseKeeping(): ");
2200 fprintf(stderr
, "something unexpected in time values\n");
2202 la
->lastCleanupTime
= la
->timeStamp
;
2206 /* Init the log file and enable logging */
2208 InitPacketAliasLog(struct libalias
*la
)
2211 LIBALIAS_LOCK_ASSERT(la
);
2212 if (~la
->packetAliasMode
& PKT_ALIAS_LOG
) {
2214 if ((la
->logDesc
= kmalloc(LIBALIAS_BUF_SIZE
,M_ALIAS
, M_WAITOK
| M_ZERO
)))
2217 if ((la
->logDesc
= fopen("/var/log/alias.log", "w")))
2218 fprintf(la
->logDesc
, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2221 return (ENOMEM
); /* log initialization failed */
2222 la
->packetAliasMode
|= PKT_ALIAS_LOG
;
2228 /* Close the log-file and disable logging. */
2230 UninitPacketAliasLog(struct libalias
*la
)
2233 LIBALIAS_LOCK_ASSERT(la
);
2236 kfree(la
->logDesc
,M_ALIAS
);
2238 fclose(la
->logDesc
);
2242 la
->packetAliasMode
&= ~PKT_ALIAS_LOG
;
2245 /* Outside world interfaces
2247 -- "outside world" means other than alias*.c routines --
2249 PacketAliasRedirectPort()
2250 PacketAliasAddServer()
2251 PacketAliasRedirectProto()
2252 PacketAliasRedirectAddr()
2253 PacketAliasRedirectDynamic()
2254 PacketAliasRedirectDelete()
2255 PacketAliasSetAddress()
2258 PacketAliasSetMode()
2260 (prototypes in alias.h)
2263 /* Redirection from a specific public addr:port to a
2264 private addr:port */
2266 LibAliasRedirectPort(struct libalias
*la
, struct in_addr src_addr
, u_short src_port
,
2267 struct in_addr dst_addr
, u_short dst_port
,
2268 struct in_addr alias_addr
, u_short alias_port
,
2272 struct alias_link
*lnk
;
2277 link_type
= LINK_UDP
;
2280 link_type
= LINK_TCP
;
2283 #ifdef LIBALIAS_DEBUG
2284 fprintf(stderr
, "PacketAliasRedirectPort(): ");
2285 fprintf(stderr
, "only TCP and UDP protocols allowed\n");
2291 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
2292 src_port
, dst_port
, alias_port
,
2296 lnk
->flags
|= LINK_PERMANENT
;
2298 #ifdef LIBALIAS_DEBUG
2300 fprintf(stderr
, "PacketAliasRedirectPort(): "
2301 "call to AddLink() failed\n");
2306 LIBALIAS_UNLOCK(la
);
2310 /* Add server to the pool of servers */
2312 LibAliasAddServer(struct libalias
*la
, struct alias_link
*lnk
, struct in_addr addr
, u_short port
)
2314 struct server
*server
;
2320 server
= kmalloc(sizeof(struct server
),M_ALIAS
, M_WAITOK
| M_ZERO
);
2322 if (server
!= NULL
) {
2323 struct server
*head
;
2325 server
->addr
= addr
;
2326 server
->port
= port
;
2330 server
->next
= server
;
2334 for (s
= head
; s
->next
!= head
; s
= s
->next
);
2336 server
->next
= head
;
2338 lnk
->server
= server
;
2343 LIBALIAS_UNLOCK(la
);
2347 /* Redirect packets of a given IP protocol from a specific
2348 public address to a private address */
2350 LibAliasRedirectProto(struct libalias
*la
, struct in_addr src_addr
,
2351 struct in_addr dst_addr
,
2352 struct in_addr alias_addr
,
2355 struct alias_link
*lnk
;
2358 lnk
= AddLink(la
, src_addr
, dst_addr
, alias_addr
,
2359 NO_SRC_PORT
, NO_DEST_PORT
, 0,
2363 lnk
->flags
|= LINK_PERMANENT
;
2365 #ifdef LIBALIAS_DEBUG
2367 fprintf(stderr
, "PacketAliasRedirectProto(): "
2368 "call to AddLink() failed\n");
2372 LIBALIAS_UNLOCK(la
);
2376 /* Static address translation */
2378 LibAliasRedirectAddr(struct libalias
*la
, struct in_addr src_addr
,
2379 struct in_addr alias_addr
)
2381 struct alias_link
*lnk
;
2384 lnk
= AddLink(la
, src_addr
, la
->nullAddress
, alias_addr
,
2389 lnk
->flags
|= LINK_PERMANENT
;
2391 #ifdef LIBALIAS_DEBUG
2393 fprintf(stderr
, "PacketAliasRedirectAddr(): "
2394 "call to AddLink() failed\n");
2398 LIBALIAS_UNLOCK(la
);
2403 /* Mark the aliasing link dynamic */
2405 LibAliasRedirectDynamic(struct libalias
*la
, struct alias_link
*lnk
)
2412 if (lnk
->flags
& LINK_PARTIALLY_SPECIFIED
)
2415 lnk
->flags
&= ~LINK_PERMANENT
;
2418 LIBALIAS_UNLOCK(la
);
2424 LibAliasRedirectDelete(struct libalias
*la
, struct alias_link
*lnk
)
2426 /* This is a dangerous function to put in the API,
2427 because an invalid pointer can crash the program. */
2430 la
->deleteAllLinks
= 1;
2432 la
->deleteAllLinks
= 0;
2433 LIBALIAS_UNLOCK(la
);
2438 LibAliasSetAddress(struct libalias
*la
, struct in_addr addr
)
2442 if (la
->packetAliasMode
& PKT_ALIAS_RESET_ON_ADDR_CHANGE
2443 && la
->aliasAddress
.s_addr
!= addr
.s_addr
)
2444 CleanupAliasData(la
);
2446 la
->aliasAddress
= addr
;
2447 LIBALIAS_UNLOCK(la
);
2452 LibAliasSetTarget(struct libalias
*la
, struct in_addr target_addr
)
2456 la
->targetAddress
= target_addr
;
2457 LIBALIAS_UNLOCK(la
);
2464 while (!LIST_EMPTY(&instancehead
))
2465 LibAliasUninit(LIST_FIRST(&instancehead
));
2469 LibAliasInit(struct libalias
*la
)
2478 la
= kmalloc(sizeof *la
,M_ALIAS
, M_WAITOK
| M_ZERO
);
2482 #ifndef _KERNEL /* kernel cleans up on module unload */
2483 if (LIST_EMPTY(&instancehead
))
2486 LIST_INSERT_HEAD(&instancehead
, la
, instancelist
);
2489 la
->timeStamp
= time_uptime
;
2490 la
->lastCleanupTime
= time_uptime
;
2492 gettimeofday(&tv
, &tz
);
2493 la
->timeStamp
= tv
.tv_sec
;
2494 la
->lastCleanupTime
= tv
.tv_sec
;
2497 for (i
= 0; i
< LINK_TABLE_OUT_SIZE
; i
++)
2498 LIST_INIT(&la
->linkTableOut
[i
]);
2499 for (i
= 0; i
< LINK_TABLE_IN_SIZE
; i
++)
2500 LIST_INIT(&la
->linkTableIn
[i
]);
2501 LIBALIAS_LOCK_INIT(la
);
2505 la
->deleteAllLinks
= 1;
2506 CleanupAliasData(la
);
2507 la
->deleteAllLinks
= 0;
2510 la
->aliasAddress
.s_addr
= INADDR_ANY
;
2511 la
->targetAddress
.s_addr
= INADDR_ANY
;
2513 la
->icmpLinkCount
= 0;
2514 la
->udpLinkCount
= 0;
2515 la
->tcpLinkCount
= 0;
2516 la
->pptpLinkCount
= 0;
2517 la
->protoLinkCount
= 0;
2518 la
->fragmentIdLinkCount
= 0;
2519 la
->fragmentPtrLinkCount
= 0;
2522 la
->cleanupIndex
= 0;
2524 la
->packetAliasMode
= PKT_ALIAS_SAME_PORTS
2525 #ifndef NO_USE_SOCKETS
2526 | PKT_ALIAS_USE_SOCKETS
2528 | PKT_ALIAS_RESET_ON_ADDR_CHANGE
;
2530 la
->fireWallFD
= -1;
2533 LibAliasRefreshModules();
2535 LIBALIAS_UNLOCK(la
);
2540 LibAliasUninit(struct libalias
*la
)
2544 la
->deleteAllLinks
= 1;
2545 CleanupAliasData(la
);
2546 la
->deleteAllLinks
= 0;
2547 UninitPacketAliasLog(la
);
2551 LIST_REMOVE(la
, instancelist
);
2552 LIBALIAS_UNLOCK(la
);
2553 LIBALIAS_LOCK_DESTROY(la
);
2557 /* Change mode for some operations */
2560 struct libalias
*la
,
2561 unsigned int flags
, /* Which state to bring flags to */
2562 unsigned int mask
/* Mask of which flags to affect (use 0 to
2563 * do a probe for flag values) */
2569 /* Enable logging? */
2570 if (flags
& mask
& PKT_ALIAS_LOG
) {
2572 if (InitPacketAliasLog(la
) == ENOMEM
)
2575 /* _Disable_ logging? */
2576 if (~flags
& mask
& PKT_ALIAS_LOG
) {
2577 UninitPacketAliasLog(la
);
2580 /* Start punching holes in the firewall? */
2581 if (flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2584 /* Stop punching holes in the firewall? */
2585 if (~flags
& mask
& PKT_ALIAS_PUNCH_FW
) {
2590 /* Other flags can be set/cleared without special action */
2591 la
->packetAliasMode
= (flags
& mask
) | (la
->packetAliasMode
& ~mask
);
2592 res
= la
->packetAliasMode
;
2594 LIBALIAS_UNLOCK(la
);
2600 LibAliasCheckNewLink(struct libalias
*la
)
2605 res
= la
->newDefaultLink
;
2606 LIBALIAS_UNLOCK(la
);
2614 Code to support firewall punching. This shouldn't really be in this
2615 file, but making variables global is evil too.
2618 /* Firewall include files */
2620 #include <netinet/ip_fw.h>
2625 * helper function, updates the pointer to cmd with the length
2626 * of the current command, and also cleans up the first word of
2627 * the new command in case it has been clobbered before.
2630 next_cmd(ipfw_insn
* cmd
)
2633 bzero(cmd
, sizeof(*cmd
));
2638 * A function to fill simple commands of size 1.
2639 * Existing flags are preserved.
2642 fill_cmd(ipfw_insn
* cmd
, enum ipfw_opcodes opcode
, int size
,
2643 int flags
, u_int16_t arg
)
2645 cmd
->opcode
= opcode
;
2646 cmd
->len
= ((cmd
->len
| flags
) & (F_NOT
| F_OR
)) | (size
& F_LEN_MASK
);
2648 return next_cmd(cmd
);
2652 fill_ip(ipfw_insn
* cmd1
, enum ipfw_opcodes opcode
, u_int32_t addr
)
2654 ipfw_insn_ip
*cmd
= (ipfw_insn_ip
*) cmd1
;
2656 cmd
->addr
.s_addr
= addr
;
2657 return fill_cmd(cmd1
, opcode
, F_INSN_SIZE(ipfw_insn_u32
), 0, 0);
2661 fill_one_port(ipfw_insn
* cmd1
, enum ipfw_opcodes opcode
, u_int16_t port
)
2663 ipfw_insn_u16
*cmd
= (ipfw_insn_u16
*) cmd1
;
2665 cmd
->ports
[0] = cmd
->ports
[1] = port
;
2666 return fill_cmd(cmd1
, opcode
, F_INSN_SIZE(ipfw_insn_u16
), 0, 0);
2670 fill_rule(void *buf
, int bufsize
, int rulenum
,
2671 enum ipfw_opcodes action
, int proto
,
2672 struct in_addr sa
, u_int16_t sp
, struct in_addr da
, u_int16_t dp
)
2674 struct ip_fw
*rule
= (struct ip_fw
*)buf
;
2675 ipfw_insn
*cmd
= (ipfw_insn
*) rule
->cmd
;
2677 bzero(buf
, bufsize
);
2678 rule
->rulenum
= rulenum
;
2680 cmd
= fill_cmd(cmd
, O_PROTO
, F_INSN_SIZE(ipfw_insn
), 0, proto
);
2681 cmd
= fill_ip(cmd
, O_IP_SRC
, sa
.s_addr
);
2682 cmd
= fill_one_port(cmd
, O_IP_SRCPORT
, sp
);
2683 cmd
= fill_ip(cmd
, O_IP_DST
, da
.s_addr
);
2684 cmd
= fill_one_port(cmd
, O_IP_DSTPORT
, dp
);
2686 rule
->act_ofs
= (u_int32_t
*) cmd
- (u_int32_t
*) rule
->cmd
;
2687 cmd
= fill_cmd(cmd
, action
, F_INSN_SIZE(ipfw_insn
), 0, 0);
2689 rule
->cmd_len
= (u_int32_t
*) cmd
- (u_int32_t
*) rule
->cmd
;
2691 return ((char *)cmd
- (char *)buf
);
2694 static void ClearAllFWHoles(struct libalias
*la
);
2697 #define fw_setfield(la, field, num) \
2699 (field)[(num) - la->fireWallBaseNum] = 1; \
2700 } /*lint -save -e717 */ while(0)/* lint -restore */
2702 #define fw_clrfield(la, field, num) \
2704 (field)[(num) - la->fireWallBaseNum] = 0; \
2705 } /*lint -save -e717 */ while(0)/* lint -restore */
2707 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2710 InitPunchFW(struct libalias
*la
)
2713 LIBALIAS_LOCK_ASSERT(la
);
2714 la
->fireWallField
= kmalloc(la
->fireWallNumNums
,M_ALIAS
, M_WAITOK
| M_ZERO
);
2715 if (la
->fireWallField
) {
2716 memset(la
->fireWallField
, 0, la
->fireWallNumNums
);
2717 if (la
->fireWallFD
< 0) {
2718 la
->fireWallFD
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
2720 ClearAllFWHoles(la
);
2721 la
->fireWallActiveNum
= la
->fireWallBaseNum
;
2726 UninitPunchFW(struct libalias
*la
)
2729 LIBALIAS_LOCK_ASSERT(la
);
2730 ClearAllFWHoles(la
);
2731 if (la
->fireWallFD
>= 0)
2732 close(la
->fireWallFD
);
2733 la
->fireWallFD
= -1;
2734 if (la
->fireWallField
)
2735 kfree(la
->fireWallField
,M_ALIAS
);
2736 la
->fireWallField
= NULL
;
2737 la
->packetAliasMode
&= ~PKT_ALIAS_PUNCH_FW
;
2740 /* Make a certain link go through the firewall */
2742 PunchFWHole(struct alias_link
*lnk
)
2744 struct libalias
*la
;
2745 int r
; /* Result code */
2746 struct ip_fw rule
; /* On-the-fly built rule */
2747 int fwhole
; /* Where to punch hole */
2749 LIBALIAS_LOCK_ASSERT(la
);
2752 /* Don't do anything unless we are asked to */
2753 if (!(la
->packetAliasMode
& PKT_ALIAS_PUNCH_FW
) ||
2754 la
->fireWallFD
< 0 ||
2755 lnk
->link_type
!= LINK_TCP
)
2758 memset(&rule
, 0, sizeof rule
);
2762 /* Find empty slot */
2763 for (fwhole
= la
->fireWallActiveNum
;
2764 fwhole
< la
->fireWallBaseNum
+ la
->fireWallNumNums
&&
2765 fw_tstfield(la
, la
->fireWallField
, fwhole
);
2767 if (fwhole
== la
->fireWallBaseNum
+ la
->fireWallNumNums
) {
2768 for (fwhole
= la
->fireWallBaseNum
;
2769 fwhole
< la
->fireWallActiveNum
&&
2770 fw_tstfield(la
, la
->fireWallField
, fwhole
);
2772 if (fwhole
== la
->fireWallActiveNum
) {
2773 /* No rule point empty - we can't punch more holes. */
2774 la
->fireWallActiveNum
= la
->fireWallBaseNum
;
2775 #ifdef LIBALIAS_DEBUG
2776 fprintf(stderr
, "libalias: Unable to create firewall hole!\n");
2781 /* Start next search at next position */
2782 la
->fireWallActiveNum
= fwhole
+ 1;
2785 * generate two rules of the form
2787 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2788 * accept tcp from DAddr DPort to OAddr OPort
2790 if (GetOriginalPort(lnk
) != 0 && GetDestPort(lnk
) != 0) {
2791 u_int32_t rulebuf
[255];
2794 i
= fill_rule(rulebuf
, sizeof(rulebuf
), fwhole
,
2795 O_ACCEPT
, IPPROTO_TCP
,
2796 GetOriginalAddress(lnk
), ntohs(GetOriginalPort(lnk
)),
2797 GetDestAddress(lnk
), ntohs(GetDestPort(lnk
)));
2798 r
= setsockopt(la
->fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, rulebuf
, i
);
2800 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2802 i
= fill_rule(rulebuf
, sizeof(rulebuf
), fwhole
,
2803 O_ACCEPT
, IPPROTO_TCP
,
2804 GetDestAddress(lnk
), ntohs(GetDestPort(lnk
)),
2805 GetOriginalAddress(lnk
), ntohs(GetOriginalPort(lnk
)));
2806 r
= setsockopt(la
->fireWallFD
, IPPROTO_IP
, IP_FW_ADD
, rulebuf
, i
);
2808 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2811 /* Indicate hole applied */
2812 lnk
->data
.tcp
->fwhole
= fwhole
;
2813 fw_setfield(la
, la
->fireWallField
, fwhole
);
2816 /* Remove a hole in a firewall associated with a particular alias
2817 lnk. Calling this too often is harmless. */
2819 ClearFWHole(struct alias_link
*lnk
)
2821 struct libalias
*la
;
2823 LIBALIAS_LOCK_ASSERT(la
);
2825 if (lnk
->link_type
== LINK_TCP
) {
2826 int fwhole
= lnk
->data
.tcp
->fwhole
; /* Where is the firewall
2833 memset(&rule
, 0, sizeof rule
); /* useless for ipfw2 */
2834 while (!setsockopt(la
->fireWallFD
, IPPROTO_IP
, IP_FW_DEL
,
2835 &fwhole
, sizeof fwhole
));
2836 fw_clrfield(la
, la
->fireWallField
, fwhole
);
2837 lnk
->data
.tcp
->fwhole
= -1;
2841 /* Clear out the entire range dedicated to firewall holes. */
2843 ClearAllFWHoles(struct libalias
*la
)
2845 struct ip_fw rule
; /* On-the-fly built rule */
2848 LIBALIAS_LOCK_ASSERT(la
);
2849 if (la
->fireWallFD
< 0)
2852 memset(&rule
, 0, sizeof rule
);
2853 for (i
= la
->fireWallBaseNum
; i
< la
->fireWallBaseNum
+ la
->fireWallNumNums
; i
++) {
2856 while (!setsockopt(la
->fireWallFD
, IPPROTO_IP
, IP_FW_DEL
, &r
, sizeof r
));
2858 /* XXX: third arg correct here ? /phk */
2859 memset(la
->fireWallField
, 0, la
->fireWallNumNums
);
2865 LibAliasSetFWBase(struct libalias
*la
, unsigned int base
, unsigned int num
)
2870 la
->fireWallBaseNum
= base
;
2871 la
->fireWallNumNums
= num
;
2873 LIBALIAS_UNLOCK(la
);
2877 LibAliasSetSkinnyPort(struct libalias
*la
, unsigned int port
)
2881 la
->skinnyPort
= port
;
2882 LIBALIAS_UNLOCK(la
);