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$");
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>
148 #include <sys/types.h>
151 #include <sys/errno.h>
152 #include <sys/queue.h>
153 #include <sys/socket.h>
154 #include <sys/time.h>
157 #include <sys/systm.h>
158 #include <sys/kernel.h>
159 #include <sys/malloc.h>
160 #include <sys/module.h>
165 #include <arpa/inet.h>
168 /* BSD network include files */
169 #include <netinet/in_systm.h>
170 #include <netinet/in.h>
171 #include <netinet/ip.h>
172 #include <netinet/tcp.h>
175 #include <netinet/libalias/alias.h>
176 #include <netinet/libalias/alias_local.h>
179 #include "alias_local.h"
182 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
186 Constants (note: constants are also defined
187 near relevant functions or structs)
190 /* Parameters used for cleanup of expired links */
191 #define ALIAS_CLEANUP_INTERVAL_SECS 60
192 #define ALIAS_CLEANUP_MAX_SPOKES 30
194 /* Timeouts (in seconds) for different link types */
195 #define ICMP_EXPIRE_TIME 60
196 #define UDP_EXPIRE_TIME 60
197 #define PROTO_EXPIRE_TIME 60
198 #define FRAGMENT_ID_EXPIRE_TIME 10
199 #define FRAGMENT_PTR_EXPIRE_TIME 30
201 /* TCP link expire time for different cases */
202 /* When the link has been used and closed - minimal grace time to
203 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
204 #ifndef TCP_EXPIRE_DEAD
205 #define TCP_EXPIRE_DEAD 10
208 /* When the link has been used and closed on one side - the other side
209 is allowed to still send data */
210 #ifndef TCP_EXPIRE_SINGLEDEAD
211 #define TCP_EXPIRE_SINGLEDEAD 90
214 /* When the link isn't yet up */
215 #ifndef TCP_EXPIRE_INITIAL
216 #define TCP_EXPIRE_INITIAL 300
219 /* When the link is up */
220 #ifndef TCP_EXPIRE_CONNECTED
221 #define TCP_EXPIRE_CONNECTED 86400
225 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
226 These constants can be anything except zero, which indicates an
227 unknown port number. */
229 #define NO_DEST_PORT 1
230 #define NO_SRC_PORT 1
236 The fundamental data structure used in this program is
237 "struct alias_link". Whenever a TCP connection is made,
238 a UDP datagram is sent out, or an ICMP echo request is made,
239 a link record is made (if it has not already been created).
240 The link record is identified by the source address/port
241 and the destination address/port. In the case of an ICMP
242 echo request, the source port is treated as being equivalent
243 with the 16-bit ID number of the ICMP packet.
245 The link record also can store some auxiliary data. For
246 TCP connections that have had sequence and acknowledgment
247 modifications, data space is available to track these changes.
248 A state field is used to keep track in changes to the TCP
249 connection state. ID numbers of fragments can also be
250 stored in the auxiliary space. Pointers to unresolved
251 fragments can also be stored.
253 The link records support two independent chainings. Lookup
254 tables for input and out tables hold the initial pointers
255 the link chains. On input, the lookup table indexes on alias
256 port and link type. On output, the lookup table indexes on
257 source address, destination address, source port, destination
261 struct ack_data_record { /* used to save changes to ACK/sequence
269 struct tcp_state { /* Information about TCP connection */
270 int in; /* State for outside -> inside */
271 int out; /* State for inside -> outside */
272 int index; /* Index to ACK data array */
273 int ack_modified; /* Indicates whether ACK and
274 * sequence numbers */
278 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
279 * saved for a modified TCP stream */
281 struct tcp_state state;
282 struct ack_data_record ack[N_LINK_TCP_DATA];
283 int fwhole; /* Which firewall record is used for this
287 struct server { /* LSNAT server pool (circular list) */
293 struct alias_link { /* Main data structure */
295 struct in_addr src_addr; /* Address and port information */
296 struct in_addr dst_addr;
297 struct in_addr alias_addr;
298 struct in_addr proxy_addr;
303 struct server *server;
305 int link_type; /* Type of link: TCP, UDP, ICMP,
308 /* values for link_type */
309 #define LINK_ICMP IPPROTO_ICMP
310 #define LINK_UDP IPPROTO_UDP
311 #define LINK_TCP IPPROTO_TCP
312 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
313 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
314 #define LINK_ADDR (IPPROTO_MAX + 3)
315 #define LINK_PPTP (IPPROTO_MAX + 4)
317 int flags; /* indicates special characteristics */
318 int pflags; /* protocol-specific flags */
321 #define LINK_UNKNOWN_DEST_PORT 0x01
322 #define LINK_UNKNOWN_DEST_ADDR 0x02
323 #define LINK_PERMANENT 0x04
324 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
325 #define LINK_UNFIREWALLED 0x08
327 int timestamp; /* Time link was last accessed */
328 int expire_time; /* Expire time for link */
329 #ifndef NO_USE_SOCKETS
330 int sockfd; /* socket descriptor */
332 LIST_ENTRY (alias_link) list_out; /* Linked list of
334 LIST_ENTRY (alias_link) list_in; /* input and output
337 union { /* Auxiliary data */
339 struct in_addr frag_addr;
344 /* Clean up procedure. */
345 static void finishoff(void);
347 /* Kernel module definition. */
349 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
351 MODULE_VERSION(libalias, 1);
354 alias_mod_handler(module_t mod, int type, void *data)
374 static moduledata_t alias_mod = {
375 "alias", alias_mod_handler, NULL
378 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
381 /* Internal utility routines (used only in alias_db.c)
383 Lookup table starting points:
384 StartPointIn() -- link table initial search point for
386 StartPointOut() -- link table initial search point for
390 SeqDiff() -- difference between two TCP sequences
391 ShowAliasStats() -- send alias statistics to a monitor file
395 /* Local prototypes */
396 static u_int StartPointIn(struct in_addr, u_short, int);
399 StartPointOut(struct in_addr, struct in_addr,
400 u_short, u_short, int);
402 static int SeqDiff(u_long, u_long);
405 /* Firewall control */
406 static void InitPunchFW(struct libalias *);
407 static void UninitPunchFW(struct libalias *);
408 static void ClearFWHole(struct alias_link *);
413 /* Log file control */
414 static void ShowAliasStats(struct libalias *);
415 static void InitPacketAliasLog(struct libalias *);
416 static void UninitPacketAliasLog(struct libalias *);
420 StartPointIn(struct in_addr alias_addr,
426 n = alias_addr.s_addr;
427 if (link_type != LINK_PPTP)
430 return (n % LINK_TABLE_IN_SIZE);
435 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
436 u_short src_port, u_short dst_port, int link_type)
441 n += dst_addr.s_addr;
442 if (link_type != LINK_PPTP) {
448 return (n % LINK_TABLE_OUT_SIZE);
453 SeqDiff(u_long x, u_long y)
455 /* Return the difference between two TCP sequence numbers */
458 This function is encapsulated in case there are any unusual
459 arithmetic conditions that need to be considered.
462 return (ntohl(y) - ntohl(x));
468 ShowAliasStats(struct libalias *la)
470 /* Used for debugging */
472 if (la->monitorFile) {
473 fprintf(la->monitorFile,
474 "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
480 la->fragmentIdLinkCount,
481 la->fragmentPtrLinkCount);
483 fprintf(la->monitorFile, " / tot=%d (sock=%d)\n",
484 la->icmpLinkCount + la->udpLinkCount
488 + la->fragmentIdLinkCount
489 + la->fragmentPtrLinkCount,
492 fflush(la->monitorFile);
497 /* Internal routines for finding, deleting and adding links
500 GetNewPort() -- find and reserve new alias port number
501 GetSocket() -- try to allocate a socket for a given port
503 Link creation and deletion:
504 CleanupAliasData() - remove all link chains from lookup table
505 IncrementalCleanup() - look for stale links in a single chain
506 DeleteLink() - remove link
508 ReLink() - change link
511 FindLinkOut() - find link for outgoing packets
512 FindLinkIn() - find link for incoming packets
515 FindNewPortGroup() - find an available group of ports
518 /* Local prototypes */
519 static int GetNewPort(struct libalias *, struct alias_link *, int);
520 #ifndef NO_USE_SOCKETS
521 static u_short GetSocket(struct libalias *, u_short, int *, int);
523 static void CleanupAliasData(struct libalias *);
525 static void IncrementalCleanup(struct libalias *);
527 static void DeleteLink(struct alias_link *);
529 static struct alias_link *
530 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
531 u_short, u_short, int, int);
533 static struct alias_link *
534 ReLink(struct alias_link *,
535 struct in_addr, struct in_addr, struct in_addr,
536 u_short, u_short, int, int);
538 static struct alias_link *
539 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
541 static struct alias_link *
542 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
545 #define ALIAS_PORT_BASE 0x08000
546 #define ALIAS_PORT_MASK 0x07fff
547 #define ALIAS_PORT_MASK_EVEN 0x07ffe
548 #define GET_NEW_PORT_MAX_ATTEMPTS 20
550 #define GET_ALIAS_PORT -1
551 #define GET_ALIAS_ID GET_ALIAS_PORT
553 #define FIND_EVEN_ALIAS_BASE 1
555 /* GetNewPort() allocates port numbers. Note that if a port number
556 is already in use, that does not mean that it cannot be used by
557 another link concurrently. This is because GetNewPort() looks for
558 unused triplets: (dest addr, dest port, alias port). */
561 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
569 Description of alias_port_param for GetNewPort(). When
570 this parameter is zero or positive, it precisely specifies
571 the port number. GetNewPort() will return this number
572 without check that it is in use.
574 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
575 selected port number.
578 if (alias_port_param == GET_ALIAS_PORT) {
580 * The aliasing port is automatically selected by one of
583 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
585 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
587 * When the PKT_ALIAS_SAME_PORTS option is chosen,
588 * the first try will be the actual source port. If
589 * this is already in use, the remainder of the
590 * trials will be random.
592 port_net = lnk->src_port;
593 port_sys = ntohs(port_net);
595 /* First trial and all subsequent are random. */
596 port_sys = random() & ALIAS_PORT_MASK;
597 port_sys += ALIAS_PORT_BASE;
598 port_net = htons(port_sys);
600 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
601 lnk->alias_port = (u_short) alias_port_param;
604 #ifdef LIBALIAS_DEBUG
605 fprintf(stderr, "PacketAlias/GetNewPort(): ");
606 fprintf(stderr, "input parameter error\n");
612 /* Port number search */
613 for (i = 0; i < max_trials; i++) {
615 struct alias_link *search_result;
617 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
618 lnk->dst_port, port_net,
621 if (search_result == NULL)
623 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
624 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
630 #ifndef NO_USE_SOCKETS
631 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
632 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
633 && ((lnk->link_type == LINK_TCP) ||
634 (lnk->link_type == LINK_UDP))) {
635 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
636 lnk->alias_port = port_net;
641 lnk->alias_port = port_net;
643 #ifndef NO_USE_SOCKETS
647 port_sys = random() & ALIAS_PORT_MASK;
648 port_sys += ALIAS_PORT_BASE;
649 port_net = htons(port_sys);
652 #ifdef LIBALIAS_DEBUG
653 fprintf(stderr, "PacketAlias/GetnewPort(): ");
654 fprintf(stderr, "could not find free port\n");
660 #ifndef NO_USE_SOCKETS
662 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
666 struct sockaddr_in sock_addr;
668 if (link_type == LINK_TCP)
669 sock = socket(AF_INET, SOCK_STREAM, 0);
670 else if (link_type == LINK_UDP)
671 sock = socket(AF_INET, SOCK_DGRAM, 0);
673 #ifdef LIBALIAS_DEBUG
674 fprintf(stderr, "PacketAlias/GetSocket(): ");
675 fprintf(stderr, "incorrect link type\n");
681 #ifdef LIBALIAS_DEBUG
682 fprintf(stderr, "PacketAlias/GetSocket(): ");
683 fprintf(stderr, "socket() error %d\n", *sockfd);
687 sock_addr.sin_family = AF_INET;
688 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
689 sock_addr.sin_port = port_net;
692 (struct sockaddr *)&sock_addr,
705 /* FindNewPortGroup() returns a base port number for an available
706 range of contiguous port numbers. Note that if a port number
707 is already in use, that does not mean that it cannot be used by
708 another link concurrently. This is because FindNewPortGroup()
709 looks for unused triplets: (dest addr, dest port, alias port). */
712 FindNewPortGroup(struct libalias *la,
713 struct in_addr dst_addr,
714 struct in_addr alias_addr,
727 * Get link_type from protocol
732 link_type = LINK_UDP;
735 link_type = LINK_TCP;
743 * The aliasing port is automatically selected by one of two
746 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
748 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
750 * When the ALIAS_SAME_PORTS option is chosen, the first
751 * try will be the actual source port. If this is already
752 * in use, the remainder of the trials will be random.
754 port_sys = ntohs(src_port);
758 /* First trial and all subsequent are random. */
759 if (align == FIND_EVEN_ALIAS_BASE)
760 port_sys = random() & ALIAS_PORT_MASK_EVEN;
762 port_sys = random() & ALIAS_PORT_MASK;
764 port_sys += ALIAS_PORT_BASE;
767 /* Port number search */
768 for (i = 0; i < max_trials; i++) {
770 struct alias_link *search_result;
772 for (j = 0; j < port_count; j++)
773 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
774 dst_port, htons(port_sys + j),
778 /* Found a good range, return base */
780 return (htons(port_sys));
782 /* Find a new base to try */
783 if (align == FIND_EVEN_ALIAS_BASE)
784 port_sys = random() & ALIAS_PORT_MASK_EVEN;
786 port_sys = random() & ALIAS_PORT_MASK;
788 port_sys += ALIAS_PORT_BASE;
791 #ifdef LIBALIAS_DEBUG
792 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
793 fprintf(stderr, "could not find free port(s)\n");
800 CleanupAliasData(struct libalias *la)
802 struct alias_link *lnk;
806 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
807 lnk = LIST_FIRST(&la->linkTableOut[i]);
808 while (lnk != NULL) {
809 struct alias_link *link_next;
811 link_next = LIST_NEXT(lnk, list_out);
818 la->cleanupIndex = 0;
823 IncrementalCleanup(struct libalias *la)
826 struct alias_link *lnk;
829 lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
830 while (lnk != NULL) {
832 struct alias_link *link_next;
834 link_next = LIST_NEXT(lnk, list_out);
835 idelta = la->timeStamp - lnk->timestamp;
836 switch (lnk->link_type) {
838 if (idelta > lnk->expire_time) {
839 struct tcp_dat *tcp_aux;
841 tcp_aux = lnk->data.tcp;
842 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
843 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) {
850 if (idelta > lnk->expire_time) {
859 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
860 la->cleanupIndex = 0;
864 DeleteLink(struct alias_link *lnk)
866 struct libalias *la = lnk->la;
868 /* Don't do anything if the link is marked permanent */
869 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
873 /* Delete associated firewall hole, if any */
877 /* Free memory allocated for LSNAT server pool */
878 if (lnk->server != NULL) {
879 struct server *head, *curr, *next;
881 head = curr = lnk->server;
885 } while ((curr = next) != head);
887 /* Adjust output table pointers */
888 LIST_REMOVE(lnk, list_out);
890 /* Adjust input table pointers */
891 LIST_REMOVE(lnk, list_in);
892 #ifndef NO_USE_SOCKETS
893 /* Close socket, if one has been allocated */
894 if (lnk->sockfd != -1) {
899 /* Link-type dependent cleanup */
900 switch (lnk->link_type) {
914 case LINK_FRAGMENT_ID:
915 la->fragmentIdLinkCount--;
917 case LINK_FRAGMENT_PTR:
918 la->fragmentPtrLinkCount--;
919 if (lnk->data.frag_ptr != NULL)
920 free(lnk->data.frag_ptr);
925 la->protoLinkCount--;
933 /* Write statistics, if logging enabled */
934 if (la->packetAliasMode & PKT_ALIAS_LOG) {
941 static struct alias_link *
942 AddLink(struct libalias *la, struct in_addr src_addr,
943 struct in_addr dst_addr,
944 struct in_addr alias_addr,
947 int alias_port_param, /* if less than zero, alias */
949 { /* port will be automatically *//* chosen.
951 u_int start_point; /* zero, equal to alias port */
952 struct alias_link *lnk;
954 lnk = malloc(sizeof(struct alias_link));
956 /* Basic initialization */
958 lnk->src_addr = src_addr;
959 lnk->dst_addr = dst_addr;
960 lnk->alias_addr = alias_addr;
961 lnk->proxy_addr.s_addr = INADDR_ANY;
962 lnk->src_port = src_port;
963 lnk->dst_port = dst_port;
966 lnk->link_type = link_type;
967 #ifndef NO_USE_SOCKETS
972 lnk->timestamp = la->timeStamp;
974 /* Expiration time */
977 lnk->expire_time = ICMP_EXPIRE_TIME;
980 lnk->expire_time = UDP_EXPIRE_TIME;
983 lnk->expire_time = TCP_EXPIRE_INITIAL;
986 lnk->flags |= LINK_PERMANENT; /* no timeout. */
988 case LINK_FRAGMENT_ID:
989 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
991 case LINK_FRAGMENT_PTR:
992 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
997 lnk->expire_time = PROTO_EXPIRE_TIME;
1001 /* Determine alias flags */
1002 if (dst_addr.s_addr == INADDR_ANY)
1003 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
1005 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1007 /* Determine alias port */
1008 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1012 /* Link-type dependent initialization */
1013 switch (link_type) {
1014 struct tcp_dat *aux_tcp;
1017 la->icmpLinkCount++;
1023 aux_tcp = malloc(sizeof(struct tcp_dat));
1024 if (aux_tcp != NULL) {
1028 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1029 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1030 aux_tcp->state.index = 0;
1031 aux_tcp->state.ack_modified = 0;
1032 for (i = 0; i < N_LINK_TCP_DATA; i++)
1033 aux_tcp->ack[i].active = 0;
1034 aux_tcp->fwhole = -1;
1035 lnk->data.tcp = aux_tcp;
1037 #ifdef LIBALIAS_DEBUG
1038 fprintf(stderr, "PacketAlias/AddLink: ");
1039 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1046 la->pptpLinkCount++;
1048 case LINK_FRAGMENT_ID:
1049 la->fragmentIdLinkCount++;
1051 case LINK_FRAGMENT_PTR:
1052 la->fragmentPtrLinkCount++;
1057 la->protoLinkCount++;
1061 /* Set up pointers for output lookup table */
1062 start_point = StartPointOut(src_addr, dst_addr,
1063 src_port, dst_port, link_type);
1064 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1066 /* Set up pointers for input lookup table */
1067 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1068 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1070 #ifdef LIBALIAS_DEBUG
1071 fprintf(stderr, "PacketAlias/AddLink(): ");
1072 fprintf(stderr, "malloc() call failed.\n");
1076 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1083 static struct alias_link *
1084 ReLink(struct alias_link *old_lnk,
1085 struct in_addr src_addr,
1086 struct in_addr dst_addr,
1087 struct in_addr alias_addr,
1090 int alias_port_param, /* if less than zero, alias */
1092 { /* port will be automatically *//* chosen.
1093 * If greater than */
1094 struct alias_link *new_lnk; /* zero, equal to alias port */
1095 struct libalias *la = old_lnk->la;
1097 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1098 src_port, dst_port, alias_port_param,
1101 if (new_lnk != NULL &&
1102 old_lnk->link_type == LINK_TCP &&
1103 old_lnk->data.tcp->fwhole > 0) {
1104 PunchFWHole(new_lnk);
1107 DeleteLink(old_lnk);
1111 static struct alias_link *
1112 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1113 struct in_addr dst_addr,
1117 int replace_partial_links)
1120 struct alias_link *lnk;
1122 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1123 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1124 if (lnk->src_addr.s_addr == src_addr.s_addr
1125 && lnk->server == NULL
1126 && lnk->dst_addr.s_addr == dst_addr.s_addr
1127 && lnk->dst_port == dst_port
1128 && lnk->src_port == src_port
1129 && lnk->link_type == link_type) {
1130 lnk->timestamp = la->timeStamp;
1135 /* Search for partially specified links. */
1136 if (lnk == NULL && replace_partial_links) {
1137 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1138 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1141 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1142 dst_port, link_type, 0);
1145 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1146 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1151 src_addr, dst_addr, lnk->alias_addr,
1152 src_port, dst_port, lnk->alias_port,
1159 static struct alias_link *
1160 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1161 struct in_addr dst_addr,
1165 int replace_partial_links)
1167 struct alias_link *lnk;
1169 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1170 link_type, replace_partial_links);
1174 * The following allows permanent links to be specified as
1175 * using the default source address (i.e. device interface
1176 * address) without knowing in advance what that address
1179 if (la->aliasAddress.s_addr != INADDR_ANY &&
1180 src_addr.s_addr == la->aliasAddress.s_addr) {
1181 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1182 link_type, replace_partial_links);
1189 static struct alias_link *
1190 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1191 struct in_addr alias_addr,
1195 int replace_partial_links)
1199 struct alias_link *lnk;
1200 struct alias_link *lnk_fully_specified;
1201 struct alias_link *lnk_unknown_all;
1202 struct alias_link *lnk_unknown_dst_addr;
1203 struct alias_link *lnk_unknown_dst_port;
1205 /* Initialize pointers */
1206 lnk_fully_specified = NULL;
1207 lnk_unknown_all = NULL;
1208 lnk_unknown_dst_addr = NULL;
1209 lnk_unknown_dst_port = NULL;
1211 /* If either the dest addr or port is unknown, the search
1212 loop will have to know about this. */
1215 if (dst_addr.s_addr == INADDR_ANY)
1216 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1218 flags_in |= LINK_UNKNOWN_DEST_PORT;
1221 start_point = StartPointIn(alias_addr, alias_port, link_type);
1222 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1225 flags = flags_in | lnk->flags;
1226 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1227 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1228 && lnk->alias_port == alias_port
1229 && lnk->dst_addr.s_addr == dst_addr.s_addr
1230 && lnk->dst_port == dst_port
1231 && lnk->link_type == link_type) {
1232 lnk_fully_specified = lnk;
1235 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1236 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1237 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1238 && lnk->alias_port == alias_port
1239 && lnk->link_type == link_type) {
1240 if (lnk_unknown_all == NULL)
1241 lnk_unknown_all = lnk;
1243 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1244 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1245 && lnk->alias_port == alias_port
1246 && lnk->link_type == link_type
1247 && lnk->dst_port == dst_port) {
1248 if (lnk_unknown_dst_addr == NULL)
1249 lnk_unknown_dst_addr = lnk;
1251 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1252 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1253 && lnk->alias_port == alias_port
1254 && lnk->link_type == link_type
1255 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1256 if (lnk_unknown_dst_port == NULL)
1257 lnk_unknown_dst_port = lnk;
1264 if (lnk_fully_specified != NULL) {
1265 lnk_fully_specified->timestamp = la->timeStamp;
1266 lnk = lnk_fully_specified;
1267 } else if (lnk_unknown_dst_port != NULL)
1268 lnk = lnk_unknown_dst_port;
1269 else if (lnk_unknown_dst_addr != NULL)
1270 lnk = lnk_unknown_dst_addr;
1271 else if (lnk_unknown_all != NULL)
1272 lnk = lnk_unknown_all;
1276 if (replace_partial_links &&
1277 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1278 struct in_addr src_addr;
1281 if (lnk->server != NULL) { /* LSNAT link */
1282 src_addr = lnk->server->addr;
1283 src_port = lnk->server->port;
1284 lnk->server = lnk->server->next;
1286 src_addr = lnk->src_addr;
1287 src_port = lnk->src_port;
1291 src_addr, dst_addr, alias_addr,
1292 src_port, dst_port, alias_port,
1298 static struct alias_link *
1299 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1300 struct in_addr alias_addr,
1304 int replace_partial_links)
1306 struct alias_link *lnk;
1308 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1309 link_type, replace_partial_links);
1313 * The following allows permanent links to be specified as
1314 * using the default aliasing address (i.e. device
1315 * interface address) without knowing in advance what that
1318 if (la->aliasAddress.s_addr != INADDR_ANY &&
1319 alias_addr.s_addr == la->aliasAddress.s_addr) {
1320 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1321 link_type, replace_partial_links);
1330 /* External routines for finding/adding links
1332 -- "external" means outside alias_db.c, but within alias*.c --
1334 FindIcmpIn(), FindIcmpOut()
1335 FindFragmentIn1(), FindFragmentIn2()
1336 AddFragmentPtrLink(), FindFragmentPtr()
1337 FindProtoIn(), FindProtoOut()
1338 FindUdpTcpIn(), FindUdpTcpOut()
1339 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1340 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1341 FindOriginalAddress(), FindAliasAddress()
1343 (prototypes in alias_local.h)
1348 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1349 struct in_addr alias_addr,
1353 struct alias_link *lnk;
1355 lnk = FindLinkIn(la, dst_addr, alias_addr,
1356 NO_DEST_PORT, id_alias,
1358 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1359 struct in_addr target_addr;
1361 target_addr = FindOriginalAddress(la, alias_addr);
1362 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1363 id_alias, NO_DEST_PORT, id_alias,
1371 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1372 struct in_addr dst_addr,
1376 struct alias_link *lnk;
1378 lnk = FindLinkOut(la, src_addr, dst_addr,
1381 if (lnk == NULL && create) {
1382 struct in_addr alias_addr;
1384 alias_addr = FindAliasAddress(la, src_addr);
1385 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1386 id, NO_DEST_PORT, GET_ALIAS_ID,
1394 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1395 struct in_addr alias_addr,
1398 struct alias_link *lnk;
1400 lnk = FindLinkIn(la, dst_addr, alias_addr,
1401 NO_DEST_PORT, ip_id,
1402 LINK_FRAGMENT_ID, 0);
1405 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1406 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1414 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1416 struct in_addr alias_addr, /* is not found. */
1419 return FindLinkIn(la, dst_addr, alias_addr,
1420 NO_DEST_PORT, ip_id,
1421 LINK_FRAGMENT_ID, 0);
1426 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1429 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1430 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1436 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1439 return FindLinkIn(la, dst_addr, la->nullAddress,
1440 NO_DEST_PORT, ip_id,
1441 LINK_FRAGMENT_PTR, 0);
1446 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1447 struct in_addr alias_addr,
1450 struct alias_link *lnk;
1452 lnk = FindLinkIn(la, dst_addr, alias_addr,
1456 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1457 struct in_addr target_addr;
1459 target_addr = FindOriginalAddress(la, alias_addr);
1460 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1461 NO_SRC_PORT, NO_DEST_PORT, 0,
1469 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1470 struct in_addr dst_addr,
1473 struct alias_link *lnk;
1475 lnk = FindLinkOut(la, src_addr, dst_addr,
1476 NO_SRC_PORT, NO_DEST_PORT,
1480 struct in_addr alias_addr;
1482 alias_addr = FindAliasAddress(la, src_addr);
1483 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1484 NO_SRC_PORT, NO_DEST_PORT, 0,
1492 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1493 struct in_addr alias_addr,
1500 struct alias_link *lnk;
1504 link_type = LINK_UDP;
1507 link_type = LINK_TCP;
1514 lnk = FindLinkIn(la, dst_addr, alias_addr,
1515 dst_port, alias_port,
1518 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1519 struct in_addr target_addr;
1521 target_addr = FindOriginalAddress(la, alias_addr);
1522 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1523 alias_port, dst_port, alias_port,
1531 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1532 struct in_addr dst_addr,
1539 struct alias_link *lnk;
1543 link_type = LINK_UDP;
1546 link_type = LINK_TCP;
1553 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1555 if (lnk == NULL && create) {
1556 struct in_addr alias_addr;
1558 alias_addr = FindAliasAddress(la, src_addr);
1559 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1560 src_port, dst_port, GET_ALIAS_PORT,
1568 AddPptp(struct libalias *la, struct in_addr src_addr,
1569 struct in_addr dst_addr,
1570 struct in_addr alias_addr,
1571 u_int16_t src_call_id)
1573 struct alias_link *lnk;
1575 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1576 src_call_id, 0, GET_ALIAS_PORT,
1584 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1585 struct in_addr dst_addr,
1586 u_int16_t src_call_id)
1589 struct alias_link *lnk;
1591 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1592 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1593 if (lnk->link_type == LINK_PPTP &&
1594 lnk->src_addr.s_addr == src_addr.s_addr &&
1595 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1596 lnk->src_port == src_call_id)
1604 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1605 struct in_addr dst_addr,
1606 u_int16_t dst_call_id)
1609 struct alias_link *lnk;
1611 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1612 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1613 if (lnk->link_type == LINK_PPTP &&
1614 lnk->src_addr.s_addr == src_addr.s_addr &&
1615 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1616 lnk->dst_port == dst_call_id)
1624 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1625 struct in_addr alias_addr,
1626 u_int16_t dst_call_id)
1629 struct alias_link *lnk;
1631 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1632 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1633 if (lnk->link_type == LINK_PPTP &&
1634 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1635 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1636 lnk->dst_port == dst_call_id)
1644 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1645 struct in_addr alias_addr,
1646 u_int16_t alias_call_id)
1648 struct alias_link *lnk;
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;
1671 link_type = LINK_UDP;
1674 link_type = LINK_TCP;
1681 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1684 struct in_addr alias_addr;
1686 alias_addr = FindAliasAddress(la, src_addr);
1687 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1688 src_port, 0, alias_port,
1696 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1698 struct alias_link *lnk;
1700 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1701 0, 0, LINK_ADDR, 0);
1703 la->newDefaultLink = 1;
1704 if (la->targetAddress.s_addr == INADDR_ANY)
1705 return (alias_addr);
1706 else if (la->targetAddress.s_addr == INADDR_NONE)
1707 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1708 la->aliasAddress : alias_addr;
1710 return (la->targetAddress);
1712 if (lnk->server != NULL) { /* LSNAT link */
1713 struct in_addr src_addr;
1715 src_addr = lnk->server->addr;
1716 lnk->server = lnk->server->next;
1718 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1719 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1720 la->aliasAddress : alias_addr;
1722 return (lnk->src_addr);
1728 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1730 struct alias_link *lnk;
1732 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1733 0, 0, LINK_ADDR, 0);
1735 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1736 la->aliasAddress : original_addr;
1738 if (lnk->alias_addr.s_addr == INADDR_ANY)
1739 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1740 la->aliasAddress : original_addr;
1742 return (lnk->alias_addr);
1747 /* External routines for getting or changing link data
1748 (external to alias_db.c, but internal to alias*.c)
1750 SetFragmentData(), GetFragmentData()
1751 SetFragmentPtr(), GetFragmentPtr()
1752 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1753 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1754 GetOriginalPort(), GetAliasPort()
1755 SetAckModified(), GetAckModified()
1756 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1757 SetProtocolFlags(), GetProtocolFlags()
1763 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1765 lnk->data.frag_addr = src_addr;
1770 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1772 *src_addr = lnk->data.frag_addr;
1777 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1779 lnk->data.frag_ptr = fptr;
1784 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1786 *fptr = lnk->data.frag_ptr;
1791 SetStateIn(struct alias_link *lnk, int state)
1793 /* TCP input state */
1795 case ALIAS_TCP_STATE_DISCONNECTED:
1796 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1797 lnk->expire_time = TCP_EXPIRE_DEAD;
1799 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1801 case ALIAS_TCP_STATE_CONNECTED:
1802 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1803 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1807 panic("libalias:SetStateIn() unknown state");
1812 lnk->data.tcp->state.in = state;
1817 SetStateOut(struct alias_link *lnk, int state)
1819 /* TCP output state */
1821 case ALIAS_TCP_STATE_DISCONNECTED:
1822 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1823 lnk->expire_time = TCP_EXPIRE_DEAD;
1825 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1827 case ALIAS_TCP_STATE_CONNECTED:
1828 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1829 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1833 panic("libalias:SetStateOut() unknown state");
1838 lnk->data.tcp->state.out = state;
1843 GetStateIn(struct alias_link *lnk)
1845 /* TCP input state */
1846 return (lnk->data.tcp->state.in);
1851 GetStateOut(struct alias_link *lnk)
1853 /* TCP output state */
1854 return (lnk->data.tcp->state.out);
1859 GetOriginalAddress(struct alias_link *lnk)
1861 if (lnk->src_addr.s_addr == INADDR_ANY)
1862 return (lnk->la->aliasAddress);
1864 return (lnk->src_addr);
1869 GetDestAddress(struct alias_link *lnk)
1871 return (lnk->dst_addr);
1876 GetAliasAddress(struct alias_link *lnk)
1878 if (lnk->alias_addr.s_addr == INADDR_ANY)
1879 return (lnk->la->aliasAddress);
1881 return (lnk->alias_addr);
1886 GetDefaultAliasAddress(struct libalias *la)
1888 return (la->aliasAddress);
1893 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1895 la->aliasAddress = alias_addr;
1900 GetOriginalPort(struct alias_link *lnk)
1902 return (lnk->src_port);
1907 GetAliasPort(struct alias_link *lnk)
1909 return (lnk->alias_port);
1914 GetDestPort(struct alias_link *lnk)
1916 return (lnk->dst_port);
1922 SetAckModified(struct alias_link *lnk)
1924 /* Indicate that ACK numbers have been modified in a TCP connection */
1925 lnk->data.tcp->state.ack_modified = 1;
1930 GetProxyAddress(struct alias_link *lnk)
1932 return (lnk->proxy_addr);
1937 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1939 lnk->proxy_addr = addr;
1944 GetProxyPort(struct alias_link *lnk)
1946 return (lnk->proxy_port);
1951 SetProxyPort(struct alias_link *lnk, u_short port)
1953 lnk->proxy_port = port;
1958 GetAckModified(struct alias_link *lnk)
1960 /* See if ACK numbers have been modified */
1961 return (lnk->data.tcp->state.ack_modified);
1966 GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
1969 Find out how much the ACK number has been altered for an incoming
1970 TCP packet. To do this, a circular list of ACK numbers where the TCP
1971 packet size was altered is searched.
1976 int delta, ack_diff_min;
1984 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1985 struct ack_data_record x;
1987 x = lnk->data.tcp->ack[i];
1988 if (x.active == 1) {
1991 ack_diff = SeqDiff(x.ack_new, ack);
1992 if (ack_diff >= 0) {
1993 if (ack_diff_min >= 0) {
1994 if (ack_diff < ack_diff_min) {
1996 ack_diff_min = ack_diff;
2000 ack_diff_min = ack_diff;
2010 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
2013 Find out how much the sequence number has been altered for an outgoing
2014 TCP packet. To do this, a circular list of ACK numbers where the TCP
2015 packet size was altered is searched.
2020 int delta, seq_diff_min;
2028 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2029 struct ack_data_record x;
2031 x = lnk->data.tcp->ack[i];
2032 if (x.active == 1) {
2035 seq_diff = SeqDiff(x.ack_old, seq);
2036 if (seq_diff >= 0) {
2037 if (seq_diff_min >= 0) {
2038 if (seq_diff < seq_diff_min) {
2040 seq_diff_min = seq_diff;
2044 seq_diff_min = seq_diff;
2054 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
2057 When a TCP packet has been altered in length, save this
2058 information in a circular list. If enough packets have
2059 been altered, then this list will begin to overwrite itself.
2063 struct ack_data_record x;
2064 int hlen, tlen, dlen;
2069 hlen = (pip->ip_hl + tc->th_off) << 2;
2070 tlen = ntohs(pip->ip_len);
2073 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2074 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2078 i = lnk->data.tcp->state.index;
2079 lnk->data.tcp->ack[i] = x;
2082 if (i == N_LINK_TCP_DATA)
2083 lnk->data.tcp->state.index = 0;
2085 lnk->data.tcp->state.index = i;
2089 SetExpire(struct alias_link *lnk, int expire)
2092 lnk->flags &= ~LINK_PERMANENT;
2094 } else if (expire == -1) {
2095 lnk->flags |= LINK_PERMANENT;
2096 } else if (expire > 0) {
2097 lnk->expire_time = expire;
2099 #ifdef LIBALIAS_DEBUG
2100 fprintf(stderr, "PacketAlias/SetExpire(): ");
2101 fprintf(stderr, "error in expire parameter\n");
2107 ClearCheckNewLink(struct libalias *la)
2109 la->newDefaultLink = 0;
2113 SetProtocolFlags(struct alias_link *lnk, int pflags)
2116 lnk->pflags = pflags;;
2120 GetProtocolFlags(struct alias_link *lnk)
2123 return (lnk->pflags);
2127 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2129 struct libalias *la = lnk->la;
2131 la->deleteAllLinks = 1;
2132 lnk = ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2133 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2134 la->deleteAllLinks = 0;
2138 /* Miscellaneous Functions
2141 InitPacketAliasLog()
2142 UninitPacketAliasLog()
2146 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2147 is called to find and remove timed-out aliasing links. Logic exists
2148 to sweep through the entire table and linked list structure
2151 (prototype in alias_local.h)
2155 HouseKeeping(struct libalias *la)
2164 * Save system time (seconds) in global variable timeStamp for use
2165 * by other functions. This is done so as not to unnecessarily
2166 * waste timeline by making system calls.
2169 la->timeStamp = time_uptime;
2171 gettimeofday(&tv, &tz);
2172 la->timeStamp = tv.tv_sec;
2175 /* Compute number of spokes (output table link chains) to cover */
2176 n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual;
2177 n100 *= la->timeStamp - la->lastCleanupTime;
2178 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2182 /* Handle different cases */
2183 if (n > ALIAS_CLEANUP_MAX_SPOKES) {
2184 n = ALIAS_CLEANUP_MAX_SPOKES;
2185 la->lastCleanupTime = la->timeStamp;
2186 la->houseKeepingResidual = 0;
2188 for (i = 0; i < n; i++)
2189 IncrementalCleanup(la);
2191 la->lastCleanupTime = la->timeStamp;
2192 la->houseKeepingResidual = n100 - 100 * n;
2194 for (i = 0; i < n; i++)
2195 IncrementalCleanup(la);
2197 #ifdef LIBALIAS_DEBUG
2198 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2199 fprintf(stderr, "something unexpected in time values\n");
2201 la->lastCleanupTime = la->timeStamp;
2202 la->houseKeepingResidual = 0;
2207 /* Init the log file and enable logging */
2209 InitPacketAliasLog(struct libalias *la)
2211 if ((~la->packetAliasMode & PKT_ALIAS_LOG)
2212 && (la->monitorFile = fopen("/var/log/alias.log", "w"))) {
2213 la->packetAliasMode |= PKT_ALIAS_LOG;
2214 fprintf(la->monitorFile,
2215 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2219 /* Close the log-file and disable logging. */
2221 UninitPacketAliasLog(struct libalias *la)
2223 if (la->monitorFile) {
2224 fclose(la->monitorFile);
2225 la->monitorFile = NULL;
2227 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2231 /* Outside world interfaces
2233 -- "outside world" means other than alias*.c routines --
2235 PacketAliasRedirectPort()
2236 PacketAliasAddServer()
2237 PacketAliasRedirectProto()
2238 PacketAliasRedirectAddr()
2239 PacketAliasRedirectDynamic()
2240 PacketAliasRedirectDelete()
2241 PacketAliasSetAddress()
2244 PacketAliasSetMode()
2246 (prototypes in alias.h)
2249 /* Redirection from a specific public addr:port to a
2250 private addr:port */
2252 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2253 struct in_addr dst_addr, u_short dst_port,
2254 struct in_addr alias_addr, u_short alias_port,
2258 struct alias_link *lnk;
2262 link_type = LINK_UDP;
2265 link_type = LINK_TCP;
2268 #ifdef LIBALIAS_DEBUG
2269 fprintf(stderr, "PacketAliasRedirectPort(): ");
2270 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2275 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2276 src_port, dst_port, alias_port,
2280 lnk->flags |= LINK_PERMANENT;
2282 #ifdef LIBALIAS_DEBUG
2284 fprintf(stderr, "PacketAliasRedirectPort(): "
2285 "call to AddLink() failed\n");
2292 /* Add server to the pool of servers */
2294 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2296 struct server *server;
2300 server = malloc(sizeof(struct server));
2302 if (server != NULL) {
2303 struct server *head;
2305 server->addr = addr;
2306 server->port = port;
2310 server->next = server;
2314 for (s = head; s->next != head; s = s->next);
2316 server->next = head;
2318 lnk->server = server;
2324 /* Redirect packets of a given IP protocol from a specific
2325 public address to a private address */
2327 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2328 struct in_addr dst_addr,
2329 struct in_addr alias_addr,
2332 struct alias_link *lnk;
2334 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2335 NO_SRC_PORT, NO_DEST_PORT, 0,
2339 lnk->flags |= LINK_PERMANENT;
2341 #ifdef LIBALIAS_DEBUG
2343 fprintf(stderr, "PacketAliasRedirectProto(): "
2344 "call to AddLink() failed\n");
2351 /* Static address translation */
2353 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2354 struct in_addr alias_addr)
2356 struct alias_link *lnk;
2358 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2363 lnk->flags |= LINK_PERMANENT;
2365 #ifdef LIBALIAS_DEBUG
2367 fprintf(stderr, "PacketAliasRedirectAddr(): "
2368 "call to AddLink() failed\n");
2376 /* Mark the aliasing link dynamic */
2378 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2383 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2386 lnk->flags &= ~LINK_PERMANENT;
2393 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2395 /* This is a dangerous function to put in the API,
2396 because an invalid pointer can crash the program. */
2398 la->deleteAllLinks = 1;
2400 la->deleteAllLinks = 0;
2405 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2407 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2408 && la->aliasAddress.s_addr != addr.s_addr)
2409 CleanupAliasData(la);
2411 la->aliasAddress = addr;
2416 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2418 la->targetAddress = target_addr;
2425 while (!LIST_EMPTY(&instancehead))
2426 LibAliasUninit(LIST_FIRST(&instancehead));
2430 LibAliasInit(struct libalias *la)
2439 la = calloc(sizeof *la, 1);
2443 #ifndef _KERNEL /* kernel cleans up on module unload */
2444 if (LIST_EMPTY(&instancehead))
2447 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2450 la->timeStamp = time_uptime;
2451 la->lastCleanupTime = time_uptime;
2453 gettimeofday(&tv, &tz);
2454 la->timeStamp = tv.tv_sec;
2455 la->lastCleanupTime = tv.tv_sec;
2457 la->houseKeepingResidual = 0;
2459 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2460 LIST_INIT(&la->linkTableOut[i]);
2461 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2462 LIST_INIT(&la->linkTableIn[i]);
2465 la->deleteAllLinks = 1;
2466 CleanupAliasData(la);
2467 la->deleteAllLinks = 0;
2470 la->aliasAddress.s_addr = INADDR_ANY;
2471 la->targetAddress.s_addr = INADDR_ANY;
2473 la->icmpLinkCount = 0;
2474 la->udpLinkCount = 0;
2475 la->tcpLinkCount = 0;
2476 la->pptpLinkCount = 0;
2477 la->protoLinkCount = 0;
2478 la->fragmentIdLinkCount = 0;
2479 la->fragmentPtrLinkCount = 0;
2482 la->cleanupIndex = 0;
2484 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2485 #ifndef NO_USE_SOCKETS
2486 | PKT_ALIAS_USE_SOCKETS
2488 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2490 la->fireWallFD = -1;
2496 LibAliasUninit(struct libalias *la)
2498 la->deleteAllLinks = 1;
2499 CleanupAliasData(la);
2500 la->deleteAllLinks = 0;
2502 UninitPacketAliasLog(la);
2507 LIST_REMOVE(la, instancelist);
2511 /* Change mode for some operations */
2514 struct libalias *la,
2515 unsigned int flags, /* Which state to bring flags to */
2516 unsigned int mask /* Mask of which flags to affect (use 0 to
2517 * do a probe for flag values) */
2521 /* Enable logging? */
2522 if (flags & mask & PKT_ALIAS_LOG) {
2523 InitPacketAliasLog(la); /* Do the enable */
2525 /* _Disable_ logging? */
2526 if (~flags & mask & PKT_ALIAS_LOG) {
2527 UninitPacketAliasLog(la);
2531 /* Start punching holes in the firewall? */
2532 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2535 /* Stop punching holes in the firewall? */
2536 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2541 /* Other flags can be set/cleared without special action */
2542 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2543 return (la->packetAliasMode);
2548 LibAliasCheckNewLink(struct libalias *la)
2550 return (la->newDefaultLink);
2557 Code to support firewall punching. This shouldn't really be in this
2558 file, but making variables global is evil too.
2561 /* Firewall include files */
2563 #include <netinet/ip_fw.h>
2568 * helper function, updates the pointer to cmd with the length
2569 * of the current command, and also cleans up the first word of
2570 * the new command in case it has been clobbered before.
2573 next_cmd(ipfw_insn * cmd)
2576 bzero(cmd, sizeof(*cmd));
2581 * A function to fill simple commands of size 1.
2582 * Existing flags are preserved.
2585 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2586 int flags, u_int16_t arg)
2588 cmd->opcode = opcode;
2589 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2591 return next_cmd(cmd);
2595 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2597 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2599 cmd->addr.s_addr = addr;
2600 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2604 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2606 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2608 cmd->ports[0] = cmd->ports[1] = port;
2609 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2613 fill_rule(void *buf, int bufsize, int rulenum,
2614 enum ipfw_opcodes action, int proto,
2615 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2617 struct ip_fw *rule = (struct ip_fw *)buf;
2618 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2620 bzero(buf, bufsize);
2621 rule->rulenum = rulenum;
2623 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2624 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2625 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2626 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2627 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2629 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2630 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2632 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2634 return ((char *)cmd - (char *)buf);
2637 static void ClearAllFWHoles(struct libalias *la);
2640 #define fw_setfield(la, field, num) \
2642 (field)[(num) - la->fireWallBaseNum] = 1; \
2643 } /*lint -save -e717 */ while(0)/* lint -restore */
2645 #define fw_clrfield(la, field, num) \
2647 (field)[(num) - la->fireWallBaseNum] = 0; \
2648 } /*lint -save -e717 */ while(0)/* lint -restore */
2650 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2653 InitPunchFW(struct libalias *la)
2656 la->fireWallField = malloc(la->fireWallNumNums);
2657 if (la->fireWallField) {
2658 memset(la->fireWallField, 0, la->fireWallNumNums);
2659 if (la->fireWallFD < 0) {
2660 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2662 ClearAllFWHoles(la);
2663 la->fireWallActiveNum = la->fireWallBaseNum;
2668 UninitPunchFW(struct libalias *la)
2670 ClearAllFWHoles(la);
2671 if (la->fireWallFD >= 0)
2672 close(la->fireWallFD);
2673 la->fireWallFD = -1;
2674 if (la->fireWallField)
2675 free(la->fireWallField);
2676 la->fireWallField = NULL;
2677 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2680 /* Make a certain link go through the firewall */
2682 PunchFWHole(struct alias_link *lnk)
2684 struct libalias *la;
2685 int r; /* Result code */
2686 struct ip_fw rule; /* On-the-fly built rule */
2687 int fwhole; /* Where to punch hole */
2691 /* Don't do anything unless we are asked to */
2692 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2693 la->fireWallFD < 0 ||
2694 lnk->link_type != LINK_TCP)
2697 memset(&rule, 0, sizeof rule);
2701 /* Find empty slot */
2702 for (fwhole = la->fireWallActiveNum;
2703 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2704 fw_tstfield(la, la->fireWallField, fwhole);
2706 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2707 for (fwhole = la->fireWallBaseNum;
2708 fwhole < la->fireWallActiveNum &&
2709 fw_tstfield(la, la->fireWallField, fwhole);
2711 if (fwhole == la->fireWallActiveNum) {
2712 /* No rule point empty - we can't punch more holes. */
2713 la->fireWallActiveNum = la->fireWallBaseNum;
2714 #ifdef LIBALIAS_DEBUG
2715 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2720 /* Start next search at next position */
2721 la->fireWallActiveNum = fwhole + 1;
2724 * generate two rules of the form
2726 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2727 * accept tcp from DAddr DPort to OAddr OPort
2729 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2730 u_int32_t rulebuf[255];
2733 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2734 O_ACCEPT, IPPROTO_TCP,
2735 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2736 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2737 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2739 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2741 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2742 O_ACCEPT, IPPROTO_TCP,
2743 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2744 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2745 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2747 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2750 /* Indicate hole applied */
2751 lnk->data.tcp->fwhole = fwhole;
2752 fw_setfield(la, la->fireWallField, fwhole);
2755 /* Remove a hole in a firewall associated with a particular alias
2756 lnk. Calling this too often is harmless. */
2758 ClearFWHole(struct alias_link *lnk)
2761 struct libalias *la;
2764 if (lnk->link_type == LINK_TCP) {
2765 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2772 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2773 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2774 &fwhole, sizeof fwhole));
2775 fw_clrfield(la, la->fireWallField, fwhole);
2776 lnk->data.tcp->fwhole = -1;
2780 /* Clear out the entire range dedicated to firewall holes. */
2782 ClearAllFWHoles(struct libalias *la)
2784 struct ip_fw rule; /* On-the-fly built rule */
2787 if (la->fireWallFD < 0)
2790 memset(&rule, 0, sizeof rule);
2791 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2794 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2796 /* XXX: third arg correct here ? /phk */
2797 memset(la->fireWallField, 0, la->fireWallNumNums);
2803 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2806 la->fireWallBaseNum = base;
2807 la->fireWallNumNums = num;
2812 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2814 la->skinnyPort = port;