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 <machine/stdarg.h>
147 #include <sys/param.h>
148 #include <sys/kernel.h>
149 #include <sys/module.h>
150 #include <sys/syslog.h>
155 #include <sys/errno.h>
156 #include <sys/time.h>
160 #include <sys/socket.h>
161 #include <netinet/tcp.h>
164 #include <netinet/libalias/alias.h>
165 #include <netinet/libalias/alias_local.h>
166 #include <netinet/libalias/alias_mod.h>
170 #include "alias_local.h"
171 #include "alias_mod.h"
174 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
178 Constants (note: constants are also defined
179 near relevant functions or structs)
182 /* Parameters used for cleanup of expired links */
183 #define ALIAS_CLEANUP_INTERVAL_SECS 60
184 #define ALIAS_CLEANUP_MAX_SPOKES 30
186 /* Timeouts (in seconds) for different link types */
187 #define ICMP_EXPIRE_TIME 60
188 #define UDP_EXPIRE_TIME 60
189 #define PROTO_EXPIRE_TIME 60
190 #define FRAGMENT_ID_EXPIRE_TIME 10
191 #define FRAGMENT_PTR_EXPIRE_TIME 30
193 /* TCP link expire time for different cases */
194 /* When the link has been used and closed - minimal grace time to
195 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
196 #ifndef TCP_EXPIRE_DEAD
197 #define TCP_EXPIRE_DEAD 10
200 /* When the link has been used and closed on one side - the other side
201 is allowed to still send data */
202 #ifndef TCP_EXPIRE_SINGLEDEAD
203 #define TCP_EXPIRE_SINGLEDEAD 90
206 /* When the link isn't yet up */
207 #ifndef TCP_EXPIRE_INITIAL
208 #define TCP_EXPIRE_INITIAL 300
211 /* When the link is up */
212 #ifndef TCP_EXPIRE_CONNECTED
213 #define TCP_EXPIRE_CONNECTED 86400
217 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
218 These constants can be anything except zero, which indicates an
219 unknown port number. */
221 #define NO_DEST_PORT 1
222 #define NO_SRC_PORT 1
228 The fundamental data structure used in this program is
229 "struct alias_link". Whenever a TCP connection is made,
230 a UDP datagram is sent out, or an ICMP echo request is made,
231 a link record is made (if it has not already been created).
232 The link record is identified by the source address/port
233 and the destination address/port. In the case of an ICMP
234 echo request, the source port is treated as being equivalent
235 with the 16-bit ID number of the ICMP packet.
237 The link record also can store some auxiliary data. For
238 TCP connections that have had sequence and acknowledgment
239 modifications, data space is available to track these changes.
240 A state field is used to keep track in changes to the TCP
241 connection state. ID numbers of fragments can also be
242 stored in the auxiliary space. Pointers to unresolved
243 fragments can also be stored.
245 The link records support two independent chainings. Lookup
246 tables for input and out tables hold the initial pointers
247 the link chains. On input, the lookup table indexes on alias
248 port and link type. On output, the lookup table indexes on
249 source address, destination address, source port, destination
253 struct ack_data_record { /* used to save changes to ACK/sequence
261 struct tcp_state { /* Information about TCP connection */
262 int in; /* State for outside -> inside */
263 int out; /* State for inside -> outside */
264 int index; /* Index to ACK data array */
265 int ack_modified; /* Indicates whether ACK and
266 * sequence numbers */
270 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
271 * saved for a modified TCP stream */
273 struct tcp_state state;
274 struct ack_data_record ack[N_LINK_TCP_DATA];
275 int fwhole; /* Which firewall record is used for this
279 struct server { /* LSNAT server pool (circular list) */
285 struct alias_link { /* Main data structure */
287 struct in_addr src_addr; /* Address and port information */
288 struct in_addr dst_addr;
289 struct in_addr alias_addr;
290 struct in_addr proxy_addr;
295 struct server *server;
297 int link_type; /* Type of link: TCP, UDP, ICMP,
300 /* values for link_type */
301 #define LINK_ICMP IPPROTO_ICMP
302 #define LINK_UDP IPPROTO_UDP
303 #define LINK_TCP IPPROTO_TCP
304 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
305 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
306 #define LINK_ADDR (IPPROTO_MAX + 3)
307 #define LINK_PPTP (IPPROTO_MAX + 4)
309 int flags; /* indicates special characteristics */
310 int pflags; /* protocol-specific flags */
313 #define LINK_UNKNOWN_DEST_PORT 0x01
314 #define LINK_UNKNOWN_DEST_ADDR 0x02
315 #define LINK_PERMANENT 0x04
316 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
317 #define LINK_UNFIREWALLED 0x08
319 int timestamp; /* Time link was last accessed */
320 int expire_time; /* Expire time for link */
321 #ifndef NO_USE_SOCKETS
322 int sockfd; /* socket descriptor */
324 LIST_ENTRY (alias_link) list_out; /* Linked list of
326 LIST_ENTRY (alias_link) list_in; /* input and output
329 union { /* Auxiliary data */
331 struct in_addr frag_addr;
336 /* Clean up procedure. */
337 static void finishoff(void);
339 /* Kernel module definition. */
341 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
343 MODULE_VERSION(libalias, 1);
346 alias_mod_handler(module_t mod, int type, void *data)
353 handler_chain_init();
357 handler_chain_destroy();
368 static moduledata_t alias_mod = {
369 "alias", alias_mod_handler, NULL
372 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
375 /* Internal utility routines (used only in alias_db.c)
377 Lookup table starting points:
378 StartPointIn() -- link table initial search point for
380 StartPointOut() -- link table initial search point for
384 SeqDiff() -- difference between two TCP sequences
385 ShowAliasStats() -- send alias statistics to a monitor file
389 /* Local prototypes */
390 static u_int StartPointIn(struct in_addr, u_short, int);
393 StartPointOut(struct in_addr, struct in_addr,
394 u_short, u_short, int);
396 static int SeqDiff(u_long, u_long);
399 /* Firewall control */
400 static void InitPunchFW(struct libalias *);
401 static void UninitPunchFW(struct libalias *);
402 static void ClearFWHole(struct alias_link *);
406 /* Log file control */
407 static void ShowAliasStats(struct libalias *);
408 static int InitPacketAliasLog(struct libalias *);
409 static void UninitPacketAliasLog(struct libalias *);
412 StartPointIn(struct in_addr alias_addr,
418 n = alias_addr.s_addr;
419 if (link_type != LINK_PPTP)
422 return (n % LINK_TABLE_IN_SIZE);
427 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
428 u_short src_port, u_short dst_port, int link_type)
433 n += dst_addr.s_addr;
434 if (link_type != LINK_PPTP) {
440 return (n % LINK_TABLE_OUT_SIZE);
445 SeqDiff(u_long x, u_long y)
447 /* Return the difference between two TCP sequence numbers */
450 This function is encapsulated in case there are any unusual
451 arithmetic conditions that need to be considered.
454 return (ntohl(y) - ntohl(x));
460 AliasLog(char *str, const char *format, ...)
464 va_start(ap, format);
465 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
466 log(LOG_SECURITY | LOG_INFO, "%s\n", str);
471 AliasLog(FILE *stream, const char *format, ...)
475 va_start(ap, format);
476 vfprintf(stream, format, ap);
483 ShowAliasStats(struct libalias *la)
485 /* Used for debugging */
487 int tot = la->icmpLinkCount + la->udpLinkCount +
488 la->tcpLinkCount + la->pptpLinkCount +
489 la->protoLinkCount + la->fragmentIdLinkCount +
490 la->fragmentPtrLinkCount;
492 AliasLog(la->logDesc,
493 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
499 la->fragmentIdLinkCount,
500 la->fragmentPtrLinkCount, tot);
502 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
507 /* Internal routines for finding, deleting and adding links
510 GetNewPort() -- find and reserve new alias port number
511 GetSocket() -- try to allocate a socket for a given port
513 Link creation and deletion:
514 CleanupAliasData() - remove all link chains from lookup table
515 IncrementalCleanup() - look for stale links in a single chain
516 DeleteLink() - remove link
518 ReLink() - change link
521 FindLinkOut() - find link for outgoing packets
522 FindLinkIn() - find link for incoming packets
525 FindNewPortGroup() - find an available group of ports
528 /* Local prototypes */
529 static int GetNewPort(struct libalias *, struct alias_link *, int);
530 #ifndef NO_USE_SOCKETS
531 static u_short GetSocket(struct libalias *, u_short, int *, int);
533 static void CleanupAliasData(struct libalias *);
535 static void IncrementalCleanup(struct libalias *);
537 static void DeleteLink(struct alias_link *);
539 static struct alias_link *
540 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
541 u_short, u_short, int, int);
543 static struct alias_link *
544 ReLink(struct alias_link *,
545 struct in_addr, struct in_addr, struct in_addr,
546 u_short, u_short, int, int);
548 static struct alias_link *
549 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
551 static struct alias_link *
552 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
555 #define ALIAS_PORT_BASE 0x08000
556 #define ALIAS_PORT_MASK 0x07fff
557 #define ALIAS_PORT_MASK_EVEN 0x07ffe
558 #define GET_NEW_PORT_MAX_ATTEMPTS 20
560 #define GET_ALIAS_PORT -1
561 #define GET_ALIAS_ID GET_ALIAS_PORT
563 #define FIND_EVEN_ALIAS_BASE 1
565 /* GetNewPort() allocates port numbers. Note that if a port number
566 is already in use, that does not mean that it cannot be used by
567 another link concurrently. This is because GetNewPort() looks for
568 unused triplets: (dest addr, dest port, alias port). */
571 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
579 Description of alias_port_param for GetNewPort(). When
580 this parameter is zero or positive, it precisely specifies
581 the port number. GetNewPort() will return this number
582 without check that it is in use.
584 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
585 selected port number.
588 if (alias_port_param == GET_ALIAS_PORT) {
590 * The aliasing port is automatically selected by one of
593 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
595 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
597 * When the PKT_ALIAS_SAME_PORTS option is chosen,
598 * the first try will be the actual source port. If
599 * this is already in use, the remainder of the
600 * trials will be random.
602 port_net = lnk->src_port;
603 port_sys = ntohs(port_net);
605 /* First trial and all subsequent are random. */
606 port_sys = random() & ALIAS_PORT_MASK;
607 port_sys += ALIAS_PORT_BASE;
608 port_net = htons(port_sys);
610 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
611 lnk->alias_port = (u_short) alias_port_param;
614 #ifdef LIBALIAS_DEBUG
615 fprintf(stderr, "PacketAlias/GetNewPort(): ");
616 fprintf(stderr, "input parameter error\n");
622 /* Port number search */
623 for (i = 0; i < max_trials; i++) {
625 struct alias_link *search_result;
627 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
628 lnk->dst_port, port_net,
631 if (search_result == NULL)
633 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
634 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
640 #ifndef NO_USE_SOCKETS
641 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
642 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
643 && ((lnk->link_type == LINK_TCP) ||
644 (lnk->link_type == LINK_UDP))) {
645 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
646 lnk->alias_port = port_net;
651 lnk->alias_port = port_net;
653 #ifndef NO_USE_SOCKETS
657 port_sys = random() & ALIAS_PORT_MASK;
658 port_sys += ALIAS_PORT_BASE;
659 port_net = htons(port_sys);
662 #ifdef LIBALIAS_DEBUG
663 fprintf(stderr, "PacketAlias/GetnewPort(): ");
664 fprintf(stderr, "could not find free port\n");
670 #ifndef NO_USE_SOCKETS
672 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
676 struct sockaddr_in sock_addr;
678 if (link_type == LINK_TCP)
679 sock = socket(AF_INET, SOCK_STREAM, 0);
680 else if (link_type == LINK_UDP)
681 sock = socket(AF_INET, SOCK_DGRAM, 0);
683 #ifdef LIBALIAS_DEBUG
684 fprintf(stderr, "PacketAlias/GetSocket(): ");
685 fprintf(stderr, "incorrect link type\n");
691 #ifdef LIBALIAS_DEBUG
692 fprintf(stderr, "PacketAlias/GetSocket(): ");
693 fprintf(stderr, "socket() error %d\n", *sockfd);
697 sock_addr.sin_family = AF_INET;
698 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
699 sock_addr.sin_port = port_net;
702 (struct sockaddr *)&sock_addr,
715 /* FindNewPortGroup() returns a base port number for an available
716 range of contiguous port numbers. Note that if a port number
717 is already in use, that does not mean that it cannot be used by
718 another link concurrently. This is because FindNewPortGroup()
719 looks for unused triplets: (dest addr, dest port, alias port). */
722 FindNewPortGroup(struct libalias *la,
723 struct in_addr dst_addr,
724 struct in_addr alias_addr,
737 * Get link_type from protocol
742 link_type = LINK_UDP;
745 link_type = LINK_TCP;
753 * The aliasing port is automatically selected by one of two
756 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
758 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
760 * When the ALIAS_SAME_PORTS option is chosen, the first
761 * try will be the actual source port. If this is already
762 * in use, the remainder of the trials will be random.
764 port_sys = ntohs(src_port);
768 /* First trial and all subsequent are random. */
769 if (align == FIND_EVEN_ALIAS_BASE)
770 port_sys = random() & ALIAS_PORT_MASK_EVEN;
772 port_sys = random() & ALIAS_PORT_MASK;
774 port_sys += ALIAS_PORT_BASE;
777 /* Port number search */
778 for (i = 0; i < max_trials; i++) {
780 struct alias_link *search_result;
782 for (j = 0; j < port_count; j++)
783 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
784 dst_port, htons(port_sys + j),
788 /* Found a good range, return base */
790 return (htons(port_sys));
792 /* Find a new base to try */
793 if (align == FIND_EVEN_ALIAS_BASE)
794 port_sys = random() & ALIAS_PORT_MASK_EVEN;
796 port_sys = random() & ALIAS_PORT_MASK;
798 port_sys += ALIAS_PORT_BASE;
801 #ifdef LIBALIAS_DEBUG
802 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
803 fprintf(stderr, "could not find free port(s)\n");
810 CleanupAliasData(struct libalias *la)
812 struct alias_link *lnk;
816 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
817 lnk = LIST_FIRST(&la->linkTableOut[i]);
818 while (lnk != NULL) {
819 struct alias_link *link_next;
821 link_next = LIST_NEXT(lnk, list_out);
828 la->cleanupIndex = 0;
833 IncrementalCleanup(struct libalias *la)
836 struct alias_link *lnk;
839 lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]);
840 while (lnk != NULL) {
842 struct alias_link *link_next;
844 link_next = LIST_NEXT(lnk, list_out);
845 idelta = la->timeStamp - lnk->timestamp;
846 switch (lnk->link_type) {
848 if (idelta > lnk->expire_time) {
849 struct tcp_dat *tcp_aux;
851 tcp_aux = lnk->data.tcp;
852 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED
853 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) {
860 if (idelta > lnk->expire_time) {
869 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
870 la->cleanupIndex = 0;
874 DeleteLink(struct alias_link *lnk)
876 struct libalias *la = lnk->la;
878 /* Don't do anything if the link is marked permanent */
879 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
883 /* Delete associated firewall hole, if any */
887 /* Free memory allocated for LSNAT server pool */
888 if (lnk->server != NULL) {
889 struct server *head, *curr, *next;
891 head = curr = lnk->server;
895 } while ((curr = next) != head);
897 /* Adjust output table pointers */
898 LIST_REMOVE(lnk, list_out);
900 /* Adjust input table pointers */
901 LIST_REMOVE(lnk, list_in);
902 #ifndef NO_USE_SOCKETS
903 /* Close socket, if one has been allocated */
904 if (lnk->sockfd != -1) {
909 /* Link-type dependent cleanup */
910 switch (lnk->link_type) {
924 case LINK_FRAGMENT_ID:
925 la->fragmentIdLinkCount--;
927 case LINK_FRAGMENT_PTR:
928 la->fragmentPtrLinkCount--;
929 if (lnk->data.frag_ptr != NULL)
930 free(lnk->data.frag_ptr);
935 la->protoLinkCount--;
942 /* Write statistics, if logging enabled */
943 if (la->packetAliasMode & PKT_ALIAS_LOG) {
949 static struct alias_link *
950 AddLink(struct libalias *la, struct in_addr src_addr,
951 struct in_addr dst_addr,
952 struct in_addr alias_addr,
955 int alias_port_param, /* if less than zero, alias */
957 { /* port will be automatically *//* chosen.
959 u_int start_point; /* zero, equal to alias port */
960 struct alias_link *lnk;
962 lnk = malloc(sizeof(struct alias_link));
964 /* Basic initialization */
966 lnk->src_addr = src_addr;
967 lnk->dst_addr = dst_addr;
968 lnk->alias_addr = alias_addr;
969 lnk->proxy_addr.s_addr = INADDR_ANY;
970 lnk->src_port = src_port;
971 lnk->dst_port = dst_port;
974 lnk->link_type = link_type;
975 #ifndef NO_USE_SOCKETS
980 lnk->timestamp = la->timeStamp;
982 /* Expiration time */
985 lnk->expire_time = ICMP_EXPIRE_TIME;
988 lnk->expire_time = UDP_EXPIRE_TIME;
991 lnk->expire_time = TCP_EXPIRE_INITIAL;
994 lnk->flags |= LINK_PERMANENT; /* no timeout. */
996 case LINK_FRAGMENT_ID:
997 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
999 case LINK_FRAGMENT_PTR:
1000 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1005 lnk->expire_time = PROTO_EXPIRE_TIME;
1009 /* Determine alias flags */
1010 if (dst_addr.s_addr == INADDR_ANY)
1011 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
1013 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1015 /* Determine alias port */
1016 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1020 /* Link-type dependent initialization */
1021 switch (link_type) {
1022 struct tcp_dat *aux_tcp;
1025 la->icmpLinkCount++;
1031 aux_tcp = malloc(sizeof(struct tcp_dat));
1032 if (aux_tcp != NULL) {
1036 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1037 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1038 aux_tcp->state.index = 0;
1039 aux_tcp->state.ack_modified = 0;
1040 for (i = 0; i < N_LINK_TCP_DATA; i++)
1041 aux_tcp->ack[i].active = 0;
1042 aux_tcp->fwhole = -1;
1043 lnk->data.tcp = aux_tcp;
1045 #ifdef LIBALIAS_DEBUG
1046 fprintf(stderr, "PacketAlias/AddLink: ");
1047 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1054 la->pptpLinkCount++;
1056 case LINK_FRAGMENT_ID:
1057 la->fragmentIdLinkCount++;
1059 case LINK_FRAGMENT_PTR:
1060 la->fragmentPtrLinkCount++;
1065 la->protoLinkCount++;
1069 /* Set up pointers for output lookup table */
1070 start_point = StartPointOut(src_addr, dst_addr,
1071 src_port, dst_port, link_type);
1072 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1074 /* Set up pointers for input lookup table */
1075 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1076 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1078 #ifdef LIBALIAS_DEBUG
1079 fprintf(stderr, "PacketAlias/AddLink(): ");
1080 fprintf(stderr, "malloc() call failed.\n");
1083 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1089 static struct alias_link *
1090 ReLink(struct alias_link *old_lnk,
1091 struct in_addr src_addr,
1092 struct in_addr dst_addr,
1093 struct in_addr alias_addr,
1096 int alias_port_param, /* if less than zero, alias */
1098 { /* port will be automatically *//* chosen.
1099 * If greater than */
1100 struct alias_link *new_lnk; /* zero, equal to alias port */
1101 struct libalias *la = old_lnk->la;
1103 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1104 src_port, dst_port, alias_port_param,
1107 if (new_lnk != NULL &&
1108 old_lnk->link_type == LINK_TCP &&
1109 old_lnk->data.tcp->fwhole > 0) {
1110 PunchFWHole(new_lnk);
1113 DeleteLink(old_lnk);
1117 static struct alias_link *
1118 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1119 struct in_addr dst_addr,
1123 int replace_partial_links)
1126 struct alias_link *lnk;
1128 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1129 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1130 if (lnk->src_addr.s_addr == src_addr.s_addr
1131 && lnk->server == NULL
1132 && lnk->dst_addr.s_addr == dst_addr.s_addr
1133 && lnk->dst_port == dst_port
1134 && lnk->src_port == src_port
1135 && lnk->link_type == link_type) {
1136 lnk->timestamp = la->timeStamp;
1141 /* Search for partially specified links. */
1142 if (lnk == NULL && replace_partial_links) {
1143 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1144 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1147 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1148 dst_port, link_type, 0);
1151 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1152 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1157 src_addr, dst_addr, lnk->alias_addr,
1158 src_port, dst_port, lnk->alias_port,
1165 static struct alias_link *
1166 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1167 struct in_addr dst_addr,
1171 int replace_partial_links)
1173 struct alias_link *lnk;
1175 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1176 link_type, replace_partial_links);
1180 * The following allows permanent links to be specified as
1181 * using the default source address (i.e. device interface
1182 * address) without knowing in advance what that address
1185 if (la->aliasAddress.s_addr != INADDR_ANY &&
1186 src_addr.s_addr == la->aliasAddress.s_addr) {
1187 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1188 link_type, replace_partial_links);
1195 static struct alias_link *
1196 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1197 struct in_addr alias_addr,
1201 int replace_partial_links)
1205 struct alias_link *lnk;
1206 struct alias_link *lnk_fully_specified;
1207 struct alias_link *lnk_unknown_all;
1208 struct alias_link *lnk_unknown_dst_addr;
1209 struct alias_link *lnk_unknown_dst_port;
1211 /* Initialize pointers */
1212 lnk_fully_specified = NULL;
1213 lnk_unknown_all = NULL;
1214 lnk_unknown_dst_addr = NULL;
1215 lnk_unknown_dst_port = NULL;
1217 /* If either the dest addr or port is unknown, the search
1218 loop will have to know about this. */
1221 if (dst_addr.s_addr == INADDR_ANY)
1222 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1224 flags_in |= LINK_UNKNOWN_DEST_PORT;
1227 start_point = StartPointIn(alias_addr, alias_port, link_type);
1228 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1231 flags = flags_in | lnk->flags;
1232 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1233 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1234 && lnk->alias_port == alias_port
1235 && lnk->dst_addr.s_addr == dst_addr.s_addr
1236 && lnk->dst_port == dst_port
1237 && lnk->link_type == link_type) {
1238 lnk_fully_specified = lnk;
1241 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1242 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1243 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1244 && lnk->alias_port == alias_port
1245 && lnk->link_type == link_type) {
1246 if (lnk_unknown_all == NULL)
1247 lnk_unknown_all = lnk;
1249 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1250 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1251 && lnk->alias_port == alias_port
1252 && lnk->link_type == link_type
1253 && lnk->dst_port == dst_port) {
1254 if (lnk_unknown_dst_addr == NULL)
1255 lnk_unknown_dst_addr = lnk;
1257 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1258 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1259 && lnk->alias_port == alias_port
1260 && lnk->link_type == link_type
1261 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1262 if (lnk_unknown_dst_port == NULL)
1263 lnk_unknown_dst_port = lnk;
1270 if (lnk_fully_specified != NULL) {
1271 lnk_fully_specified->timestamp = la->timeStamp;
1272 lnk = lnk_fully_specified;
1273 } else if (lnk_unknown_dst_port != NULL)
1274 lnk = lnk_unknown_dst_port;
1275 else if (lnk_unknown_dst_addr != NULL)
1276 lnk = lnk_unknown_dst_addr;
1277 else if (lnk_unknown_all != NULL)
1278 lnk = lnk_unknown_all;
1282 if (replace_partial_links &&
1283 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1284 struct in_addr src_addr;
1287 if (lnk->server != NULL) { /* LSNAT link */
1288 src_addr = lnk->server->addr;
1289 src_port = lnk->server->port;
1290 lnk->server = lnk->server->next;
1292 src_addr = lnk->src_addr;
1293 src_port = lnk->src_port;
1297 src_addr, dst_addr, alias_addr,
1298 src_port, dst_port, alias_port,
1304 static struct alias_link *
1305 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1306 struct in_addr alias_addr,
1310 int replace_partial_links)
1312 struct alias_link *lnk;
1314 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1315 link_type, replace_partial_links);
1319 * The following allows permanent links to be specified as
1320 * using the default aliasing address (i.e. device
1321 * interface address) without knowing in advance what that
1324 if (la->aliasAddress.s_addr != INADDR_ANY &&
1325 alias_addr.s_addr == la->aliasAddress.s_addr) {
1326 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1327 link_type, replace_partial_links);
1336 /* External routines for finding/adding links
1338 -- "external" means outside alias_db.c, but within alias*.c --
1340 FindIcmpIn(), FindIcmpOut()
1341 FindFragmentIn1(), FindFragmentIn2()
1342 AddFragmentPtrLink(), FindFragmentPtr()
1343 FindProtoIn(), FindProtoOut()
1344 FindUdpTcpIn(), FindUdpTcpOut()
1345 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1346 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1347 FindOriginalAddress(), FindAliasAddress()
1349 (prototypes in alias_local.h)
1354 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1355 struct in_addr alias_addr,
1359 struct alias_link *lnk;
1361 lnk = FindLinkIn(la, dst_addr, alias_addr,
1362 NO_DEST_PORT, id_alias,
1364 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1365 struct in_addr target_addr;
1367 target_addr = FindOriginalAddress(la, alias_addr);
1368 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1369 id_alias, NO_DEST_PORT, id_alias,
1377 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1378 struct in_addr dst_addr,
1382 struct alias_link *lnk;
1384 lnk = FindLinkOut(la, src_addr, dst_addr,
1387 if (lnk == NULL && create) {
1388 struct in_addr alias_addr;
1390 alias_addr = FindAliasAddress(la, src_addr);
1391 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1392 id, NO_DEST_PORT, GET_ALIAS_ID,
1400 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1401 struct in_addr alias_addr,
1404 struct alias_link *lnk;
1406 lnk = FindLinkIn(la, dst_addr, alias_addr,
1407 NO_DEST_PORT, ip_id,
1408 LINK_FRAGMENT_ID, 0);
1411 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1412 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1420 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1422 struct in_addr alias_addr, /* is not found. */
1425 return FindLinkIn(la, dst_addr, alias_addr,
1426 NO_DEST_PORT, ip_id,
1427 LINK_FRAGMENT_ID, 0);
1432 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1435 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1436 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1442 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1445 return FindLinkIn(la, dst_addr, la->nullAddress,
1446 NO_DEST_PORT, ip_id,
1447 LINK_FRAGMENT_PTR, 0);
1452 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1453 struct in_addr alias_addr,
1456 struct alias_link *lnk;
1458 lnk = FindLinkIn(la, dst_addr, alias_addr,
1462 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1463 struct in_addr target_addr;
1465 target_addr = FindOriginalAddress(la, alias_addr);
1466 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1467 NO_SRC_PORT, NO_DEST_PORT, 0,
1475 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1476 struct in_addr dst_addr,
1479 struct alias_link *lnk;
1481 lnk = FindLinkOut(la, src_addr, dst_addr,
1482 NO_SRC_PORT, NO_DEST_PORT,
1486 struct in_addr alias_addr;
1488 alias_addr = FindAliasAddress(la, src_addr);
1489 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1490 NO_SRC_PORT, NO_DEST_PORT, 0,
1498 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1499 struct in_addr alias_addr,
1506 struct alias_link *lnk;
1510 link_type = LINK_UDP;
1513 link_type = LINK_TCP;
1520 lnk = FindLinkIn(la, dst_addr, alias_addr,
1521 dst_port, alias_port,
1524 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1525 struct in_addr target_addr;
1527 target_addr = FindOriginalAddress(la, alias_addr);
1528 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1529 alias_port, dst_port, alias_port,
1537 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1538 struct in_addr dst_addr,
1545 struct alias_link *lnk;
1549 link_type = LINK_UDP;
1552 link_type = LINK_TCP;
1559 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1561 if (lnk == NULL && create) {
1562 struct in_addr alias_addr;
1564 alias_addr = FindAliasAddress(la, src_addr);
1565 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1566 src_port, dst_port, GET_ALIAS_PORT,
1574 AddPptp(struct libalias *la, struct in_addr src_addr,
1575 struct in_addr dst_addr,
1576 struct in_addr alias_addr,
1577 u_int16_t src_call_id)
1579 struct alias_link *lnk;
1581 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1582 src_call_id, 0, GET_ALIAS_PORT,
1590 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1591 struct in_addr dst_addr,
1592 u_int16_t src_call_id)
1595 struct alias_link *lnk;
1597 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1598 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1599 if (lnk->link_type == LINK_PPTP &&
1600 lnk->src_addr.s_addr == src_addr.s_addr &&
1601 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1602 lnk->src_port == src_call_id)
1610 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1611 struct in_addr dst_addr,
1612 u_int16_t dst_call_id)
1615 struct alias_link *lnk;
1617 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1618 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1619 if (lnk->link_type == LINK_PPTP &&
1620 lnk->src_addr.s_addr == src_addr.s_addr &&
1621 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1622 lnk->dst_port == dst_call_id)
1630 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1631 struct in_addr alias_addr,
1632 u_int16_t dst_call_id)
1635 struct alias_link *lnk;
1637 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1638 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1639 if (lnk->link_type == LINK_PPTP &&
1640 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1641 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1642 lnk->dst_port == dst_call_id)
1650 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1651 struct in_addr alias_addr,
1652 u_int16_t alias_call_id)
1654 struct alias_link *lnk;
1656 lnk = FindLinkIn(la, dst_addr, alias_addr,
1657 0 /* any */ , alias_call_id,
1666 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1667 struct in_addr dst_addr,
1673 struct alias_link *lnk;
1677 link_type = LINK_UDP;
1680 link_type = LINK_TCP;
1687 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1690 struct in_addr alias_addr;
1692 alias_addr = FindAliasAddress(la, src_addr);
1693 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1694 src_port, 0, alias_port,
1702 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1704 struct alias_link *lnk;
1706 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1707 0, 0, LINK_ADDR, 0);
1709 la->newDefaultLink = 1;
1710 if (la->targetAddress.s_addr == INADDR_ANY)
1711 return (alias_addr);
1712 else if (la->targetAddress.s_addr == INADDR_NONE)
1713 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1714 la->aliasAddress : alias_addr;
1716 return (la->targetAddress);
1718 if (lnk->server != NULL) { /* LSNAT link */
1719 struct in_addr src_addr;
1721 src_addr = lnk->server->addr;
1722 lnk->server = lnk->server->next;
1724 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1725 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1726 la->aliasAddress : alias_addr;
1728 return (lnk->src_addr);
1734 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1736 struct alias_link *lnk;
1738 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1739 0, 0, LINK_ADDR, 0);
1741 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1742 la->aliasAddress : original_addr;
1744 if (lnk->alias_addr.s_addr == INADDR_ANY)
1745 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1746 la->aliasAddress : original_addr;
1748 return (lnk->alias_addr);
1753 /* External routines for getting or changing link data
1754 (external to alias_db.c, but internal to alias*.c)
1756 SetFragmentData(), GetFragmentData()
1757 SetFragmentPtr(), GetFragmentPtr()
1758 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1759 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1760 GetOriginalPort(), GetAliasPort()
1761 SetAckModified(), GetAckModified()
1762 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1763 SetProtocolFlags(), GetProtocolFlags()
1769 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1771 lnk->data.frag_addr = src_addr;
1776 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1778 *src_addr = lnk->data.frag_addr;
1783 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1785 lnk->data.frag_ptr = fptr;
1790 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1792 *fptr = lnk->data.frag_ptr;
1797 SetStateIn(struct alias_link *lnk, int state)
1799 /* TCP input state */
1801 case ALIAS_TCP_STATE_DISCONNECTED:
1802 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1803 lnk->expire_time = TCP_EXPIRE_DEAD;
1805 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1807 case ALIAS_TCP_STATE_CONNECTED:
1808 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1809 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1813 panic("libalias:SetStateIn() unknown state");
1818 lnk->data.tcp->state.in = state;
1823 SetStateOut(struct alias_link *lnk, int state)
1825 /* TCP output state */
1827 case ALIAS_TCP_STATE_DISCONNECTED:
1828 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1829 lnk->expire_time = TCP_EXPIRE_DEAD;
1831 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1833 case ALIAS_TCP_STATE_CONNECTED:
1834 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1835 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1839 panic("libalias:SetStateOut() unknown state");
1844 lnk->data.tcp->state.out = state;
1849 GetStateIn(struct alias_link *lnk)
1851 /* TCP input state */
1852 return (lnk->data.tcp->state.in);
1857 GetStateOut(struct alias_link *lnk)
1859 /* TCP output state */
1860 return (lnk->data.tcp->state.out);
1865 GetOriginalAddress(struct alias_link *lnk)
1867 if (lnk->src_addr.s_addr == INADDR_ANY)
1868 return (lnk->la->aliasAddress);
1870 return (lnk->src_addr);
1875 GetDestAddress(struct alias_link *lnk)
1877 return (lnk->dst_addr);
1882 GetAliasAddress(struct alias_link *lnk)
1884 if (lnk->alias_addr.s_addr == INADDR_ANY)
1885 return (lnk->la->aliasAddress);
1887 return (lnk->alias_addr);
1892 GetDefaultAliasAddress(struct libalias *la)
1894 return (la->aliasAddress);
1899 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1901 la->aliasAddress = alias_addr;
1906 GetOriginalPort(struct alias_link *lnk)
1908 return (lnk->src_port);
1913 GetAliasPort(struct alias_link *lnk)
1915 return (lnk->alias_port);
1920 GetDestPort(struct alias_link *lnk)
1922 return (lnk->dst_port);
1928 SetAckModified(struct alias_link *lnk)
1930 /* Indicate that ACK numbers have been modified in a TCP connection */
1931 lnk->data.tcp->state.ack_modified = 1;
1936 GetProxyAddress(struct alias_link *lnk)
1938 return (lnk->proxy_addr);
1943 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1945 lnk->proxy_addr = addr;
1950 GetProxyPort(struct alias_link *lnk)
1952 return (lnk->proxy_port);
1957 SetProxyPort(struct alias_link *lnk, u_short port)
1959 lnk->proxy_port = port;
1964 GetAckModified(struct alias_link *lnk)
1966 /* See if ACK numbers have been modified */
1967 return (lnk->data.tcp->state.ack_modified);
1972 GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
1975 Find out how much the ACK number has been altered for an incoming
1976 TCP packet. To do this, a circular list of ACK numbers where the TCP
1977 packet size was altered is searched.
1982 int delta, ack_diff_min;
1990 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1991 struct ack_data_record x;
1993 x = lnk->data.tcp->ack[i];
1994 if (x.active == 1) {
1997 ack_diff = SeqDiff(x.ack_new, ack);
1998 if (ack_diff >= 0) {
1999 if (ack_diff_min >= 0) {
2000 if (ack_diff < ack_diff_min) {
2002 ack_diff_min = ack_diff;
2006 ack_diff_min = ack_diff;
2016 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
2019 Find out how much the sequence number has been altered for an outgoing
2020 TCP packet. To do this, a circular list of ACK numbers where the TCP
2021 packet size was altered is searched.
2026 int delta, seq_diff_min;
2034 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2035 struct ack_data_record x;
2037 x = lnk->data.tcp->ack[i];
2038 if (x.active == 1) {
2041 seq_diff = SeqDiff(x.ack_old, seq);
2042 if (seq_diff >= 0) {
2043 if (seq_diff_min >= 0) {
2044 if (seq_diff < seq_diff_min) {
2046 seq_diff_min = seq_diff;
2050 seq_diff_min = seq_diff;
2060 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
2063 When a TCP packet has been altered in length, save this
2064 information in a circular list. If enough packets have
2065 been altered, then this list will begin to overwrite itself.
2069 struct ack_data_record x;
2070 int hlen, tlen, dlen;
2075 hlen = (pip->ip_hl + tc->th_off) << 2;
2076 tlen = ntohs(pip->ip_len);
2079 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2080 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2084 i = lnk->data.tcp->state.index;
2085 lnk->data.tcp->ack[i] = x;
2088 if (i == N_LINK_TCP_DATA)
2089 lnk->data.tcp->state.index = 0;
2091 lnk->data.tcp->state.index = i;
2095 SetExpire(struct alias_link *lnk, int expire)
2098 lnk->flags &= ~LINK_PERMANENT;
2100 } else if (expire == -1) {
2101 lnk->flags |= LINK_PERMANENT;
2102 } else if (expire > 0) {
2103 lnk->expire_time = expire;
2105 #ifdef LIBALIAS_DEBUG
2106 fprintf(stderr, "PacketAlias/SetExpire(): ");
2107 fprintf(stderr, "error in expire parameter\n");
2113 ClearCheckNewLink(struct libalias *la)
2115 la->newDefaultLink = 0;
2119 SetProtocolFlags(struct alias_link *lnk, int pflags)
2122 lnk->pflags = pflags;;
2126 GetProtocolFlags(struct alias_link *lnk)
2129 return (lnk->pflags);
2133 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2135 struct libalias *la = lnk->la;
2137 la->deleteAllLinks = 1;
2138 lnk = ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2139 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2140 la->deleteAllLinks = 0;
2144 /* Miscellaneous Functions
2147 InitPacketAliasLog()
2148 UninitPacketAliasLog()
2152 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2153 is called to find and remove timed-out aliasing links. Logic exists
2154 to sweep through the entire table and linked list structure
2157 (prototype in alias_local.h)
2161 HouseKeeping(struct libalias *la)
2170 * Save system time (seconds) in global variable timeStamp for use
2171 * by other functions. This is done so as not to unnecessarily
2172 * waste timeline by making system calls.
2175 la->timeStamp = time_uptime;
2177 gettimeofday(&tv, &tz);
2178 la->timeStamp = tv.tv_sec;
2181 /* Compute number of spokes (output table link chains) to cover */
2182 n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual;
2183 n100 *= la->timeStamp - la->lastCleanupTime;
2184 n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2188 /* Handle different cases */
2189 if (n > ALIAS_CLEANUP_MAX_SPOKES) {
2190 n = ALIAS_CLEANUP_MAX_SPOKES;
2191 la->lastCleanupTime = la->timeStamp;
2192 la->houseKeepingResidual = 0;
2194 for (i = 0; i < n; i++)
2195 IncrementalCleanup(la);
2197 la->lastCleanupTime = la->timeStamp;
2198 la->houseKeepingResidual = n100 - 100 * n;
2200 for (i = 0; i < n; i++)
2201 IncrementalCleanup(la);
2203 #ifdef LIBALIAS_DEBUG
2204 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2205 fprintf(stderr, "something unexpected in time values\n");
2207 la->lastCleanupTime = la->timeStamp;
2208 la->houseKeepingResidual = 0;
2212 /* Init the log file and enable logging */
2214 InitPacketAliasLog(struct libalias *la)
2216 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2218 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2221 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2222 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2225 return (ENOMEM); /* log initialization failed */
2226 la->packetAliasMode |= PKT_ALIAS_LOG;
2232 /* Close the log-file and disable logging. */
2234 UninitPacketAliasLog(struct libalias *la)
2240 fclose(la->logDesc);
2244 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2247 /* Outside world interfaces
2249 -- "outside world" means other than alias*.c routines --
2251 PacketAliasRedirectPort()
2252 PacketAliasAddServer()
2253 PacketAliasRedirectProto()
2254 PacketAliasRedirectAddr()
2255 PacketAliasRedirectDynamic()
2256 PacketAliasRedirectDelete()
2257 PacketAliasSetAddress()
2260 PacketAliasSetMode()
2262 (prototypes in alias.h)
2265 /* Redirection from a specific public addr:port to a
2266 private addr:port */
2268 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2269 struct in_addr dst_addr, u_short dst_port,
2270 struct in_addr alias_addr, u_short alias_port,
2274 struct alias_link *lnk;
2278 link_type = LINK_UDP;
2281 link_type = LINK_TCP;
2284 #ifdef LIBALIAS_DEBUG
2285 fprintf(stderr, "PacketAliasRedirectPort(): ");
2286 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");
2308 /* Add server to the pool of servers */
2310 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2312 struct server *server;
2316 server = malloc(sizeof(struct server));
2318 if (server != NULL) {
2319 struct server *head;
2321 server->addr = addr;
2322 server->port = port;
2326 server->next = server;
2330 for (s = head; s->next != head; s = s->next);
2332 server->next = head;
2334 lnk->server = server;
2340 /* Redirect packets of a given IP protocol from a specific
2341 public address to a private address */
2343 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2344 struct in_addr dst_addr,
2345 struct in_addr alias_addr,
2348 struct alias_link *lnk;
2350 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2351 NO_SRC_PORT, NO_DEST_PORT, 0,
2355 lnk->flags |= LINK_PERMANENT;
2357 #ifdef LIBALIAS_DEBUG
2359 fprintf(stderr, "PacketAliasRedirectProto(): "
2360 "call to AddLink() failed\n");
2367 /* Static address translation */
2369 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2370 struct in_addr alias_addr)
2372 struct alias_link *lnk;
2374 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2379 lnk->flags |= LINK_PERMANENT;
2381 #ifdef LIBALIAS_DEBUG
2383 fprintf(stderr, "PacketAliasRedirectAddr(): "
2384 "call to AddLink() failed\n");
2392 /* Mark the aliasing link dynamic */
2394 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2399 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2402 lnk->flags &= ~LINK_PERMANENT;
2409 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2411 /* This is a dangerous function to put in the API,
2412 because an invalid pointer can crash the program. */
2414 la->deleteAllLinks = 1;
2416 la->deleteAllLinks = 0;
2421 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2423 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2424 && la->aliasAddress.s_addr != addr.s_addr)
2425 CleanupAliasData(la);
2427 la->aliasAddress = addr;
2432 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2434 la->targetAddress = target_addr;
2441 while (!LIST_EMPTY(&instancehead))
2442 LibAliasUninit(LIST_FIRST(&instancehead));
2446 LibAliasInit(struct libalias *la)
2455 la = calloc(sizeof *la, 1);
2459 #ifndef _KERNEL /* kernel cleans up on module unload */
2460 if (LIST_EMPTY(&instancehead))
2463 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2466 la->timeStamp = time_uptime;
2467 la->lastCleanupTime = time_uptime;
2469 gettimeofday(&tv, &tz);
2470 la->timeStamp = tv.tv_sec;
2471 la->lastCleanupTime = tv.tv_sec;
2473 la->houseKeepingResidual = 0;
2475 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2476 LIST_INIT(&la->linkTableOut[i]);
2477 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2478 LIST_INIT(&la->linkTableIn[i]);
2481 la->deleteAllLinks = 1;
2482 CleanupAliasData(la);
2483 la->deleteAllLinks = 0;
2486 la->aliasAddress.s_addr = INADDR_ANY;
2487 la->targetAddress.s_addr = INADDR_ANY;
2489 la->icmpLinkCount = 0;
2490 la->udpLinkCount = 0;
2491 la->tcpLinkCount = 0;
2492 la->pptpLinkCount = 0;
2493 la->protoLinkCount = 0;
2494 la->fragmentIdLinkCount = 0;
2495 la->fragmentPtrLinkCount = 0;
2498 la->cleanupIndex = 0;
2500 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2501 #ifndef NO_USE_SOCKETS
2502 | PKT_ALIAS_USE_SOCKETS
2504 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2506 la->fireWallFD = -1;
2509 LibAliasRefreshModules();
2515 LibAliasUninit(struct libalias *la)
2517 la->deleteAllLinks = 1;
2518 CleanupAliasData(la);
2519 la->deleteAllLinks = 0;
2520 UninitPacketAliasLog(la);
2524 LIST_REMOVE(la, instancelist);
2528 /* Change mode for some operations */
2531 struct libalias *la,
2532 unsigned int flags, /* Which state to bring flags to */
2533 unsigned int mask /* Mask of which flags to affect (use 0 to
2534 * do a probe for flag values) */
2537 /* Enable logging? */
2538 if (flags & mask & PKT_ALIAS_LOG) {
2540 if (InitPacketAliasLog(la) == ENOMEM)
2543 /* _Disable_ logging? */
2544 if (~flags & mask & PKT_ALIAS_LOG) {
2545 UninitPacketAliasLog(la);
2548 /* Start punching holes in the firewall? */
2549 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2552 /* Stop punching holes in the firewall? */
2553 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2558 /* Other flags can be set/cleared without special action */
2559 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2560 return (la->packetAliasMode);
2565 LibAliasCheckNewLink(struct libalias *la)
2567 return (la->newDefaultLink);
2574 Code to support firewall punching. This shouldn't really be in this
2575 file, but making variables global is evil too.
2578 /* Firewall include files */
2580 #include <netinet/ip_fw.h>
2585 * helper function, updates the pointer to cmd with the length
2586 * of the current command, and also cleans up the first word of
2587 * the new command in case it has been clobbered before.
2590 next_cmd(ipfw_insn * cmd)
2593 bzero(cmd, sizeof(*cmd));
2598 * A function to fill simple commands of size 1.
2599 * Existing flags are preserved.
2602 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2603 int flags, u_int16_t arg)
2605 cmd->opcode = opcode;
2606 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2608 return next_cmd(cmd);
2612 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2614 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2616 cmd->addr.s_addr = addr;
2617 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2621 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2623 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2625 cmd->ports[0] = cmd->ports[1] = port;
2626 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2630 fill_rule(void *buf, int bufsize, int rulenum,
2631 enum ipfw_opcodes action, int proto,
2632 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2634 struct ip_fw *rule = (struct ip_fw *)buf;
2635 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2637 bzero(buf, bufsize);
2638 rule->rulenum = rulenum;
2640 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2641 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2642 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2643 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2644 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2646 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2647 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2649 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2651 return ((char *)cmd - (char *)buf);
2654 static void ClearAllFWHoles(struct libalias *la);
2657 #define fw_setfield(la, field, num) \
2659 (field)[(num) - la->fireWallBaseNum] = 1; \
2660 } /*lint -save -e717 */ while(0)/* lint -restore */
2662 #define fw_clrfield(la, field, num) \
2664 (field)[(num) - la->fireWallBaseNum] = 0; \
2665 } /*lint -save -e717 */ while(0)/* lint -restore */
2667 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2670 InitPunchFW(struct libalias *la)
2673 la->fireWallField = malloc(la->fireWallNumNums);
2674 if (la->fireWallField) {
2675 memset(la->fireWallField, 0, la->fireWallNumNums);
2676 if (la->fireWallFD < 0) {
2677 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2679 ClearAllFWHoles(la);
2680 la->fireWallActiveNum = la->fireWallBaseNum;
2685 UninitPunchFW(struct libalias *la)
2687 ClearAllFWHoles(la);
2688 if (la->fireWallFD >= 0)
2689 close(la->fireWallFD);
2690 la->fireWallFD = -1;
2691 if (la->fireWallField)
2692 free(la->fireWallField);
2693 la->fireWallField = NULL;
2694 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2697 /* Make a certain link go through the firewall */
2699 PunchFWHole(struct alias_link *lnk)
2701 struct libalias *la;
2702 int r; /* Result code */
2703 struct ip_fw rule; /* On-the-fly built rule */
2704 int fwhole; /* Where to punch hole */
2708 /* Don't do anything unless we are asked to */
2709 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2710 la->fireWallFD < 0 ||
2711 lnk->link_type != LINK_TCP)
2714 memset(&rule, 0, sizeof rule);
2718 /* Find empty slot */
2719 for (fwhole = la->fireWallActiveNum;
2720 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2721 fw_tstfield(la, la->fireWallField, fwhole);
2723 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2724 for (fwhole = la->fireWallBaseNum;
2725 fwhole < la->fireWallActiveNum &&
2726 fw_tstfield(la, la->fireWallField, fwhole);
2728 if (fwhole == la->fireWallActiveNum) {
2729 /* No rule point empty - we can't punch more holes. */
2730 la->fireWallActiveNum = la->fireWallBaseNum;
2731 #ifdef LIBALIAS_DEBUG
2732 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2737 /* Start next search at next position */
2738 la->fireWallActiveNum = fwhole + 1;
2741 * generate two rules of the form
2743 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2744 * accept tcp from DAddr DPort to OAddr OPort
2746 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2747 u_int32_t rulebuf[255];
2750 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2751 O_ACCEPT, IPPROTO_TCP,
2752 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2753 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2754 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2756 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2758 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2759 O_ACCEPT, IPPROTO_TCP,
2760 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2761 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2762 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2764 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2767 /* Indicate hole applied */
2768 lnk->data.tcp->fwhole = fwhole;
2769 fw_setfield(la, la->fireWallField, fwhole);
2772 /* Remove a hole in a firewall associated with a particular alias
2773 lnk. Calling this too often is harmless. */
2775 ClearFWHole(struct alias_link *lnk)
2778 struct libalias *la;
2781 if (lnk->link_type == LINK_TCP) {
2782 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2789 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2790 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2791 &fwhole, sizeof fwhole));
2792 fw_clrfield(la, la->fireWallField, fwhole);
2793 lnk->data.tcp->fwhole = -1;
2797 /* Clear out the entire range dedicated to firewall holes. */
2799 ClearAllFWHoles(struct libalias *la)
2801 struct ip_fw rule; /* On-the-fly built rule */
2804 if (la->fireWallFD < 0)
2807 memset(&rule, 0, sizeof rule);
2808 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2811 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2813 /* XXX: third arg correct here ? /phk */
2814 memset(la->fireWallField, 0, la->fireWallNumNums);
2820 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2823 la->fireWallBaseNum = base;
2824 la->fireWallNumNums = num;
2829 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2831 la->skinnyPort = port;