2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: src/sys/netinet/libalias/alias_db.c,v 1.71.2.2.2.1 2008/11/25 02:59:29 kensmith Exp $");
31 Alias_db.c encapsulates all data structures used for storing
32 packet aliasing data. Other parts of the aliasing software
33 access data through functions provided in this file.
35 Data storage is based on the notion of a "link", which is
36 established for ICMP echo/reply packets, UDP datagrams and
37 TCP stream connections. A link stores the original source
38 and destination addresses. For UDP and TCP, it also stores
39 source and destination port numbers, as well as an alias
40 port number. Links are also used to store information about
43 There is a facility for sweeping through and deleting old
44 links as new packets are sent through. A simple timeout is
45 used for ICMP and UDP links. TCP links are left alone unless
46 there is an incomplete connection, in which case the link
47 can be deleted after a certain amount of time.
50 Initial version: August, 1996 (cjm)
52 Version 1.4: September 16, 1996 (cjm)
53 Facility for handling incoming links added.
55 Version 1.6: September 18, 1996 (cjm)
56 ICMP data handling simplified.
58 Version 1.7: January 9, 1997 (cjm)
59 Fragment handling simplified.
60 Saves pointers for unresolved fragments.
61 Permits links for unspecified remote ports
62 or unspecified remote addresses.
63 Fixed bug which did not properly zero port
64 table entries after a link was deleted.
65 Cleaned up some obsolete comments.
67 Version 1.8: January 14, 1997 (cjm)
68 Fixed data type error in StartPoint().
69 (This error did not exist prior to v1.7
70 and was discovered and fixed by Ari Suutari)
72 Version 1.9: February 1, 1997
73 Optionally, connections initiated from packet aliasing host
74 machine will will not have their port number aliased unless it
75 conflicts with an aliasing port already being used. (cjm)
77 All options earlier being #ifdef'ed are now available through
78 a new interface, SetPacketAliasMode(). This allows run time
79 control (which is now available in PPP+pktAlias through the
80 'alias' keyword). (ee)
82 Added ability to create an alias port without
83 either destination address or port specified.
84 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
86 Removed K&R style function headers
87 and general cleanup. (ee)
89 Added packetAliasMode to replace compiler #defines's (ee)
91 Allocates sockets for partially specified
92 ports if ALIAS_USE_SOCKETS defined. (cjm)
94 Version 2.0: March, 1997
95 SetAliasAddress() will now clean up alias links
96 if the aliasing address is changed. (cjm)
98 PacketAliasPermanentLink() function added to support permanent
99 links. (J. Fortes suggested the need for this.)
102 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
104 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
107 These permanent links allow for incoming connections to
108 machines on the local network. They can be given with a
109 user-chosen amount of specificity, with increasing specificity
110 meaning more security. (cjm)
112 Quite a bit of rework to the basic engine. The portTable[]
113 array, which kept track of which ports were in use was replaced
114 by a table/linked list structure. (cjm)
116 SetExpire() function added. (cjm)
118 DeleteLink() no longer frees memory association with a pointer
119 to a fragment (this bug was first recognized by E. Eklund in
122 Version 2.1: May, 1997 (cjm)
123 Packet aliasing engine reworked so that it can handle
124 multiple external addresses rather than just a single
127 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
128 added to the API. The first function is a more generalized
129 version of PacketAliasPermanentLink(). The second function
130 implements static network address translation.
132 Version 3.2: July, 2000 (salander and satoh)
133 Added FindNewPortGroup to get contiguous range of port values.
135 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
136 link but not actually add one.
138 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
139 except that the alias port (from FindNewPortGroup) is provided
142 See HISTORY file for additional revisions.
145 #include <sys/param.h>
146 #include <sys/kernel.h>
147 #include <sys/module.h>
148 #include <sys/syslog.h>
149 #include <sys/queue.h>
151 #include <sys/socket.h>
152 #include <netinet/tcp.h>
155 #include "alias_local.h"
156 #include "alias_mod.h"
159 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
163 Constants (note: constants are also defined
164 near relevant functions or structs)
167 /* Parameters used for cleanup of expired links */
168 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
169 #define ALIAS_CLEANUP_INTERVAL_SECS 64
170 #define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
172 /* Timeouts (in seconds) for different link types */
173 #define ICMP_EXPIRE_TIME 60
174 #define UDP_EXPIRE_TIME 60
175 #define PROTO_EXPIRE_TIME 60
176 #define FRAGMENT_ID_EXPIRE_TIME 10
177 #define FRAGMENT_PTR_EXPIRE_TIME 30
179 /* TCP link expire time for different cases */
180 /* When the link has been used and closed - minimal grace time to
181 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
182 #ifndef TCP_EXPIRE_DEAD
183 #define TCP_EXPIRE_DEAD 10
186 /* When the link has been used and closed on one side - the other side
187 is allowed to still send data */
188 #ifndef TCP_EXPIRE_SINGLEDEAD
189 #define TCP_EXPIRE_SINGLEDEAD 90
192 /* When the link isn't yet up */
193 #ifndef TCP_EXPIRE_INITIAL
194 #define TCP_EXPIRE_INITIAL 300
197 /* When the link is up */
198 #ifndef TCP_EXPIRE_CONNECTED
199 #define TCP_EXPIRE_CONNECTED 86400
203 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
204 These constants can be anything except zero, which indicates an
205 unknown port number. */
207 #define NO_DEST_PORT 1
208 #define NO_SRC_PORT 1
210 /* Clean up procedure. */
211 static void finishoff(void);
213 /* Kernel module definition. */
215 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
217 MODULE_VERSION(libalias, 1);
220 alias_mod_handler(module_t mod, int type, void *data)
227 handler_chain_init();
230 handler_chain_destroy();
241 static moduledata_t alias_mod = {
242 "alias", alias_mod_handler, NULL
245 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
248 /* Internal utility routines (used only in alias_db.c)
250 Lookup table starting points:
251 StartPointIn() -- link table initial search point for
253 StartPointOut() -- link table initial search point for
257 SeqDiff() -- difference between two TCP sequences
258 ShowAliasStats() -- send alias statistics to a monitor file
262 /* Local prototypes */
263 static u_int StartPointIn(struct in_addr, u_short, int);
266 StartPointOut(struct in_addr, struct in_addr,
267 u_short, u_short, int);
269 static int SeqDiff(u_long, u_long);
272 /* Firewall control */
273 static void InitPunchFW(struct libalias *);
274 static void UninitPunchFW(struct libalias *);
275 static void ClearFWHole(struct alias_link *);
279 /* Log file control */
280 static void ShowAliasStats(struct libalias *);
281 static int InitPacketAliasLog(struct libalias *);
282 static void UninitPacketAliasLog(struct libalias *);
285 StartPointIn(struct in_addr alias_addr,
291 n = alias_addr.s_addr;
292 if (link_type != LINK_PPTP)
295 return (n % LINK_TABLE_IN_SIZE);
300 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
301 u_short src_port, u_short dst_port, int link_type)
306 n += dst_addr.s_addr;
307 if (link_type != LINK_PPTP) {
313 return (n % LINK_TABLE_OUT_SIZE);
318 SeqDiff(u_long x, u_long y)
320 /* Return the difference between two TCP sequence numbers */
323 This function is encapsulated in case there are any unusual
324 arithmetic conditions that need to be considered.
327 return (ntohl(y) - ntohl(x));
333 AliasLog(char *str, const char *format, ...)
337 va_start(ap, format);
338 kvsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
343 AliasLog(FILE *stream, const char *format, ...)
347 va_start(ap, format);
348 vfprintf(stream, format, ap);
355 ShowAliasStats(struct libalias *la)
358 LIBALIAS_LOCK_ASSERT(la);
359 /* Used for debugging */
361 int tot = la->icmpLinkCount + la->udpLinkCount +
362 la->tcpLinkCount + la->pptpLinkCount +
363 la->protoLinkCount + la->fragmentIdLinkCount +
364 la->fragmentPtrLinkCount;
366 AliasLog(la->logDesc,
367 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
373 la->fragmentIdLinkCount,
374 la->fragmentPtrLinkCount, tot);
376 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
381 /* Internal routines for finding, deleting and adding links
384 GetNewPort() -- find and reserve new alias port number
385 GetSocket() -- try to allocate a socket for a given port
387 Link creation and deletion:
388 CleanupAliasData() - remove all link chains from lookup table
389 IncrementalCleanup() - look for stale links in a single chain
390 DeleteLink() - remove link
392 ReLink() - change link
395 FindLinkOut() - find link for outgoing packets
396 FindLinkIn() - find link for incoming packets
399 FindNewPortGroup() - find an available group of ports
402 /* Local prototypes */
403 static int GetNewPort(struct libalias *, struct alias_link *, int);
404 #ifndef NO_USE_SOCKETS
405 static u_short GetSocket(struct libalias *, u_short, int *, int);
407 static void CleanupAliasData(struct libalias *);
409 static void IncrementalCleanup(struct libalias *);
411 static void DeleteLink(struct alias_link *);
413 static struct alias_link *
414 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
415 u_short, u_short, int, int);
417 static struct alias_link *
418 ReLink(struct alias_link *,
419 struct in_addr, struct in_addr, struct in_addr,
420 u_short, u_short, int, int);
422 static struct alias_link *
423 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
425 static struct alias_link *
426 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
429 #define ALIAS_PORT_BASE 0x08000
430 #define ALIAS_PORT_MASK 0x07fff
431 #define ALIAS_PORT_MASK_EVEN 0x07ffe
432 #define GET_NEW_PORT_MAX_ATTEMPTS 20
434 #define GET_ALIAS_PORT -1
435 #define GET_ALIAS_ID GET_ALIAS_PORT
437 #define FIND_EVEN_ALIAS_BASE 1
439 /* GetNewPort() allocates port numbers. Note that if a port number
440 is already in use, that does not mean that it cannot be used by
441 another link concurrently. This is because GetNewPort() looks for
442 unused triplets: (dest addr, dest port, alias port). */
445 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
452 LIBALIAS_LOCK_ASSERT(la);
454 Description of alias_port_param for GetNewPort(). When
455 this parameter is zero or positive, it precisely specifies
456 the port number. GetNewPort() will return this number
457 without check that it is in use.
459 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
460 selected port number.
463 if (alias_port_param == GET_ALIAS_PORT) {
465 * The aliasing port is automatically selected by one of
468 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
470 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
472 * When the PKT_ALIAS_SAME_PORTS option is chosen,
473 * the first try will be the actual source port. If
474 * this is already in use, the remainder of the
475 * trials will be random.
477 port_net = lnk->src_port;
478 port_sys = ntohs(port_net);
480 /* First trial and all subsequent are random. */
481 port_sys = krandom() & ALIAS_PORT_MASK;
482 port_sys += ALIAS_PORT_BASE;
483 port_net = htons(port_sys);
485 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
486 lnk->alias_port = (u_short) alias_port_param;
489 #ifdef LIBALIAS_DEBUG
490 fprintf(stderr, "PacketAlias/GetNewPort(): ");
491 fprintf(stderr, "input parameter error\n");
497 /* Port number search */
498 for (i = 0; i < max_trials; i++) {
500 struct alias_link *search_result;
502 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
503 lnk->dst_port, port_net,
506 if (search_result == NULL)
508 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
509 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
515 #ifndef NO_USE_SOCKETS
516 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
517 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
518 && ((lnk->link_type == LINK_TCP) ||
519 (lnk->link_type == LINK_UDP))) {
520 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
521 lnk->alias_port = port_net;
526 lnk->alias_port = port_net;
528 #ifndef NO_USE_SOCKETS
532 port_sys = krandom() & ALIAS_PORT_MASK;
533 port_sys += ALIAS_PORT_BASE;
534 port_net = htons(port_sys);
537 #ifdef LIBALIAS_DEBUG
538 fprintf(stderr, "PacketAlias/GetnewPort(): ");
539 fprintf(stderr, "could not find free port\n");
545 #ifndef NO_USE_SOCKETS
547 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
551 struct sockaddr_in sock_addr;
553 LIBALIAS_LOCK_ASSERT(la);
554 if (link_type == LINK_TCP)
555 sock = socket(AF_INET, SOCK_STREAM, 0);
556 else if (link_type == LINK_UDP)
557 sock = socket(AF_INET, SOCK_DGRAM, 0);
559 #ifdef LIBALIAS_DEBUG
560 fprintf(stderr, "PacketAlias/GetSocket(): ");
561 fprintf(stderr, "incorrect link type\n");
567 #ifdef LIBALIAS_DEBUG
568 fprintf(stderr, "PacketAlias/GetSocket(): ");
569 fprintf(stderr, "socket() error %d\n", *sockfd);
573 sock_addr.sin_family = AF_INET;
574 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
575 sock_addr.sin_port = port_net;
578 (struct sockaddr *)&sock_addr,
591 /* FindNewPortGroup() returns a base port number for an available
592 range of contiguous port numbers. Note that if a port number
593 is already in use, that does not mean that it cannot be used by
594 another link concurrently. This is because FindNewPortGroup()
595 looks for unused triplets: (dest addr, dest port, alias port). */
598 FindNewPortGroup(struct libalias *la,
599 struct in_addr dst_addr,
600 struct in_addr alias_addr,
612 LIBALIAS_LOCK_ASSERT(la);
614 * Get link_type from protocol
619 link_type = LINK_UDP;
622 link_type = LINK_TCP;
630 * The aliasing port is automatically selected by one of two
633 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
635 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
637 * When the ALIAS_SAME_PORTS option is chosen, the first
638 * try will be the actual source port. If this is already
639 * in use, the remainder of the trials will be random.
641 port_sys = ntohs(src_port);
645 /* First trial and all subsequent are random. */
646 if (align == FIND_EVEN_ALIAS_BASE)
647 port_sys = krandom() & ALIAS_PORT_MASK_EVEN;
649 port_sys = krandom() & ALIAS_PORT_MASK;
651 port_sys += ALIAS_PORT_BASE;
654 /* Port number search */
655 for (i = 0; i < max_trials; i++) {
657 struct alias_link *search_result;
659 for (j = 0; j < port_count; j++)
660 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
661 dst_port, htons(port_sys + j),
665 /* Found a good range, return base */
667 return (htons(port_sys));
669 /* Find a new base to try */
670 if (align == FIND_EVEN_ALIAS_BASE)
671 port_sys = krandom() & ALIAS_PORT_MASK_EVEN;
673 port_sys = krandom() & ALIAS_PORT_MASK;
675 port_sys += ALIAS_PORT_BASE;
678 #ifdef LIBALIAS_DEBUG
679 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
680 fprintf(stderr, "could not find free port(s)\n");
687 CleanupAliasData(struct libalias *la)
689 struct alias_link *lnk;
692 LIBALIAS_LOCK_ASSERT(la);
693 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
694 lnk = LIST_FIRST(&la->linkTableOut[i]);
695 while (lnk != NULL) {
696 struct alias_link *link_next = LIST_NEXT(lnk, list_out);
702 la->cleanupIndex = 0;
707 IncrementalCleanup(struct libalias *la)
709 struct alias_link *lnk, *lnk_tmp;
711 LIBALIAS_LOCK_ASSERT(la);
713 LIST_FOREACH_MUTABLE(lnk, &la->linkTableOut[la->cleanupIndex++],list_out, lnk_tmp) {
714 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
718 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
719 la->cleanupIndex = 0;
723 DeleteLink(struct alias_link *lnk)
725 struct libalias *la = lnk->la;
727 LIBALIAS_LOCK_ASSERT(la);
728 /* Don't do anything if the link is marked permanent */
729 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
733 /* Delete associated firewall hole, if any */
737 /* Free memory allocated for LSNAT server pool */
738 if (lnk->server != NULL) {
739 struct server *head, *curr, *next;
741 head = curr = lnk->server;
745 } while ((curr = next) != head);
747 /* Adjust output table pointers */
748 LIST_REMOVE(lnk, list_out);
750 /* Adjust input table pointers */
751 LIST_REMOVE(lnk, list_in);
752 #ifndef NO_USE_SOCKETS
753 /* Close socket, if one has been allocated */
754 if (lnk->sockfd != -1) {
759 /* Link-type dependent cleanup */
760 switch (lnk->link_type) {
769 kfree(lnk->data.tcp,M_ALIAS);
774 case LINK_FRAGMENT_ID:
775 la->fragmentIdLinkCount--;
777 case LINK_FRAGMENT_PTR:
778 la->fragmentPtrLinkCount--;
779 if (lnk->data.frag_ptr != NULL)
780 kfree(lnk->data.frag_ptr,M_ALIAS);
785 la->protoLinkCount--;
792 /* Write statistics, if logging enabled */
793 if (la->packetAliasMode & PKT_ALIAS_LOG) {
799 static struct alias_link *
800 AddLink(struct libalias *la, struct in_addr src_addr,
801 struct in_addr dst_addr,
802 struct in_addr alias_addr,
805 int alias_port_param, /* if less than zero, alias */
807 { /* port will be automatically *//* chosen.
809 u_int start_point; /* zero, equal to alias port */
810 struct alias_link *lnk;
812 LIBALIAS_LOCK_ASSERT(la);
813 lnk = kmalloc(sizeof(struct alias_link),M_ALIAS, M_WAITOK | M_ZERO);
815 /* Basic initialization */
817 lnk->src_addr = src_addr;
818 lnk->dst_addr = dst_addr;
819 lnk->alias_addr = alias_addr;
820 lnk->proxy_addr.s_addr = INADDR_ANY;
821 lnk->src_port = src_port;
822 lnk->dst_port = dst_port;
825 lnk->link_type = link_type;
826 #ifndef NO_USE_SOCKETS
831 lnk->timestamp = la->timeStamp;
833 /* Expiration time */
836 lnk->expire_time = ICMP_EXPIRE_TIME;
839 lnk->expire_time = UDP_EXPIRE_TIME;
842 lnk->expire_time = TCP_EXPIRE_INITIAL;
845 lnk->flags |= LINK_PERMANENT; /* no timeout. */
847 case LINK_FRAGMENT_ID:
848 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
850 case LINK_FRAGMENT_PTR:
851 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
856 lnk->expire_time = PROTO_EXPIRE_TIME;
860 /* Determine alias flags */
861 if (dst_addr.s_addr == INADDR_ANY)
862 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
864 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
866 /* Determine alias port */
867 if (GetNewPort(la, lnk, alias_port_param) != 0) {
871 /* Link-type dependent initialization */
873 struct tcp_dat *aux_tcp;
882 aux_tcp = kmalloc(sizeof(struct tcp_dat),M_ALIAS, M_WAITOK | M_ZERO);
883 if (aux_tcp != NULL) {
887 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
888 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
889 aux_tcp->state.index = 0;
890 aux_tcp->state.ack_modified = 0;
891 for (i = 0; i < N_LINK_TCP_DATA; i++)
892 aux_tcp->ack[i].active = 0;
893 aux_tcp->fwhole = -1;
894 lnk->data.tcp = aux_tcp;
896 #ifdef LIBALIAS_DEBUG
897 fprintf(stderr, "PacketAlias/AddLink: ");
898 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
907 case LINK_FRAGMENT_ID:
908 la->fragmentIdLinkCount++;
910 case LINK_FRAGMENT_PTR:
911 la->fragmentPtrLinkCount++;
916 la->protoLinkCount++;
920 /* Set up pointers for output lookup table */
921 start_point = StartPointOut(src_addr, dst_addr,
922 src_port, dst_port, link_type);
923 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
925 /* Set up pointers for input lookup table */
926 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
927 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
929 #ifdef LIBALIAS_DEBUG
930 fprintf(stderr, "PacketAlias/AddLink(): ");
931 fprintf(stderr, "kmalloc() call failed.\n");
934 if (la->packetAliasMode & PKT_ALIAS_LOG) {
940 static struct alias_link *
941 ReLink(struct alias_link *old_lnk,
942 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 struct alias_link *new_lnk; /* zero, equal to alias port */
952 struct libalias *la = old_lnk->la;
954 LIBALIAS_LOCK_ASSERT(la);
955 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
956 src_port, dst_port, alias_port_param,
959 if (new_lnk != NULL &&
960 old_lnk->link_type == LINK_TCP &&
961 old_lnk->data.tcp->fwhole > 0) {
962 PunchFWHole(new_lnk);
969 static struct alias_link *
970 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
971 struct in_addr dst_addr,
975 int replace_partial_links)
978 struct alias_link *lnk;
980 LIBALIAS_LOCK_ASSERT(la);
981 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
982 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
983 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
984 lnk->src_addr.s_addr == src_addr.s_addr &&
985 lnk->src_port == src_port &&
986 lnk->dst_port == dst_port &&
987 lnk->link_type == link_type &&
988 lnk->server == NULL) {
989 lnk->timestamp = la->timeStamp;
994 /* Search for partially specified links. */
995 if (lnk == NULL && replace_partial_links) {
996 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
997 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1000 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1001 dst_port, link_type, 0);
1004 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1005 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1010 src_addr, dst_addr, lnk->alias_addr,
1011 src_port, dst_port, lnk->alias_port,
1018 static struct alias_link *
1019 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1020 struct in_addr dst_addr,
1024 int replace_partial_links)
1026 struct alias_link *lnk;
1028 LIBALIAS_LOCK_ASSERT(la);
1029 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1030 link_type, replace_partial_links);
1034 * The following allows permanent links to be specified as
1035 * using the default source address (i.e. device interface
1036 * address) without knowing in advance what that address
1039 if (la->aliasAddress.s_addr != INADDR_ANY &&
1040 src_addr.s_addr == la->aliasAddress.s_addr) {
1041 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1042 link_type, replace_partial_links);
1049 static struct alias_link *
1050 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1051 struct in_addr alias_addr,
1055 int replace_partial_links)
1059 struct alias_link *lnk;
1060 struct alias_link *lnk_fully_specified;
1061 struct alias_link *lnk_unknown_all;
1062 struct alias_link *lnk_unknown_dst_addr;
1063 struct alias_link *lnk_unknown_dst_port;
1065 LIBALIAS_LOCK_ASSERT(la);
1066 /* Initialize pointers */
1067 lnk_fully_specified = NULL;
1068 lnk_unknown_all = NULL;
1069 lnk_unknown_dst_addr = NULL;
1070 lnk_unknown_dst_port = NULL;
1072 /* If either the dest addr or port is unknown, the search
1073 loop will have to know about this. */
1076 if (dst_addr.s_addr == INADDR_ANY)
1077 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1079 flags_in |= LINK_UNKNOWN_DEST_PORT;
1082 start_point = StartPointIn(alias_addr, alias_port, link_type);
1083 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1086 flags = flags_in | lnk->flags;
1087 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1088 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1089 && lnk->alias_port == alias_port
1090 && lnk->dst_addr.s_addr == dst_addr.s_addr
1091 && lnk->dst_port == dst_port
1092 && lnk->link_type == link_type) {
1093 lnk_fully_specified = lnk;
1096 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1097 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1098 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1099 && lnk->alias_port == alias_port
1100 && lnk->link_type == link_type) {
1101 if (lnk_unknown_all == NULL)
1102 lnk_unknown_all = lnk;
1104 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1105 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1106 && lnk->alias_port == alias_port
1107 && lnk->link_type == link_type
1108 && lnk->dst_port == dst_port) {
1109 if (lnk_unknown_dst_addr == NULL)
1110 lnk_unknown_dst_addr = lnk;
1112 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1113 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1114 && lnk->alias_port == alias_port
1115 && lnk->link_type == link_type
1116 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1117 if (lnk_unknown_dst_port == NULL)
1118 lnk_unknown_dst_port = lnk;
1125 if (lnk_fully_specified != NULL) {
1126 lnk_fully_specified->timestamp = la->timeStamp;
1127 lnk = lnk_fully_specified;
1128 } else if (lnk_unknown_dst_port != NULL)
1129 lnk = lnk_unknown_dst_port;
1130 else if (lnk_unknown_dst_addr != NULL)
1131 lnk = lnk_unknown_dst_addr;
1132 else if (lnk_unknown_all != NULL)
1133 lnk = lnk_unknown_all;
1137 if (replace_partial_links &&
1138 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1139 struct in_addr src_addr;
1142 if (lnk->server != NULL) { /* LSNAT link */
1143 src_addr = lnk->server->addr;
1144 src_port = lnk->server->port;
1145 lnk->server = lnk->server->next;
1147 src_addr = lnk->src_addr;
1148 src_port = lnk->src_port;
1152 src_addr, dst_addr, alias_addr,
1153 src_port, dst_port, alias_port,
1159 static struct alias_link *
1160 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1161 struct in_addr alias_addr,
1165 int replace_partial_links)
1167 struct alias_link *lnk;
1169 LIBALIAS_LOCK_ASSERT(la);
1170 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1171 link_type, replace_partial_links);
1175 * The following allows permanent links to be specified as
1176 * using the default aliasing address (i.e. device
1177 * interface address) without knowing in advance what that
1180 if (la->aliasAddress.s_addr != INADDR_ANY &&
1181 alias_addr.s_addr == la->aliasAddress.s_addr) {
1182 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1183 link_type, replace_partial_links);
1192 /* External routines for finding/adding links
1194 -- "external" means outside alias_db.c, but within alias*.c --
1196 FindIcmpIn(), FindIcmpOut()
1197 FindFragmentIn1(), FindFragmentIn2()
1198 AddFragmentPtrLink(), FindFragmentPtr()
1199 FindProtoIn(), FindProtoOut()
1200 FindUdpTcpIn(), FindUdpTcpOut()
1201 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1202 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1203 FindOriginalAddress(), FindAliasAddress()
1205 (prototypes in alias_local.h)
1210 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1211 struct in_addr alias_addr,
1215 struct alias_link *lnk;
1217 LIBALIAS_LOCK_ASSERT(la);
1218 lnk = FindLinkIn(la, dst_addr, alias_addr,
1219 NO_DEST_PORT, id_alias,
1221 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1222 struct in_addr target_addr;
1224 target_addr = FindOriginalAddress(la, alias_addr);
1225 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1226 id_alias, NO_DEST_PORT, id_alias,
1234 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1235 struct in_addr dst_addr,
1239 struct alias_link *lnk;
1241 LIBALIAS_LOCK_ASSERT(la);
1242 lnk = FindLinkOut(la, src_addr, dst_addr,
1245 if (lnk == NULL && create) {
1246 struct in_addr alias_addr;
1248 alias_addr = FindAliasAddress(la, src_addr);
1249 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1250 id, NO_DEST_PORT, GET_ALIAS_ID,
1258 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1259 struct in_addr alias_addr,
1262 struct alias_link *lnk;
1264 LIBALIAS_LOCK_ASSERT(la);
1265 lnk = FindLinkIn(la, dst_addr, alias_addr,
1266 NO_DEST_PORT, ip_id,
1267 LINK_FRAGMENT_ID, 0);
1270 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1271 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1279 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1281 struct in_addr alias_addr, /* is not found. */
1285 LIBALIAS_LOCK_ASSERT(la);
1286 return FindLinkIn(la, dst_addr, alias_addr,
1287 NO_DEST_PORT, ip_id,
1288 LINK_FRAGMENT_ID, 0);
1293 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1297 LIBALIAS_LOCK_ASSERT(la);
1298 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1299 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1305 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1309 LIBALIAS_LOCK_ASSERT(la);
1310 return FindLinkIn(la, dst_addr, la->nullAddress,
1311 NO_DEST_PORT, ip_id,
1312 LINK_FRAGMENT_PTR, 0);
1317 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1318 struct in_addr alias_addr,
1321 struct alias_link *lnk;
1323 LIBALIAS_LOCK_ASSERT(la);
1324 lnk = FindLinkIn(la, dst_addr, alias_addr,
1328 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1329 struct in_addr target_addr;
1331 target_addr = FindOriginalAddress(la, alias_addr);
1332 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1333 NO_SRC_PORT, NO_DEST_PORT, 0,
1341 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1342 struct in_addr dst_addr,
1345 struct alias_link *lnk;
1347 LIBALIAS_LOCK_ASSERT(la);
1348 lnk = FindLinkOut(la, src_addr, dst_addr,
1349 NO_SRC_PORT, NO_DEST_PORT,
1353 struct in_addr alias_addr;
1355 alias_addr = FindAliasAddress(la, src_addr);
1356 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1357 NO_SRC_PORT, NO_DEST_PORT, 0,
1365 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1366 struct in_addr alias_addr,
1373 struct alias_link *lnk;
1375 LIBALIAS_LOCK_ASSERT(la);
1378 link_type = LINK_UDP;
1381 link_type = LINK_TCP;
1388 lnk = FindLinkIn(la, dst_addr, alias_addr,
1389 dst_port, alias_port,
1392 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1393 struct in_addr target_addr;
1395 target_addr = FindOriginalAddress(la, alias_addr);
1396 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1397 alias_port, dst_port, alias_port,
1405 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1406 struct in_addr dst_addr,
1413 struct alias_link *lnk;
1415 LIBALIAS_LOCK_ASSERT(la);
1418 link_type = LINK_UDP;
1421 link_type = LINK_TCP;
1428 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1430 if (lnk == NULL && create) {
1431 struct in_addr alias_addr;
1433 alias_addr = FindAliasAddress(la, src_addr);
1434 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1435 src_port, dst_port, GET_ALIAS_PORT,
1443 AddPptp(struct libalias *la, struct in_addr src_addr,
1444 struct in_addr dst_addr,
1445 struct in_addr alias_addr,
1446 u_int16_t src_call_id)
1448 struct alias_link *lnk;
1450 LIBALIAS_LOCK_ASSERT(la);
1451 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1452 src_call_id, 0, GET_ALIAS_PORT,
1460 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1461 struct in_addr dst_addr,
1462 u_int16_t src_call_id)
1465 struct alias_link *lnk;
1467 LIBALIAS_LOCK_ASSERT(la);
1468 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1469 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1470 if (lnk->link_type == LINK_PPTP &&
1471 lnk->src_addr.s_addr == src_addr.s_addr &&
1472 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1473 lnk->src_port == src_call_id)
1481 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1482 struct in_addr dst_addr,
1483 u_int16_t dst_call_id)
1486 struct alias_link *lnk;
1488 LIBALIAS_LOCK_ASSERT(la);
1489 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1490 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1491 if (lnk->link_type == LINK_PPTP &&
1492 lnk->src_addr.s_addr == src_addr.s_addr &&
1493 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1494 lnk->dst_port == dst_call_id)
1502 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1503 struct in_addr alias_addr,
1504 u_int16_t dst_call_id)
1507 struct alias_link *lnk;
1509 LIBALIAS_LOCK_ASSERT(la);
1510 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1511 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1512 if (lnk->link_type == LINK_PPTP &&
1513 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1514 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1515 lnk->dst_port == dst_call_id)
1523 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1524 struct in_addr alias_addr,
1525 u_int16_t alias_call_id)
1527 struct alias_link *lnk;
1529 LIBALIAS_LOCK_ASSERT(la);
1530 lnk = FindLinkIn(la, dst_addr, alias_addr,
1531 0 /* any */ , alias_call_id,
1540 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1541 struct in_addr dst_addr,
1547 struct alias_link *lnk;
1549 LIBALIAS_LOCK_ASSERT(la);
1552 link_type = LINK_UDP;
1555 link_type = LINK_TCP;
1562 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1565 struct in_addr alias_addr;
1567 alias_addr = FindAliasAddress(la, src_addr);
1568 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1569 src_port, 0, alias_port,
1577 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1579 struct alias_link *lnk;
1581 LIBALIAS_LOCK_ASSERT(la);
1582 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1583 0, 0, LINK_ADDR, 0);
1585 la->newDefaultLink = 1;
1586 if (la->targetAddress.s_addr == INADDR_ANY)
1587 return (alias_addr);
1588 else if (la->targetAddress.s_addr == INADDR_NONE)
1589 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1590 la->aliasAddress : alias_addr;
1592 return (la->targetAddress);
1594 if (lnk->server != NULL) { /* LSNAT link */
1595 struct in_addr src_addr;
1597 src_addr = lnk->server->addr;
1598 lnk->server = lnk->server->next;
1600 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1601 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1602 la->aliasAddress : alias_addr;
1604 return (lnk->src_addr);
1610 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1612 struct alias_link *lnk;
1614 LIBALIAS_LOCK_ASSERT(la);
1615 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1616 0, 0, LINK_ADDR, 0);
1618 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1619 la->aliasAddress : original_addr;
1621 if (lnk->alias_addr.s_addr == INADDR_ANY)
1622 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1623 la->aliasAddress : original_addr;
1625 return (lnk->alias_addr);
1630 /* External routines for getting or changing link data
1631 (external to alias_db.c, but internal to alias*.c)
1633 SetFragmentData(), GetFragmentData()
1634 SetFragmentPtr(), GetFragmentPtr()
1635 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1636 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1637 GetOriginalPort(), GetAliasPort()
1638 SetAckModified(), GetAckModified()
1639 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1640 SetProtocolFlags(), GetProtocolFlags()
1646 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1648 lnk->data.frag_addr = src_addr;
1653 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1655 *src_addr = lnk->data.frag_addr;
1660 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1662 lnk->data.frag_ptr = fptr;
1667 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1669 *fptr = lnk->data.frag_ptr;
1674 SetStateIn(struct alias_link *lnk, int state)
1676 /* TCP input state */
1678 case ALIAS_TCP_STATE_DISCONNECTED:
1679 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1680 lnk->expire_time = TCP_EXPIRE_DEAD;
1682 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1684 case ALIAS_TCP_STATE_CONNECTED:
1685 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1686 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1690 panic("libalias:SetStateIn() unknown state");
1695 lnk->data.tcp->state.in = state;
1700 SetStateOut(struct alias_link *lnk, int state)
1702 /* TCP output state */
1704 case ALIAS_TCP_STATE_DISCONNECTED:
1705 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1706 lnk->expire_time = TCP_EXPIRE_DEAD;
1708 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1710 case ALIAS_TCP_STATE_CONNECTED:
1711 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1712 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1716 panic("libalias:SetStateOut() unknown state");
1721 lnk->data.tcp->state.out = state;
1726 GetStateIn(struct alias_link *lnk)
1728 /* TCP input state */
1729 return (lnk->data.tcp->state.in);
1734 GetStateOut(struct alias_link *lnk)
1736 /* TCP output state */
1737 return (lnk->data.tcp->state.out);
1742 GetOriginalAddress(struct alias_link *lnk)
1744 if (lnk->src_addr.s_addr == INADDR_ANY)
1745 return (lnk->la->aliasAddress);
1747 return (lnk->src_addr);
1752 GetDestAddress(struct alias_link *lnk)
1754 return (lnk->dst_addr);
1759 GetAliasAddress(struct alias_link *lnk)
1761 if (lnk->alias_addr.s_addr == INADDR_ANY)
1762 return (lnk->la->aliasAddress);
1764 return (lnk->alias_addr);
1769 GetDefaultAliasAddress(struct libalias *la)
1772 LIBALIAS_LOCK_ASSERT(la);
1773 return (la->aliasAddress);
1778 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1781 LIBALIAS_LOCK_ASSERT(la);
1782 la->aliasAddress = alias_addr;
1787 GetOriginalPort(struct alias_link *lnk)
1789 return (lnk->src_port);
1794 GetAliasPort(struct alias_link *lnk)
1796 return (lnk->alias_port);
1801 GetDestPort(struct alias_link *lnk)
1803 return (lnk->dst_port);
1809 SetAckModified(struct alias_link *lnk)
1811 /* Indicate that ACK numbers have been modified in a TCP connection */
1812 lnk->data.tcp->state.ack_modified = 1;
1817 GetProxyAddress(struct alias_link *lnk)
1819 return (lnk->proxy_addr);
1824 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1826 lnk->proxy_addr = addr;
1831 GetProxyPort(struct alias_link *lnk)
1833 return (lnk->proxy_port);
1838 SetProxyPort(struct alias_link *lnk, u_short port)
1840 lnk->proxy_port = port;
1845 GetAckModified(struct alias_link *lnk)
1847 /* See if ACK numbers have been modified */
1848 return (lnk->data.tcp->state.ack_modified);
1853 GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
1856 Find out how much the ACK number has been altered for an incoming
1857 TCP packet. To do this, a circular list of ACK numbers where the TCP
1858 packet size was altered is searched.
1863 int delta, ack_diff_min;
1871 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1872 struct ack_data_record x;
1874 x = lnk->data.tcp->ack[i];
1875 if (x.active == 1) {
1878 ack_diff = SeqDiff(x.ack_new, ack);
1879 if (ack_diff >= 0) {
1880 if (ack_diff_min >= 0) {
1881 if (ack_diff < ack_diff_min) {
1883 ack_diff_min = ack_diff;
1887 ack_diff_min = ack_diff;
1897 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
1900 Find out how much the sequence number has been altered for an outgoing
1901 TCP packet. To do this, a circular list of ACK numbers where the TCP
1902 packet size was altered is searched.
1907 int delta, seq_diff_min;
1915 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1916 struct ack_data_record x;
1918 x = lnk->data.tcp->ack[i];
1919 if (x.active == 1) {
1922 seq_diff = SeqDiff(x.ack_old, seq);
1923 if (seq_diff >= 0) {
1924 if (seq_diff_min >= 0) {
1925 if (seq_diff < seq_diff_min) {
1927 seq_diff_min = seq_diff;
1931 seq_diff_min = seq_diff;
1941 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
1944 When a TCP packet has been altered in length, save this
1945 information in a circular list. If enough packets have
1946 been altered, then this list will begin to overwrite itself.
1950 struct ack_data_record x;
1951 int hlen, tlen, dlen;
1956 hlen = (pip->ip_hl + tc->th_off) << 2;
1957 tlen = ntohs(pip->ip_len);
1960 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1961 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1965 i = lnk->data.tcp->state.index;
1966 lnk->data.tcp->ack[i] = x;
1969 if (i == N_LINK_TCP_DATA)
1970 lnk->data.tcp->state.index = 0;
1972 lnk->data.tcp->state.index = i;
1976 SetExpire(struct alias_link *lnk, int expire)
1979 lnk->flags &= ~LINK_PERMANENT;
1981 } else if (expire == -1) {
1982 lnk->flags |= LINK_PERMANENT;
1983 } else if (expire > 0) {
1984 lnk->expire_time = expire;
1986 #ifdef LIBALIAS_DEBUG
1987 fprintf(stderr, "PacketAlias/SetExpire(): ");
1988 fprintf(stderr, "error in expire parameter\n");
1994 ClearCheckNewLink(struct libalias *la)
1997 LIBALIAS_LOCK_ASSERT(la);
1998 la->newDefaultLink = 0;
2002 SetProtocolFlags(struct alias_link *lnk, int pflags)
2005 lnk->pflags = pflags;;
2009 GetProtocolFlags(struct alias_link *lnk)
2012 return (lnk->pflags);
2016 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2018 struct libalias *la = lnk->la;
2020 LIBALIAS_LOCK_ASSERT(la);
2021 la->deleteAllLinks = 1;
2022 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2023 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2024 la->deleteAllLinks = 0;
2028 /* Miscellaneous Functions
2031 InitPacketAliasLog()
2032 UninitPacketAliasLog()
2036 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2037 is called to find and remove timed-out aliasing links. Logic exists
2038 to sweep through the entire table and linked list structure
2041 (prototype in alias_local.h)
2045 HouseKeeping(struct libalias *la)
2053 LIBALIAS_LOCK_ASSERT(la);
2055 * Save system time (seconds) in global variable timeStamp for use
2056 * by other functions. This is done so as not to unnecessarily
2057 * waste timeline by making system calls.
2060 la->timeStamp = time_uptime;
2062 gettimeofday(&tv, &tz);
2063 la->timeStamp = tv.tv_sec;
2066 /* Compute number of spokes (output table link chains) to cover */
2067 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2068 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2070 /* Handle different cases */
2072 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2073 n = ALIAS_CLEANUP_MAX_SPOKES;
2074 la->lastCleanupTime = la->timeStamp;
2075 for (i = 0; i < n; i++)
2076 IncrementalCleanup(la);
2078 #ifdef LIBALIAS_DEBUG
2079 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2080 fprintf(stderr, "something unexpected in time values\n");
2082 la->lastCleanupTime = la->timeStamp;
2086 /* Init the log file and enable logging */
2088 InitPacketAliasLog(struct libalias *la)
2091 LIBALIAS_LOCK_ASSERT(la);
2092 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2094 if ((la->logDesc = kmalloc(LIBALIAS_BUF_SIZE,M_ALIAS, M_WAITOK | M_ZERO)))
2097 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2098 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2101 return (ENOMEM); /* log initialization failed */
2102 la->packetAliasMode |= PKT_ALIAS_LOG;
2108 /* Close the log-file and disable logging. */
2110 UninitPacketAliasLog(struct libalias *la)
2113 LIBALIAS_LOCK_ASSERT(la);
2116 kfree(la->logDesc,M_ALIAS);
2118 fclose(la->logDesc);
2122 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2125 /* Outside world interfaces
2127 -- "outside world" means other than alias*.c routines --
2129 PacketAliasRedirectPort()
2130 PacketAliasAddServer()
2131 PacketAliasRedirectProto()
2132 PacketAliasRedirectAddr()
2133 PacketAliasRedirectDynamic()
2134 PacketAliasRedirectDelete()
2135 PacketAliasSetAddress()
2138 PacketAliasSetMode()
2140 (prototypes in alias.h)
2143 /* Redirection from a specific public addr:port to a
2144 private addr:port */
2146 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2147 struct in_addr dst_addr, u_short dst_port,
2148 struct in_addr alias_addr, u_short alias_port,
2152 struct alias_link *lnk;
2157 link_type = LINK_UDP;
2160 link_type = LINK_TCP;
2163 #ifdef LIBALIAS_DEBUG
2164 fprintf(stderr, "PacketAliasRedirectPort(): ");
2165 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2171 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2172 src_port, dst_port, alias_port,
2176 lnk->flags |= LINK_PERMANENT;
2178 #ifdef LIBALIAS_DEBUG
2180 fprintf(stderr, "PacketAliasRedirectPort(): "
2181 "call to AddLink() failed\n");
2186 LIBALIAS_UNLOCK(la);
2190 /* Add server to the pool of servers */
2192 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2194 struct server *server;
2200 server = kmalloc(sizeof(struct server),M_ALIAS, M_WAITOK | M_ZERO);
2202 if (server != NULL) {
2203 struct server *head;
2205 server->addr = addr;
2206 server->port = port;
2210 server->next = server;
2214 for (s = head; s->next != head; s = s->next);
2216 server->next = head;
2218 lnk->server = server;
2223 LIBALIAS_UNLOCK(la);
2227 /* Redirect packets of a given IP protocol from a specific
2228 public address to a private address */
2230 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2231 struct in_addr dst_addr,
2232 struct in_addr alias_addr,
2235 struct alias_link *lnk;
2238 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2239 NO_SRC_PORT, NO_DEST_PORT, 0,
2243 lnk->flags |= LINK_PERMANENT;
2245 #ifdef LIBALIAS_DEBUG
2247 fprintf(stderr, "PacketAliasRedirectProto(): "
2248 "call to AddLink() failed\n");
2252 LIBALIAS_UNLOCK(la);
2256 /* Static address translation */
2258 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2259 struct in_addr alias_addr)
2261 struct alias_link *lnk;
2264 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2269 lnk->flags |= LINK_PERMANENT;
2271 #ifdef LIBALIAS_DEBUG
2273 fprintf(stderr, "PacketAliasRedirectAddr(): "
2274 "call to AddLink() failed\n");
2278 LIBALIAS_UNLOCK(la);
2283 /* Mark the aliasing link dynamic */
2285 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2292 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2295 lnk->flags &= ~LINK_PERMANENT;
2298 LIBALIAS_UNLOCK(la);
2304 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2306 /* This is a dangerous function to put in the API,
2307 because an invalid pointer can crash the program. */
2310 la->deleteAllLinks = 1;
2312 la->deleteAllLinks = 0;
2313 LIBALIAS_UNLOCK(la);
2318 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2322 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2323 && la->aliasAddress.s_addr != addr.s_addr)
2324 CleanupAliasData(la);
2326 la->aliasAddress = addr;
2327 LIBALIAS_UNLOCK(la);
2332 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2336 la->targetAddress = target_addr;
2337 LIBALIAS_UNLOCK(la);
2344 while (!LIST_EMPTY(&instancehead))
2345 LibAliasUninit(LIST_FIRST(&instancehead));
2349 LibAliasInit(struct libalias *la)
2358 la = kmalloc(sizeof *la,M_ALIAS, M_WAITOK | M_ZERO);
2362 #ifndef _KERNEL /* kernel cleans up on module unload */
2363 if (LIST_EMPTY(&instancehead))
2366 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2369 la->timeStamp = time_uptime;
2370 la->lastCleanupTime = time_uptime;
2372 gettimeofday(&tv, &tz);
2373 la->timeStamp = tv.tv_sec;
2374 la->lastCleanupTime = tv.tv_sec;
2377 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2378 LIST_INIT(&la->linkTableOut[i]);
2379 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2380 LIST_INIT(&la->linkTableIn[i]);
2381 LIBALIAS_LOCK_INIT(la);
2385 la->deleteAllLinks = 1;
2386 CleanupAliasData(la);
2387 la->deleteAllLinks = 0;
2390 la->aliasAddress.s_addr = INADDR_ANY;
2391 la->targetAddress.s_addr = INADDR_ANY;
2393 la->icmpLinkCount = 0;
2394 la->udpLinkCount = 0;
2395 la->tcpLinkCount = 0;
2396 la->pptpLinkCount = 0;
2397 la->protoLinkCount = 0;
2398 la->fragmentIdLinkCount = 0;
2399 la->fragmentPtrLinkCount = 0;
2402 la->cleanupIndex = 0;
2404 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2405 #ifndef NO_USE_SOCKETS
2406 | PKT_ALIAS_USE_SOCKETS
2408 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2410 la->fireWallFD = -1;
2413 LibAliasRefreshModules();
2415 LIBALIAS_UNLOCK(la);
2420 LibAliasUninit(struct libalias *la)
2424 la->deleteAllLinks = 1;
2425 CleanupAliasData(la);
2426 la->deleteAllLinks = 0;
2427 UninitPacketAliasLog(la);
2431 LIST_REMOVE(la, instancelist);
2432 LIBALIAS_UNLOCK(la);
2433 LIBALIAS_LOCK_DESTROY(la);
2437 /* Change mode for some operations */
2440 struct libalias *la,
2441 unsigned int flags, /* Which state to bring flags to */
2442 unsigned int mask /* Mask of which flags to affect (use 0 to
2443 * do a probe for flag values) */
2449 /* Enable logging? */
2450 if (flags & mask & PKT_ALIAS_LOG) {
2452 if (InitPacketAliasLog(la) == ENOMEM)
2455 /* _Disable_ logging? */
2456 if (~flags & mask & PKT_ALIAS_LOG) {
2457 UninitPacketAliasLog(la);
2460 /* Start punching holes in the firewall? */
2461 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2464 /* Stop punching holes in the firewall? */
2465 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2470 /* Other flags can be set/cleared without special action */
2471 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2472 res = la->packetAliasMode;
2474 LIBALIAS_UNLOCK(la);
2480 LibAliasCheckNewLink(struct libalias *la)
2485 res = la->newDefaultLink;
2486 LIBALIAS_UNLOCK(la);
2494 Code to support firewall punching. This shouldn't really be in this
2495 file, but making variables global is evil too.
2498 /* Firewall include files */
2500 #include <netinet/ip_fw.h>
2505 * helper function, updates the pointer to cmd with the length
2506 * of the current command, and also cleans up the first word of
2507 * the new command in case it has been clobbered before.
2510 next_cmd(ipfw_insn * cmd)
2513 bzero(cmd, sizeof(*cmd));
2518 * A function to fill simple commands of size 1.
2519 * Existing flags are preserved.
2522 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2523 int flags, u_int16_t arg)
2525 cmd->opcode = opcode;
2526 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2528 return next_cmd(cmd);
2532 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2534 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2536 cmd->addr.s_addr = addr;
2537 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2541 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2543 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2545 cmd->ports[0] = cmd->ports[1] = port;
2546 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2550 fill_rule(void *buf, int bufsize, int rulenum,
2551 enum ipfw_opcodes action, int proto,
2552 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2554 struct ip_fw *rule = (struct ip_fw *)buf;
2555 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2557 bzero(buf, bufsize);
2558 rule->rulenum = rulenum;
2560 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2561 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2562 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2563 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2564 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2566 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2567 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2569 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2571 return ((char *)cmd - (char *)buf);
2574 static void ClearAllFWHoles(struct libalias *la);
2577 #define fw_setfield(la, field, num) \
2579 (field)[(num) - la->fireWallBaseNum] = 1; \
2580 } /*lint -save -e717 */ while(0)/* lint -restore */
2582 #define fw_clrfield(la, field, num) \
2584 (field)[(num) - la->fireWallBaseNum] = 0; \
2585 } /*lint -save -e717 */ while(0)/* lint -restore */
2587 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2590 InitPunchFW(struct libalias *la)
2593 LIBALIAS_LOCK_ASSERT(la);
2594 la->fireWallField = kmalloc(la->fireWallNumNums,M_ALIAS, M_WAITOK | M_ZERO);
2595 if (la->fireWallField) {
2596 memset(la->fireWallField, 0, la->fireWallNumNums);
2597 if (la->fireWallFD < 0) {
2598 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2600 ClearAllFWHoles(la);
2601 la->fireWallActiveNum = la->fireWallBaseNum;
2606 UninitPunchFW(struct libalias *la)
2609 LIBALIAS_LOCK_ASSERT(la);
2610 ClearAllFWHoles(la);
2611 if (la->fireWallFD >= 0)
2612 close(la->fireWallFD);
2613 la->fireWallFD = -1;
2614 if (la->fireWallField)
2615 kfree(la->fireWallField,M_ALIAS);
2616 la->fireWallField = NULL;
2617 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2620 /* Make a certain link go through the firewall */
2622 PunchFWHole(struct alias_link *lnk)
2624 struct libalias *la;
2625 int r; /* Result code */
2626 struct ip_fw rule; /* On-the-fly built rule */
2627 int fwhole; /* Where to punch hole */
2629 LIBALIAS_LOCK_ASSERT(la);
2632 /* Don't do anything unless we are asked to */
2633 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2634 la->fireWallFD < 0 ||
2635 lnk->link_type != LINK_TCP)
2638 memset(&rule, 0, sizeof rule);
2642 /* Find empty slot */
2643 for (fwhole = la->fireWallActiveNum;
2644 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2645 fw_tstfield(la, la->fireWallField, fwhole);
2647 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2648 for (fwhole = la->fireWallBaseNum;
2649 fwhole < la->fireWallActiveNum &&
2650 fw_tstfield(la, la->fireWallField, fwhole);
2652 if (fwhole == la->fireWallActiveNum) {
2653 /* No rule point empty - we can't punch more holes. */
2654 la->fireWallActiveNum = la->fireWallBaseNum;
2655 #ifdef LIBALIAS_DEBUG
2656 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2661 /* Start next search at next position */
2662 la->fireWallActiveNum = fwhole + 1;
2665 * generate two rules of the form
2667 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2668 * accept tcp from DAddr DPort to OAddr OPort
2670 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2671 u_int32_t rulebuf[255];
2674 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2675 O_ACCEPT, IPPROTO_TCP,
2676 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2677 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2678 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2680 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2682 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2683 O_ACCEPT, IPPROTO_TCP,
2684 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2685 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2686 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2688 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2691 /* Indicate hole applied */
2692 lnk->data.tcp->fwhole = fwhole;
2693 fw_setfield(la, la->fireWallField, fwhole);
2696 /* Remove a hole in a firewall associated with a particular alias
2697 lnk. Calling this too often is harmless. */
2699 ClearFWHole(struct alias_link *lnk)
2701 struct libalias *la;
2703 LIBALIAS_LOCK_ASSERT(la);
2705 if (lnk->link_type == LINK_TCP) {
2706 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2713 memset(&rule, 0, sizeof rule); /* useless for ipfw3 */
2714 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2715 &fwhole, sizeof fwhole));
2716 fw_clrfield(la, la->fireWallField, fwhole);
2717 lnk->data.tcp->fwhole = -1;
2721 /* Clear out the entire range dedicated to firewall holes. */
2723 ClearAllFWHoles(struct libalias *la)
2725 struct ip_fw rule; /* On-the-fly built rule */
2728 LIBALIAS_LOCK_ASSERT(la);
2729 if (la->fireWallFD < 0)
2732 memset(&rule, 0, sizeof rule);
2733 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2736 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2738 /* XXX: third arg correct here ? /phk */
2739 memset(la->fireWallField, 0, la->fireWallNumNums);
2745 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2750 la->fireWallBaseNum = base;
2751 la->fireWallNumNums = num;
2753 LIBALIAS_UNLOCK(la);
2757 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2761 la->skinnyPort = port;
2762 LIBALIAS_UNLOCK(la);