New ipfw2 for DragonflyBSD which is able to run parallelly with the original ipfw.
[dragonfly.git] / sys / net / libalias / alias_db.c
blob2c00e0c0e01a78ff6667ebdaf2170e0777a3455c
1 /*-
2 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
24 * SUCH DAMAGE.
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
41 fragments.
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.)
100 Examples:
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
105 unknown dest port
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
120 v1.9).
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
125 host address.
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
140 as input.
142 See HISTORY file for additional revisions.
144 #ifdef _KERNEL
145 #include <stdarg.h>
146 #include <sys/param.h>
147 #include <sys/kernel.h>
148 #include <sys/module.h>
149 #include <sys/syslog.h>
150 #include <sys/queue.h>
151 #else
152 #include <stdarg.h>
153 #include <stdlib.h>
154 #include <stdio.h>
155 #include <sys/errno.h>
156 #include <sys/time.h>
157 #include <unistd.h>
158 #endif
160 #include <sys/socket.h>
161 #include <netinet/tcp.h>
163 #include "alias.h"
164 #include "alias_local.h"
165 #include "alias_mod.h"
168 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
172 Constants (note: constants are also defined
173 near relevant functions or structs)
176 /* Parameters used for cleanup of expired links */
177 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
178 #define ALIAS_CLEANUP_INTERVAL_SECS 64
179 #define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
181 /* Timeouts (in seconds) for different link types */
182 #define ICMP_EXPIRE_TIME 60
183 #define UDP_EXPIRE_TIME 60
184 #define PROTO_EXPIRE_TIME 60
185 #define FRAGMENT_ID_EXPIRE_TIME 10
186 #define FRAGMENT_PTR_EXPIRE_TIME 30
188 /* TCP link expire time for different cases */
189 /* When the link has been used and closed - minimal grace time to
190 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
191 #ifndef TCP_EXPIRE_DEAD
192 #define TCP_EXPIRE_DEAD 10
193 #endif
195 /* When the link has been used and closed on one side - the other side
196 is allowed to still send data */
197 #ifndef TCP_EXPIRE_SINGLEDEAD
198 #define TCP_EXPIRE_SINGLEDEAD 90
199 #endif
201 /* When the link isn't yet up */
202 #ifndef TCP_EXPIRE_INITIAL
203 #define TCP_EXPIRE_INITIAL 300
204 #endif
206 /* When the link is up */
207 #ifndef TCP_EXPIRE_CONNECTED
208 #define TCP_EXPIRE_CONNECTED 86400
209 #endif
212 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
213 These constants can be anything except zero, which indicates an
214 unknown port number. */
216 #define NO_DEST_PORT 1
217 #define NO_SRC_PORT 1
220 /* Data Structures
222 The fundamental data structure used in this program is
223 "struct alias_link". Whenever a TCP connection is made,
224 a UDP datagram is sent out, or an ICMP echo request is made,
225 a link record is made (if it has not already been created).
226 The link record is identified by the source address/port
227 and the destination address/port. In the case of an ICMP
228 echo request, the source port is treated as being equivalent
229 with the 16-bit ID number of the ICMP packet.
231 The link record also can store some auxiliary data. For
232 TCP connections that have had sequence and acknowledgment
233 modifications, data space is available to track these changes.
234 A state field is used to keep track in changes to the TCP
235 connection state. ID numbers of fragments can also be
236 stored in the auxiliary space. Pointers to unresolved
237 fragments can also be stored.
239 The link records support two independent chainings. Lookup
240 tables for input and out tables hold the initial pointers
241 the link chains. On input, the lookup table indexes on alias
242 port and link type. On output, the lookup table indexes on
243 source address, destination address, source port, destination
244 port and link type.
247 struct ack_data_record { /* used to save changes to ACK/sequence
248 * numbers */
249 u_long ack_old;
250 u_long ack_new;
251 int delta;
252 int active;
255 struct tcp_state { /* Information about TCP connection */
256 int in; /* State for outside -> inside */
257 int out; /* State for inside -> outside */
258 int index; /* Index to ACK data array */
259 int ack_modified; /* Indicates whether ACK and
260 * sequence numbers */
261 /* been modified */
264 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
265 * saved for a modified TCP stream */
266 struct tcp_dat {
267 struct tcp_state state;
268 struct ack_data_record ack[N_LINK_TCP_DATA];
269 int fwhole; /* Which firewall record is used for this
270 * hole? */
273 struct server { /* LSNAT server pool (circular list) */
274 struct in_addr addr;
275 u_short port;
276 struct server *next;
279 struct alias_link { /* Main data structure */
280 struct libalias *la;
281 struct in_addr src_addr; /* Address and port information */
282 struct in_addr dst_addr;
283 struct in_addr alias_addr;
284 struct in_addr proxy_addr;
285 u_short src_port;
286 u_short dst_port;
287 u_short alias_port;
288 u_short proxy_port;
289 struct server *server;
291 int link_type; /* Type of link: TCP, UDP, ICMP,
292 * proto, frag */
294 /* values for link_type */
295 #define LINK_ICMP IPPROTO_ICMP
296 #define LINK_UDP IPPROTO_UDP
297 #define LINK_TCP IPPROTO_TCP
298 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
299 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
300 #define LINK_ADDR (IPPROTO_MAX + 3)
301 #define LINK_PPTP (IPPROTO_MAX + 4)
303 int flags; /* indicates special characteristics */
304 int pflags; /* protocol-specific flags */
306 /* flag bits */
307 #define LINK_UNKNOWN_DEST_PORT 0x01
308 #define LINK_UNKNOWN_DEST_ADDR 0x02
309 #define LINK_PERMANENT 0x04
310 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
311 #define LINK_UNFIREWALLED 0x08
313 int timestamp; /* Time link was last accessed */
314 int expire_time; /* Expire time for link */
315 #ifndef NO_USE_SOCKETS
316 int sockfd; /* socket descriptor */
317 #endif
318 LIST_ENTRY (alias_link) list_out; /* Linked list of
319 * pointers for */
320 LIST_ENTRY (alias_link) list_in; /* input and output
321 * lookup tables */
323 union { /* Auxiliary data */
324 char *frag_ptr;
325 struct in_addr frag_addr;
326 struct tcp_dat *tcp;
327 } data;
330 /* Clean up procedure. */
331 static void finishoff(void);
333 /* Kernel module definition. */
334 #ifdef _KERNEL
335 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
337 MODULE_VERSION(libalias, 1);
339 static int
340 alias_mod_handler(module_t mod, int type, void *data)
342 int error;
344 switch (type) {
345 case MOD_LOAD:
346 error = 0;
347 handler_chain_init();
348 break;
349 case MOD_UNLOAD:
350 handler_chain_destroy();
351 finishoff();
352 error = 0;
353 break;
354 default:
355 error = EINVAL;
358 return (error);
361 static moduledata_t alias_mod = {
362 "alias", alias_mod_handler, NULL
365 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
366 #endif
368 /* Internal utility routines (used only in alias_db.c)
370 Lookup table starting points:
371 StartPointIn() -- link table initial search point for
372 incoming packets
373 StartPointOut() -- link table initial search point for
374 outgoing packets
376 Miscellaneous:
377 SeqDiff() -- difference between two TCP sequences
378 ShowAliasStats() -- send alias statistics to a monitor file
382 /* Local prototypes */
383 static u_int StartPointIn(struct in_addr, u_short, int);
385 static u_int
386 StartPointOut(struct in_addr, struct in_addr,
387 u_short, u_short, int);
389 static int SeqDiff(u_long, u_long);
391 #ifndef NO_FW_PUNCH
392 /* Firewall control */
393 static void InitPunchFW(struct libalias *);
394 static void UninitPunchFW(struct libalias *);
395 static void ClearFWHole(struct alias_link *);
397 #endif
399 /* Log file control */
400 static void ShowAliasStats(struct libalias *);
401 static int InitPacketAliasLog(struct libalias *);
402 static void UninitPacketAliasLog(struct libalias *);
404 static u_int
405 StartPointIn(struct in_addr alias_addr,
406 u_short alias_port,
407 int link_type)
409 u_int n;
411 n = alias_addr.s_addr;
412 if (link_type != LINK_PPTP)
413 n += alias_port;
414 n += link_type;
415 return (n % LINK_TABLE_IN_SIZE);
419 static u_int
420 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
421 u_short src_port, u_short dst_port, int link_type)
423 u_int n;
425 n = src_addr.s_addr;
426 n += dst_addr.s_addr;
427 if (link_type != LINK_PPTP) {
428 n += src_port;
429 n += dst_port;
431 n += link_type;
433 return (n % LINK_TABLE_OUT_SIZE);
437 static int
438 SeqDiff(u_long x, u_long y)
440 /* Return the difference between two TCP sequence numbers */
443 This function is encapsulated in case there are any unusual
444 arithmetic conditions that need to be considered.
447 return (ntohl(y) - ntohl(x));
450 #ifdef _KERNEL
452 static void
453 AliasLog(char *str, const char *format, ...)
455 va_list ap;
457 va_start(ap, format);
458 kvsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
459 va_end(ap);
461 #else
462 static void
463 AliasLog(FILE *stream, const char *format, ...)
465 va_list ap;
467 va_start(ap, format);
468 vfprintf(stream, format, ap);
469 va_end(ap);
470 fflush(stream);
472 #endif
474 static void
475 ShowAliasStats(struct libalias *la)
478 LIBALIAS_LOCK_ASSERT(la);
479 /* Used for debugging */
480 if (la->logDesc) {
481 int tot = la->icmpLinkCount + la->udpLinkCount +
482 la->tcpLinkCount + la->pptpLinkCount +
483 la->protoLinkCount + la->fragmentIdLinkCount +
484 la->fragmentPtrLinkCount;
486 AliasLog(la->logDesc,
487 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
488 la->icmpLinkCount,
489 la->udpLinkCount,
490 la->tcpLinkCount,
491 la->pptpLinkCount,
492 la->protoLinkCount,
493 la->fragmentIdLinkCount,
494 la->fragmentPtrLinkCount, tot);
495 #ifndef _KERNEL
496 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
497 #endif
501 /* Internal routines for finding, deleting and adding links
503 Port Allocation:
504 GetNewPort() -- find and reserve new alias port number
505 GetSocket() -- try to allocate a socket for a given port
507 Link creation and deletion:
508 CleanupAliasData() - remove all link chains from lookup table
509 IncrementalCleanup() - look for stale links in a single chain
510 DeleteLink() - remove link
511 AddLink() - add link
512 ReLink() - change link
514 Link search:
515 FindLinkOut() - find link for outgoing packets
516 FindLinkIn() - find link for incoming packets
518 Port search:
519 FindNewPortGroup() - find an available group of ports
522 /* Local prototypes */
523 static int GetNewPort(struct libalias *, struct alias_link *, int);
524 #ifndef NO_USE_SOCKETS
525 static u_short GetSocket(struct libalias *, u_short, int *, int);
526 #endif
527 static void CleanupAliasData(struct libalias *);
529 static void IncrementalCleanup(struct libalias *);
531 static void DeleteLink(struct alias_link *);
533 static struct alias_link *
534 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
535 u_short, u_short, int, int);
537 static struct alias_link *
538 ReLink(struct alias_link *,
539 struct in_addr, struct in_addr, struct in_addr,
540 u_short, u_short, int, int);
542 static struct alias_link *
543 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
545 static struct alias_link *
546 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
549 #define ALIAS_PORT_BASE 0x08000
550 #define ALIAS_PORT_MASK 0x07fff
551 #define ALIAS_PORT_MASK_EVEN 0x07ffe
552 #define GET_NEW_PORT_MAX_ATTEMPTS 20
554 #define GET_ALIAS_PORT -1
555 #define GET_ALIAS_ID GET_ALIAS_PORT
557 #define FIND_EVEN_ALIAS_BASE 1
559 /* GetNewPort() allocates port numbers. Note that if a port number
560 is already in use, that does not mean that it cannot be used by
561 another link concurrently. This is because GetNewPort() looks for
562 unused triplets: (dest addr, dest port, alias port). */
564 static int
565 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
567 int i;
568 int max_trials;
569 u_short port_sys;
570 u_short port_net;
572 LIBALIAS_LOCK_ASSERT(la);
574 Description of alias_port_param for GetNewPort(). When
575 this parameter is zero or positive, it precisely specifies
576 the port number. GetNewPort() will return this number
577 without check that it is in use.
579 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
580 selected port number.
583 if (alias_port_param == GET_ALIAS_PORT) {
585 * The aliasing port is automatically selected by one of
586 * two methods below:
588 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
590 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
592 * When the PKT_ALIAS_SAME_PORTS option is chosen,
593 * the first try will be the actual source port. If
594 * this is already in use, the remainder of the
595 * trials will be random.
597 port_net = lnk->src_port;
598 port_sys = ntohs(port_net);
599 } else {
600 /* First trial and all subsequent are random. */
601 port_sys = krandom() & ALIAS_PORT_MASK;
602 port_sys += ALIAS_PORT_BASE;
603 port_net = htons(port_sys);
605 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
606 lnk->alias_port = (u_short) alias_port_param;
607 return (0);
608 } else {
609 #ifdef LIBALIAS_DEBUG
610 fprintf(stderr, "PacketAlias/GetNewPort(): ");
611 fprintf(stderr, "input parameter error\n");
612 #endif
613 return (-1);
617 /* Port number search */
618 for (i = 0; i < max_trials; i++) {
619 int go_ahead;
620 struct alias_link *search_result;
622 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
623 lnk->dst_port, port_net,
624 lnk->link_type, 0);
626 if (search_result == NULL)
627 go_ahead = 1;
628 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
629 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
630 go_ahead = 1;
631 else
632 go_ahead = 0;
634 if (go_ahead) {
635 #ifndef NO_USE_SOCKETS
636 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
637 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
638 && ((lnk->link_type == LINK_TCP) ||
639 (lnk->link_type == LINK_UDP))) {
640 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
641 lnk->alias_port = port_net;
642 return (0);
644 } else {
645 #endif
646 lnk->alias_port = port_net;
647 return (0);
648 #ifndef NO_USE_SOCKETS
650 #endif
652 port_sys = krandom() & ALIAS_PORT_MASK;
653 port_sys += ALIAS_PORT_BASE;
654 port_net = htons(port_sys);
657 #ifdef LIBALIAS_DEBUG
658 fprintf(stderr, "PacketAlias/GetnewPort(): ");
659 fprintf(stderr, "could not find free port\n");
660 #endif
662 return (-1);
665 #ifndef NO_USE_SOCKETS
666 static u_short
667 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
669 int err;
670 int sock;
671 struct sockaddr_in sock_addr;
673 LIBALIAS_LOCK_ASSERT(la);
674 if (link_type == LINK_TCP)
675 sock = socket(AF_INET, SOCK_STREAM, 0);
676 else if (link_type == LINK_UDP)
677 sock = socket(AF_INET, SOCK_DGRAM, 0);
678 else {
679 #ifdef LIBALIAS_DEBUG
680 fprintf(stderr, "PacketAlias/GetSocket(): ");
681 fprintf(stderr, "incorrect link type\n");
682 #endif
683 return (0);
686 if (sock < 0) {
687 #ifdef LIBALIAS_DEBUG
688 fprintf(stderr, "PacketAlias/GetSocket(): ");
689 fprintf(stderr, "socket() error %d\n", *sockfd);
690 #endif
691 return (0);
693 sock_addr.sin_family = AF_INET;
694 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
695 sock_addr.sin_port = port_net;
697 err = bind(sock,
698 (struct sockaddr *)&sock_addr,
699 sizeof(sock_addr));
700 if (err == 0) {
701 la->sockCount++;
702 *sockfd = sock;
703 return (1);
704 } else {
705 close(sock);
706 return (0);
709 #endif
711 /* FindNewPortGroup() returns a base port number for an available
712 range of contiguous port numbers. Note that if a port number
713 is already in use, that does not mean that it cannot be used by
714 another link concurrently. This is because FindNewPortGroup()
715 looks for unused triplets: (dest addr, dest port, alias port). */
718 FindNewPortGroup(struct libalias *la,
719 struct in_addr dst_addr,
720 struct in_addr alias_addr,
721 u_short src_port,
722 u_short dst_port,
723 u_short port_count,
724 u_char proto,
725 u_char align)
727 int i, j;
728 int max_trials;
729 u_short port_sys;
730 int link_type;
732 LIBALIAS_LOCK_ASSERT(la);
734 * Get link_type from protocol
737 switch (proto) {
738 case IPPROTO_UDP:
739 link_type = LINK_UDP;
740 break;
741 case IPPROTO_TCP:
742 link_type = LINK_TCP;
743 break;
744 default:
745 return (0);
746 break;
750 * The aliasing port is automatically selected by one of two
751 * methods below:
753 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
755 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
757 * When the ALIAS_SAME_PORTS option is chosen, the first
758 * try will be the actual source port. If this is already
759 * in use, the remainder of the trials will be random.
761 port_sys = ntohs(src_port);
763 } else {
765 /* First trial and all subsequent are random. */
766 if (align == FIND_EVEN_ALIAS_BASE)
767 port_sys = krandom() & ALIAS_PORT_MASK_EVEN;
768 else
769 port_sys = krandom() & ALIAS_PORT_MASK;
771 port_sys += ALIAS_PORT_BASE;
774 /* Port number search */
775 for (i = 0; i < max_trials; i++) {
777 struct alias_link *search_result;
779 for (j = 0; j < port_count; j++)
780 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
781 dst_port, htons(port_sys + j),
782 link_type, 0)))
783 break;
785 /* Found a good range, return base */
786 if (j == port_count)
787 return (htons(port_sys));
789 /* Find a new base to try */
790 if (align == FIND_EVEN_ALIAS_BASE)
791 port_sys = krandom() & ALIAS_PORT_MASK_EVEN;
792 else
793 port_sys = krandom() & ALIAS_PORT_MASK;
795 port_sys += ALIAS_PORT_BASE;
798 #ifdef LIBALIAS_DEBUG
799 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
800 fprintf(stderr, "could not find free port(s)\n");
801 #endif
803 return (0);
806 static void
807 CleanupAliasData(struct libalias *la)
809 struct alias_link *lnk;
810 int i;
812 LIBALIAS_LOCK_ASSERT(la);
813 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
814 lnk = LIST_FIRST(&la->linkTableOut[i]);
815 while (lnk != NULL) {
816 struct alias_link *link_next = LIST_NEXT(lnk, list_out);
817 DeleteLink(lnk);
818 lnk = link_next;
822 la->cleanupIndex = 0;
826 static void
827 IncrementalCleanup(struct libalias *la)
829 struct alias_link *lnk, *lnk_tmp;
831 LIBALIAS_LOCK_ASSERT(la);
833 LIST_FOREACH_MUTABLE(lnk, &la->linkTableOut[la->cleanupIndex++],list_out, lnk_tmp) {
834 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
835 DeleteLink(lnk);
838 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
839 la->cleanupIndex = 0;
842 static void
843 DeleteLink(struct alias_link *lnk)
845 struct libalias *la = lnk->la;
847 LIBALIAS_LOCK_ASSERT(la);
848 /* Don't do anything if the link is marked permanent */
849 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
850 return;
852 #ifndef NO_FW_PUNCH
853 /* Delete associated firewall hole, if any */
854 ClearFWHole(lnk);
855 #endif
857 /* Free memory allocated for LSNAT server pool */
858 if (lnk->server != NULL) {
859 struct server *head, *curr, *next;
861 head = curr = lnk->server;
862 do {
863 next = curr->next;
864 kfree(curr,M_ALIAS);
865 } while ((curr = next) != head);
867 /* Adjust output table pointers */
868 LIST_REMOVE(lnk, list_out);
870 /* Adjust input table pointers */
871 LIST_REMOVE(lnk, list_in);
872 #ifndef NO_USE_SOCKETS
873 /* Close socket, if one has been allocated */
874 if (lnk->sockfd != -1) {
875 la->sockCount--;
876 close(lnk->sockfd);
878 #endif
879 /* Link-type dependent cleanup */
880 switch (lnk->link_type) {
881 case LINK_ICMP:
882 la->icmpLinkCount--;
883 break;
884 case LINK_UDP:
885 la->udpLinkCount--;
886 break;
887 case LINK_TCP:
888 la->tcpLinkCount--;
889 kfree(lnk->data.tcp,M_ALIAS);
890 break;
891 case LINK_PPTP:
892 la->pptpLinkCount--;
893 break;
894 case LINK_FRAGMENT_ID:
895 la->fragmentIdLinkCount--;
896 break;
897 case LINK_FRAGMENT_PTR:
898 la->fragmentPtrLinkCount--;
899 if (lnk->data.frag_ptr != NULL)
900 kfree(lnk->data.frag_ptr,M_ALIAS);
901 break;
902 case LINK_ADDR:
903 break;
904 default:
905 la->protoLinkCount--;
906 break;
909 /* Free memory */
910 kfree(lnk,M_ALIAS);
912 /* Write statistics, if logging enabled */
913 if (la->packetAliasMode & PKT_ALIAS_LOG) {
914 ShowAliasStats(la);
919 static struct alias_link *
920 AddLink(struct libalias *la, struct in_addr src_addr,
921 struct in_addr dst_addr,
922 struct in_addr alias_addr,
923 u_short src_port,
924 u_short dst_port,
925 int alias_port_param, /* if less than zero, alias */
926 int link_type)
927 { /* port will be automatically *//* chosen.
928 * If greater than */
929 u_int start_point; /* zero, equal to alias port */
930 struct alias_link *lnk;
932 LIBALIAS_LOCK_ASSERT(la);
933 lnk = kmalloc(sizeof(struct alias_link),M_ALIAS, M_WAITOK | M_ZERO);
934 if (lnk != NULL) {
935 /* Basic initialization */
936 lnk->la = la;
937 lnk->src_addr = src_addr;
938 lnk->dst_addr = dst_addr;
939 lnk->alias_addr = alias_addr;
940 lnk->proxy_addr.s_addr = INADDR_ANY;
941 lnk->src_port = src_port;
942 lnk->dst_port = dst_port;
943 lnk->proxy_port = 0;
944 lnk->server = NULL;
945 lnk->link_type = link_type;
946 #ifndef NO_USE_SOCKETS
947 lnk->sockfd = -1;
948 #endif
949 lnk->flags = 0;
950 lnk->pflags = 0;
951 lnk->timestamp = la->timeStamp;
953 /* Expiration time */
954 switch (link_type) {
955 case LINK_ICMP:
956 lnk->expire_time = ICMP_EXPIRE_TIME;
957 break;
958 case LINK_UDP:
959 lnk->expire_time = UDP_EXPIRE_TIME;
960 break;
961 case LINK_TCP:
962 lnk->expire_time = TCP_EXPIRE_INITIAL;
963 break;
964 case LINK_PPTP:
965 lnk->flags |= LINK_PERMANENT; /* no timeout. */
966 break;
967 case LINK_FRAGMENT_ID:
968 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
969 break;
970 case LINK_FRAGMENT_PTR:
971 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
972 break;
973 case LINK_ADDR:
974 break;
975 default:
976 lnk->expire_time = PROTO_EXPIRE_TIME;
977 break;
980 /* Determine alias flags */
981 if (dst_addr.s_addr == INADDR_ANY)
982 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
983 if (dst_port == 0)
984 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
986 /* Determine alias port */
987 if (GetNewPort(la, lnk, alias_port_param) != 0) {
988 kfree(lnk,M_ALIAS);
989 return (NULL);
991 /* Link-type dependent initialization */
992 switch (link_type) {
993 struct tcp_dat *aux_tcp;
995 case LINK_ICMP:
996 la->icmpLinkCount++;
997 break;
998 case LINK_UDP:
999 la->udpLinkCount++;
1000 break;
1001 case LINK_TCP:
1002 aux_tcp = kmalloc(sizeof(struct tcp_dat),M_ALIAS, M_WAITOK | M_ZERO);
1003 if (aux_tcp != NULL) {
1004 int i;
1006 la->tcpLinkCount++;
1007 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1008 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1009 aux_tcp->state.index = 0;
1010 aux_tcp->state.ack_modified = 0;
1011 for (i = 0; i < N_LINK_TCP_DATA; i++)
1012 aux_tcp->ack[i].active = 0;
1013 aux_tcp->fwhole = -1;
1014 lnk->data.tcp = aux_tcp;
1015 } else {
1016 #ifdef LIBALIAS_DEBUG
1017 fprintf(stderr, "PacketAlias/AddLink: ");
1018 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1019 #endif
1020 kfree(lnk,M_ALIAS);
1021 return (NULL);
1023 break;
1024 case LINK_PPTP:
1025 la->pptpLinkCount++;
1026 break;
1027 case LINK_FRAGMENT_ID:
1028 la->fragmentIdLinkCount++;
1029 break;
1030 case LINK_FRAGMENT_PTR:
1031 la->fragmentPtrLinkCount++;
1032 break;
1033 case LINK_ADDR:
1034 break;
1035 default:
1036 la->protoLinkCount++;
1037 break;
1040 /* Set up pointers for output lookup table */
1041 start_point = StartPointOut(src_addr, dst_addr,
1042 src_port, dst_port, link_type);
1043 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1045 /* Set up pointers for input lookup table */
1046 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1047 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1048 } else {
1049 #ifdef LIBALIAS_DEBUG
1050 fprintf(stderr, "PacketAlias/AddLink(): ");
1051 fprintf(stderr, "kmalloc() call failed.\n");
1052 #endif
1054 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1055 ShowAliasStats(la);
1057 return (lnk);
1060 static struct alias_link *
1061 ReLink(struct alias_link *old_lnk,
1062 struct in_addr src_addr,
1063 struct in_addr dst_addr,
1064 struct in_addr alias_addr,
1065 u_short src_port,
1066 u_short dst_port,
1067 int alias_port_param, /* if less than zero, alias */
1068 int link_type)
1069 { /* port will be automatically *//* chosen.
1070 * If greater than */
1071 struct alias_link *new_lnk; /* zero, equal to alias port */
1072 struct libalias *la = old_lnk->la;
1074 LIBALIAS_LOCK_ASSERT(la);
1075 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1076 src_port, dst_port, alias_port_param,
1077 link_type);
1078 #ifndef NO_FW_PUNCH
1079 if (new_lnk != NULL &&
1080 old_lnk->link_type == LINK_TCP &&
1081 old_lnk->data.tcp->fwhole > 0) {
1082 PunchFWHole(new_lnk);
1084 #endif
1085 DeleteLink(old_lnk);
1086 return (new_lnk);
1089 static struct alias_link *
1090 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1091 struct in_addr dst_addr,
1092 u_short src_port,
1093 u_short dst_port,
1094 int link_type,
1095 int replace_partial_links)
1097 u_int i;
1098 struct alias_link *lnk;
1100 LIBALIAS_LOCK_ASSERT(la);
1101 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1102 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1103 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1104 lnk->src_addr.s_addr == src_addr.s_addr &&
1105 lnk->src_port == src_port &&
1106 lnk->dst_port == dst_port &&
1107 lnk->link_type == link_type &&
1108 lnk->server == NULL) {
1109 lnk->timestamp = la->timeStamp;
1110 break;
1114 /* Search for partially specified links. */
1115 if (lnk == NULL && replace_partial_links) {
1116 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1117 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1118 link_type, 0);
1119 if (lnk == NULL)
1120 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1121 dst_port, link_type, 0);
1123 if (lnk == NULL &&
1124 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1125 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1126 link_type, 0);
1128 if (lnk != NULL) {
1129 lnk = ReLink(lnk,
1130 src_addr, dst_addr, lnk->alias_addr,
1131 src_port, dst_port, lnk->alias_port,
1132 link_type);
1135 return (lnk);
1138 static struct alias_link *
1139 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1140 struct in_addr dst_addr,
1141 u_short src_port,
1142 u_short dst_port,
1143 int link_type,
1144 int replace_partial_links)
1146 struct alias_link *lnk;
1148 LIBALIAS_LOCK_ASSERT(la);
1149 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1150 link_type, replace_partial_links);
1152 if (lnk == NULL) {
1154 * The following allows permanent links to be specified as
1155 * using the default source address (i.e. device interface
1156 * address) without knowing in advance what that address
1157 * is.
1159 if (la->aliasAddress.s_addr != INADDR_ANY &&
1160 src_addr.s_addr == la->aliasAddress.s_addr) {
1161 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1162 link_type, replace_partial_links);
1165 return (lnk);
1169 static struct alias_link *
1170 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1171 struct in_addr alias_addr,
1172 u_short dst_port,
1173 u_short alias_port,
1174 int link_type,
1175 int replace_partial_links)
1177 int flags_in;
1178 u_int start_point;
1179 struct alias_link *lnk;
1180 struct alias_link *lnk_fully_specified;
1181 struct alias_link *lnk_unknown_all;
1182 struct alias_link *lnk_unknown_dst_addr;
1183 struct alias_link *lnk_unknown_dst_port;
1185 LIBALIAS_LOCK_ASSERT(la);
1186 /* Initialize pointers */
1187 lnk_fully_specified = NULL;
1188 lnk_unknown_all = NULL;
1189 lnk_unknown_dst_addr = NULL;
1190 lnk_unknown_dst_port = NULL;
1192 /* If either the dest addr or port is unknown, the search
1193 loop will have to know about this. */
1195 flags_in = 0;
1196 if (dst_addr.s_addr == INADDR_ANY)
1197 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1198 if (dst_port == 0)
1199 flags_in |= LINK_UNKNOWN_DEST_PORT;
1201 /* Search loop */
1202 start_point = StartPointIn(alias_addr, alias_port, link_type);
1203 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1204 int flags;
1206 flags = flags_in | lnk->flags;
1207 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1208 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1209 && lnk->alias_port == alias_port
1210 && lnk->dst_addr.s_addr == dst_addr.s_addr
1211 && lnk->dst_port == dst_port
1212 && lnk->link_type == link_type) {
1213 lnk_fully_specified = lnk;
1214 break;
1216 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1217 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1218 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1219 && lnk->alias_port == alias_port
1220 && lnk->link_type == link_type) {
1221 if (lnk_unknown_all == NULL)
1222 lnk_unknown_all = lnk;
1224 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1225 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1226 && lnk->alias_port == alias_port
1227 && lnk->link_type == link_type
1228 && lnk->dst_port == dst_port) {
1229 if (lnk_unknown_dst_addr == NULL)
1230 lnk_unknown_dst_addr = lnk;
1232 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1233 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1234 && lnk->alias_port == alias_port
1235 && lnk->link_type == link_type
1236 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1237 if (lnk_unknown_dst_port == NULL)
1238 lnk_unknown_dst_port = lnk;
1245 if (lnk_fully_specified != NULL) {
1246 lnk_fully_specified->timestamp = la->timeStamp;
1247 lnk = lnk_fully_specified;
1248 } else if (lnk_unknown_dst_port != NULL)
1249 lnk = lnk_unknown_dst_port;
1250 else if (lnk_unknown_dst_addr != NULL)
1251 lnk = lnk_unknown_dst_addr;
1252 else if (lnk_unknown_all != NULL)
1253 lnk = lnk_unknown_all;
1254 else
1255 return (NULL);
1257 if (replace_partial_links &&
1258 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1259 struct in_addr src_addr;
1260 u_short src_port;
1262 if (lnk->server != NULL) { /* LSNAT link */
1263 src_addr = lnk->server->addr;
1264 src_port = lnk->server->port;
1265 lnk->server = lnk->server->next;
1266 } else {
1267 src_addr = lnk->src_addr;
1268 src_port = lnk->src_port;
1271 lnk = ReLink(lnk,
1272 src_addr, dst_addr, alias_addr,
1273 src_port, dst_port, alias_port,
1274 link_type);
1276 return (lnk);
1279 static struct alias_link *
1280 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1281 struct in_addr alias_addr,
1282 u_short dst_port,
1283 u_short alias_port,
1284 int link_type,
1285 int replace_partial_links)
1287 struct alias_link *lnk;
1289 LIBALIAS_LOCK_ASSERT(la);
1290 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1291 link_type, replace_partial_links);
1293 if (lnk == NULL) {
1295 * The following allows permanent links to be specified as
1296 * using the default aliasing address (i.e. device
1297 * interface address) without knowing in advance what that
1298 * address is.
1300 if (la->aliasAddress.s_addr != INADDR_ANY &&
1301 alias_addr.s_addr == la->aliasAddress.s_addr) {
1302 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1303 link_type, replace_partial_links);
1306 return (lnk);
1312 /* External routines for finding/adding links
1314 -- "external" means outside alias_db.c, but within alias*.c --
1316 FindIcmpIn(), FindIcmpOut()
1317 FindFragmentIn1(), FindFragmentIn2()
1318 AddFragmentPtrLink(), FindFragmentPtr()
1319 FindProtoIn(), FindProtoOut()
1320 FindUdpTcpIn(), FindUdpTcpOut()
1321 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1322 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1323 FindOriginalAddress(), FindAliasAddress()
1325 (prototypes in alias_local.h)
1329 struct alias_link *
1330 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1331 struct in_addr alias_addr,
1332 u_short id_alias,
1333 int create)
1335 struct alias_link *lnk;
1337 LIBALIAS_LOCK_ASSERT(la);
1338 lnk = FindLinkIn(la, dst_addr, alias_addr,
1339 NO_DEST_PORT, id_alias,
1340 LINK_ICMP, 0);
1341 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1342 struct in_addr target_addr;
1344 target_addr = FindOriginalAddress(la, alias_addr);
1345 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1346 id_alias, NO_DEST_PORT, id_alias,
1347 LINK_ICMP);
1349 return (lnk);
1353 struct alias_link *
1354 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1355 struct in_addr dst_addr,
1356 u_short id,
1357 int create)
1359 struct alias_link *lnk;
1361 LIBALIAS_LOCK_ASSERT(la);
1362 lnk = FindLinkOut(la, src_addr, dst_addr,
1363 id, NO_DEST_PORT,
1364 LINK_ICMP, 0);
1365 if (lnk == NULL && create) {
1366 struct in_addr alias_addr;
1368 alias_addr = FindAliasAddress(la, src_addr);
1369 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1370 id, NO_DEST_PORT, GET_ALIAS_ID,
1371 LINK_ICMP);
1373 return (lnk);
1377 struct alias_link *
1378 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1379 struct in_addr alias_addr,
1380 u_short ip_id)
1382 struct alias_link *lnk;
1384 LIBALIAS_LOCK_ASSERT(la);
1385 lnk = FindLinkIn(la, dst_addr, alias_addr,
1386 NO_DEST_PORT, ip_id,
1387 LINK_FRAGMENT_ID, 0);
1389 if (lnk == NULL) {
1390 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1391 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1392 LINK_FRAGMENT_ID);
1394 return (lnk);
1398 struct alias_link *
1399 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1400 * one */
1401 struct in_addr alias_addr, /* is not found. */
1402 u_short ip_id)
1405 LIBALIAS_LOCK_ASSERT(la);
1406 return FindLinkIn(la, dst_addr, alias_addr,
1407 NO_DEST_PORT, ip_id,
1408 LINK_FRAGMENT_ID, 0);
1412 struct alias_link *
1413 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1414 u_short ip_id)
1417 LIBALIAS_LOCK_ASSERT(la);
1418 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1419 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1420 LINK_FRAGMENT_PTR);
1424 struct alias_link *
1425 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1426 u_short ip_id)
1429 LIBALIAS_LOCK_ASSERT(la);
1430 return FindLinkIn(la, dst_addr, la->nullAddress,
1431 NO_DEST_PORT, ip_id,
1432 LINK_FRAGMENT_PTR, 0);
1436 struct alias_link *
1437 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1438 struct in_addr alias_addr,
1439 u_char proto)
1441 struct alias_link *lnk;
1443 LIBALIAS_LOCK_ASSERT(la);
1444 lnk = FindLinkIn(la, dst_addr, alias_addr,
1445 NO_DEST_PORT, 0,
1446 proto, 1);
1448 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1449 struct in_addr target_addr;
1451 target_addr = FindOriginalAddress(la, alias_addr);
1452 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1453 NO_SRC_PORT, NO_DEST_PORT, 0,
1454 proto);
1456 return (lnk);
1460 struct alias_link *
1461 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1462 struct in_addr dst_addr,
1463 u_char proto)
1465 struct alias_link *lnk;
1467 LIBALIAS_LOCK_ASSERT(la);
1468 lnk = FindLinkOut(la, src_addr, dst_addr,
1469 NO_SRC_PORT, NO_DEST_PORT,
1470 proto, 1);
1472 if (lnk == NULL) {
1473 struct in_addr alias_addr;
1475 alias_addr = FindAliasAddress(la, src_addr);
1476 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1477 NO_SRC_PORT, NO_DEST_PORT, 0,
1478 proto);
1480 return (lnk);
1484 struct alias_link *
1485 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1486 struct in_addr alias_addr,
1487 u_short dst_port,
1488 u_short alias_port,
1489 u_char proto,
1490 int create)
1492 int link_type;
1493 struct alias_link *lnk;
1495 LIBALIAS_LOCK_ASSERT(la);
1496 switch (proto) {
1497 case IPPROTO_UDP:
1498 link_type = LINK_UDP;
1499 break;
1500 case IPPROTO_TCP:
1501 link_type = LINK_TCP;
1502 break;
1503 default:
1504 return (NULL);
1505 break;
1508 lnk = FindLinkIn(la, dst_addr, alias_addr,
1509 dst_port, alias_port,
1510 link_type, create);
1512 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1513 struct in_addr target_addr;
1515 target_addr = FindOriginalAddress(la, alias_addr);
1516 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1517 alias_port, dst_port, alias_port,
1518 link_type);
1520 return (lnk);
1524 struct alias_link *
1525 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1526 struct in_addr dst_addr,
1527 u_short src_port,
1528 u_short dst_port,
1529 u_char proto,
1530 int create)
1532 int link_type;
1533 struct alias_link *lnk;
1535 LIBALIAS_LOCK_ASSERT(la);
1536 switch (proto) {
1537 case IPPROTO_UDP:
1538 link_type = LINK_UDP;
1539 break;
1540 case IPPROTO_TCP:
1541 link_type = LINK_TCP;
1542 break;
1543 default:
1544 return (NULL);
1545 break;
1548 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1550 if (lnk == NULL && create) {
1551 struct in_addr alias_addr;
1553 alias_addr = FindAliasAddress(la, src_addr);
1554 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1555 src_port, dst_port, GET_ALIAS_PORT,
1556 link_type);
1558 return (lnk);
1562 struct alias_link *
1563 AddPptp(struct libalias *la, struct in_addr src_addr,
1564 struct in_addr dst_addr,
1565 struct in_addr alias_addr,
1566 u_int16_t src_call_id)
1568 struct alias_link *lnk;
1570 LIBALIAS_LOCK_ASSERT(la);
1571 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1572 src_call_id, 0, GET_ALIAS_PORT,
1573 LINK_PPTP);
1575 return (lnk);
1579 struct alias_link *
1580 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1581 struct in_addr dst_addr,
1582 u_int16_t src_call_id)
1584 u_int i;
1585 struct alias_link *lnk;
1587 LIBALIAS_LOCK_ASSERT(la);
1588 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1589 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1590 if (lnk->link_type == LINK_PPTP &&
1591 lnk->src_addr.s_addr == src_addr.s_addr &&
1592 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1593 lnk->src_port == src_call_id)
1594 break;
1596 return (lnk);
1600 struct alias_link *
1601 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1602 struct in_addr dst_addr,
1603 u_int16_t dst_call_id)
1605 u_int i;
1606 struct alias_link *lnk;
1608 LIBALIAS_LOCK_ASSERT(la);
1609 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1610 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1611 if (lnk->link_type == LINK_PPTP &&
1612 lnk->src_addr.s_addr == src_addr.s_addr &&
1613 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1614 lnk->dst_port == dst_call_id)
1615 break;
1617 return (lnk);
1621 struct alias_link *
1622 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1623 struct in_addr alias_addr,
1624 u_int16_t dst_call_id)
1626 u_int i;
1627 struct alias_link *lnk;
1629 LIBALIAS_LOCK_ASSERT(la);
1630 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1631 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1632 if (lnk->link_type == LINK_PPTP &&
1633 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1634 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1635 lnk->dst_port == dst_call_id)
1636 break;
1638 return (lnk);
1642 struct alias_link *
1643 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1644 struct in_addr alias_addr,
1645 u_int16_t alias_call_id)
1647 struct alias_link *lnk;
1649 LIBALIAS_LOCK_ASSERT(la);
1650 lnk = FindLinkIn(la, dst_addr, alias_addr,
1651 0 /* any */ , alias_call_id,
1652 LINK_PPTP, 0);
1655 return (lnk);
1659 struct alias_link *
1660 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1661 struct in_addr dst_addr,
1662 u_short src_port,
1663 u_short alias_port,
1664 u_char proto)
1666 int link_type;
1667 struct alias_link *lnk;
1669 LIBALIAS_LOCK_ASSERT(la);
1670 switch (proto) {
1671 case IPPROTO_UDP:
1672 link_type = LINK_UDP;
1673 break;
1674 case IPPROTO_TCP:
1675 link_type = LINK_TCP;
1676 break;
1677 default:
1678 return (NULL);
1679 break;
1682 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1684 if (lnk == NULL) {
1685 struct in_addr alias_addr;
1687 alias_addr = FindAliasAddress(la, src_addr);
1688 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1689 src_port, 0, alias_port,
1690 link_type);
1692 return (lnk);
1696 struct in_addr
1697 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1699 struct alias_link *lnk;
1701 LIBALIAS_LOCK_ASSERT(la);
1702 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1703 0, 0, LINK_ADDR, 0);
1704 if (lnk == NULL) {
1705 la->newDefaultLink = 1;
1706 if (la->targetAddress.s_addr == INADDR_ANY)
1707 return (alias_addr);
1708 else if (la->targetAddress.s_addr == INADDR_NONE)
1709 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1710 la->aliasAddress : alias_addr;
1711 else
1712 return (la->targetAddress);
1713 } else {
1714 if (lnk->server != NULL) { /* LSNAT link */
1715 struct in_addr src_addr;
1717 src_addr = lnk->server->addr;
1718 lnk->server = lnk->server->next;
1719 return (src_addr);
1720 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1721 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1722 la->aliasAddress : alias_addr;
1723 else
1724 return (lnk->src_addr);
1729 struct in_addr
1730 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1732 struct alias_link *lnk;
1734 LIBALIAS_LOCK_ASSERT(la);
1735 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1736 0, 0, LINK_ADDR, 0);
1737 if (lnk == NULL) {
1738 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1739 la->aliasAddress : original_addr;
1740 } else {
1741 if (lnk->alias_addr.s_addr == INADDR_ANY)
1742 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1743 la->aliasAddress : original_addr;
1744 else
1745 return (lnk->alias_addr);
1750 /* External routines for getting or changing link data
1751 (external to alias_db.c, but internal to alias*.c)
1753 SetFragmentData(), GetFragmentData()
1754 SetFragmentPtr(), GetFragmentPtr()
1755 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1756 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1757 GetOriginalPort(), GetAliasPort()
1758 SetAckModified(), GetAckModified()
1759 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1760 SetProtocolFlags(), GetProtocolFlags()
1761 SetDestCallId()
1765 void
1766 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1768 lnk->data.frag_addr = src_addr;
1772 void
1773 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1775 *src_addr = lnk->data.frag_addr;
1779 void
1780 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1782 lnk->data.frag_ptr = fptr;
1786 void
1787 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1789 *fptr = lnk->data.frag_ptr;
1793 void
1794 SetStateIn(struct alias_link *lnk, int state)
1796 /* TCP input state */
1797 switch (state) {
1798 case ALIAS_TCP_STATE_DISCONNECTED:
1799 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1800 lnk->expire_time = TCP_EXPIRE_DEAD;
1801 else
1802 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1803 break;
1804 case ALIAS_TCP_STATE_CONNECTED:
1805 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1806 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1807 break;
1808 default:
1809 #ifdef _KERNEL
1810 panic("libalias:SetStateIn() unknown state");
1811 #else
1812 abort();
1813 #endif
1815 lnk->data.tcp->state.in = state;
1819 void
1820 SetStateOut(struct alias_link *lnk, int state)
1822 /* TCP output state */
1823 switch (state) {
1824 case ALIAS_TCP_STATE_DISCONNECTED:
1825 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1826 lnk->expire_time = TCP_EXPIRE_DEAD;
1827 else
1828 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1829 break;
1830 case ALIAS_TCP_STATE_CONNECTED:
1831 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1832 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1833 break;
1834 default:
1835 #ifdef _KERNEL
1836 panic("libalias:SetStateOut() unknown state");
1837 #else
1838 abort();
1839 #endif
1841 lnk->data.tcp->state.out = state;
1846 GetStateIn(struct alias_link *lnk)
1848 /* TCP input state */
1849 return (lnk->data.tcp->state.in);
1854 GetStateOut(struct alias_link *lnk)
1856 /* TCP output state */
1857 return (lnk->data.tcp->state.out);
1861 struct in_addr
1862 GetOriginalAddress(struct alias_link *lnk)
1864 if (lnk->src_addr.s_addr == INADDR_ANY)
1865 return (lnk->la->aliasAddress);
1866 else
1867 return (lnk->src_addr);
1871 struct in_addr
1872 GetDestAddress(struct alias_link *lnk)
1874 return (lnk->dst_addr);
1878 struct in_addr
1879 GetAliasAddress(struct alias_link *lnk)
1881 if (lnk->alias_addr.s_addr == INADDR_ANY)
1882 return (lnk->la->aliasAddress);
1883 else
1884 return (lnk->alias_addr);
1888 struct in_addr
1889 GetDefaultAliasAddress(struct libalias *la)
1892 LIBALIAS_LOCK_ASSERT(la);
1893 return (la->aliasAddress);
1897 void
1898 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1901 LIBALIAS_LOCK_ASSERT(la);
1902 la->aliasAddress = alias_addr;
1906 u_short
1907 GetOriginalPort(struct alias_link *lnk)
1909 return (lnk->src_port);
1913 u_short
1914 GetAliasPort(struct alias_link *lnk)
1916 return (lnk->alias_port);
1919 #ifndef NO_FW_PUNCH
1920 static u_short
1921 GetDestPort(struct alias_link *lnk)
1923 return (lnk->dst_port);
1926 #endif
1928 void
1929 SetAckModified(struct alias_link *lnk)
1931 /* Indicate that ACK numbers have been modified in a TCP connection */
1932 lnk->data.tcp->state.ack_modified = 1;
1936 struct in_addr
1937 GetProxyAddress(struct alias_link *lnk)
1939 return (lnk->proxy_addr);
1943 void
1944 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1946 lnk->proxy_addr = addr;
1950 u_short
1951 GetProxyPort(struct alias_link *lnk)
1953 return (lnk->proxy_port);
1957 void
1958 SetProxyPort(struct alias_link *lnk, u_short port)
1960 lnk->proxy_port = port;
1965 GetAckModified(struct alias_link *lnk)
1967 /* See if ACK numbers have been modified */
1968 return (lnk->data.tcp->state.ack_modified);
1973 GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
1976 Find out how much the ACK number has been altered for an incoming
1977 TCP packet. To do this, a circular list of ACK numbers where the TCP
1978 packet size was altered is searched.
1981 int i;
1982 struct tcphdr *tc;
1983 int delta, ack_diff_min;
1984 u_long ack;
1986 tc = ip_next(pip);
1987 ack = tc->th_ack;
1989 delta = 0;
1990 ack_diff_min = -1;
1991 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1992 struct ack_data_record x;
1994 x = lnk->data.tcp->ack[i];
1995 if (x.active == 1) {
1996 int ack_diff;
1998 ack_diff = SeqDiff(x.ack_new, ack);
1999 if (ack_diff >= 0) {
2000 if (ack_diff_min >= 0) {
2001 if (ack_diff < ack_diff_min) {
2002 delta = x.delta;
2003 ack_diff_min = ack_diff;
2005 } else {
2006 delta = x.delta;
2007 ack_diff_min = ack_diff;
2012 return (delta);
2017 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
2020 Find out how much the sequence number has been altered for an outgoing
2021 TCP packet. To do this, a circular list of ACK numbers where the TCP
2022 packet size was altered is searched.
2025 int i;
2026 struct tcphdr *tc;
2027 int delta, seq_diff_min;
2028 u_long seq;
2030 tc = ip_next(pip);
2031 seq = tc->th_seq;
2033 delta = 0;
2034 seq_diff_min = -1;
2035 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2036 struct ack_data_record x;
2038 x = lnk->data.tcp->ack[i];
2039 if (x.active == 1) {
2040 int seq_diff;
2042 seq_diff = SeqDiff(x.ack_old, seq);
2043 if (seq_diff >= 0) {
2044 if (seq_diff_min >= 0) {
2045 if (seq_diff < seq_diff_min) {
2046 delta = x.delta;
2047 seq_diff_min = seq_diff;
2049 } else {
2050 delta = x.delta;
2051 seq_diff_min = seq_diff;
2056 return (delta);
2060 void
2061 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
2064 When a TCP packet has been altered in length, save this
2065 information in a circular list. If enough packets have
2066 been altered, then this list will begin to overwrite itself.
2069 struct tcphdr *tc;
2070 struct ack_data_record x;
2071 int hlen, tlen, dlen;
2072 int i;
2074 tc = ip_next(pip);
2076 hlen = (pip->ip_hl + tc->th_off) << 2;
2077 tlen = ntohs(pip->ip_len);
2078 dlen = tlen - hlen;
2080 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2081 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2082 x.delta = delta;
2083 x.active = 1;
2085 i = lnk->data.tcp->state.index;
2086 lnk->data.tcp->ack[i] = x;
2088 i++;
2089 if (i == N_LINK_TCP_DATA)
2090 lnk->data.tcp->state.index = 0;
2091 else
2092 lnk->data.tcp->state.index = i;
2095 void
2096 SetExpire(struct alias_link *lnk, int expire)
2098 if (expire == 0) {
2099 lnk->flags &= ~LINK_PERMANENT;
2100 DeleteLink(lnk);
2101 } else if (expire == -1) {
2102 lnk->flags |= LINK_PERMANENT;
2103 } else if (expire > 0) {
2104 lnk->expire_time = expire;
2105 } else {
2106 #ifdef LIBALIAS_DEBUG
2107 fprintf(stderr, "PacketAlias/SetExpire(): ");
2108 fprintf(stderr, "error in expire parameter\n");
2109 #endif
2113 void
2114 ClearCheckNewLink(struct libalias *la)
2117 LIBALIAS_LOCK_ASSERT(la);
2118 la->newDefaultLink = 0;
2121 void
2122 SetProtocolFlags(struct alias_link *lnk, int pflags)
2125 lnk->pflags = pflags;;
2129 GetProtocolFlags(struct alias_link *lnk)
2132 return (lnk->pflags);
2135 void
2136 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2138 struct libalias *la = lnk->la;
2140 LIBALIAS_LOCK_ASSERT(la);
2141 la->deleteAllLinks = 1;
2142 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2143 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2144 la->deleteAllLinks = 0;
2148 /* Miscellaneous Functions
2150 HouseKeeping()
2151 InitPacketAliasLog()
2152 UninitPacketAliasLog()
2156 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2157 is called to find and remove timed-out aliasing links. Logic exists
2158 to sweep through the entire table and linked list structure
2159 every 60 seconds.
2161 (prototype in alias_local.h)
2164 void
2165 HouseKeeping(struct libalias *la)
2167 int i, n;
2168 #ifndef _KERNEL
2169 struct timeval tv;
2170 struct timezone tz;
2171 #endif
2173 LIBALIAS_LOCK_ASSERT(la);
2175 * Save system time (seconds) in global variable timeStamp for use
2176 * by other functions. This is done so as not to unnecessarily
2177 * waste timeline by making system calls.
2179 #ifdef _KERNEL
2180 la->timeStamp = time_uptime;
2181 #else
2182 gettimeofday(&tv, &tz);
2183 la->timeStamp = tv.tv_sec;
2184 #endif
2186 /* Compute number of spokes (output table link chains) to cover */
2187 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2188 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2190 /* Handle different cases */
2191 if (n > 0) {
2192 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2193 n = ALIAS_CLEANUP_MAX_SPOKES;
2194 la->lastCleanupTime = la->timeStamp;
2195 for (i = 0; i < n; i++)
2196 IncrementalCleanup(la);
2197 } else if (n < 0) {
2198 #ifdef LIBALIAS_DEBUG
2199 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2200 fprintf(stderr, "something unexpected in time values\n");
2201 #endif
2202 la->lastCleanupTime = la->timeStamp;
2206 /* Init the log file and enable logging */
2207 static int
2208 InitPacketAliasLog(struct libalias *la)
2211 LIBALIAS_LOCK_ASSERT(la);
2212 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2213 #ifdef _KERNEL
2214 if ((la->logDesc = kmalloc(LIBALIAS_BUF_SIZE,M_ALIAS, M_WAITOK | M_ZERO)))
2216 #else
2217 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2218 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2219 #endif
2220 else
2221 return (ENOMEM); /* log initialization failed */
2222 la->packetAliasMode |= PKT_ALIAS_LOG;
2225 return (1);
2228 /* Close the log-file and disable logging. */
2229 static void
2230 UninitPacketAliasLog(struct libalias *la)
2233 LIBALIAS_LOCK_ASSERT(la);
2234 if (la->logDesc) {
2235 #ifdef _KERNEL
2236 kfree(la->logDesc,M_ALIAS);
2237 #else
2238 fclose(la->logDesc);
2239 #endif
2240 la->logDesc = NULL;
2242 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2245 /* Outside world interfaces
2247 -- "outside world" means other than alias*.c routines --
2249 PacketAliasRedirectPort()
2250 PacketAliasAddServer()
2251 PacketAliasRedirectProto()
2252 PacketAliasRedirectAddr()
2253 PacketAliasRedirectDynamic()
2254 PacketAliasRedirectDelete()
2255 PacketAliasSetAddress()
2256 PacketAliasInit()
2257 PacketAliasUninit()
2258 PacketAliasSetMode()
2260 (prototypes in alias.h)
2263 /* Redirection from a specific public addr:port to a
2264 private addr:port */
2265 struct alias_link *
2266 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2267 struct in_addr dst_addr, u_short dst_port,
2268 struct in_addr alias_addr, u_short alias_port,
2269 u_char proto)
2271 int link_type;
2272 struct alias_link *lnk;
2274 LIBALIAS_LOCK(la);
2275 switch (proto) {
2276 case IPPROTO_UDP:
2277 link_type = LINK_UDP;
2278 break;
2279 case IPPROTO_TCP:
2280 link_type = LINK_TCP;
2281 break;
2282 default:
2283 #ifdef LIBALIAS_DEBUG
2284 fprintf(stderr, "PacketAliasRedirectPort(): ");
2285 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2286 #endif
2287 lnk = NULL;
2288 goto getout;
2291 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2292 src_port, dst_port, alias_port,
2293 link_type);
2295 if (lnk != NULL) {
2296 lnk->flags |= LINK_PERMANENT;
2298 #ifdef LIBALIAS_DEBUG
2299 else {
2300 fprintf(stderr, "PacketAliasRedirectPort(): "
2301 "call to AddLink() failed\n");
2303 #endif
2305 getout:
2306 LIBALIAS_UNLOCK(la);
2307 return (lnk);
2310 /* Add server to the pool of servers */
2312 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2314 struct server *server;
2315 int res;
2317 LIBALIAS_LOCK(la);
2318 (void)la;
2320 server = kmalloc(sizeof(struct server),M_ALIAS, M_WAITOK | M_ZERO);
2322 if (server != NULL) {
2323 struct server *head;
2325 server->addr = addr;
2326 server->port = port;
2328 head = lnk->server;
2329 if (head == NULL)
2330 server->next = server;
2331 else {
2332 struct server *s;
2334 for (s = head; s->next != head; s = s->next);
2335 s->next = server;
2336 server->next = head;
2338 lnk->server = server;
2339 res = 0;
2340 } else
2341 res = -1;
2343 LIBALIAS_UNLOCK(la);
2344 return (res);
2347 /* Redirect packets of a given IP protocol from a specific
2348 public address to a private address */
2349 struct alias_link *
2350 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2351 struct in_addr dst_addr,
2352 struct in_addr alias_addr,
2353 u_char proto)
2355 struct alias_link *lnk;
2357 LIBALIAS_LOCK(la);
2358 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2359 NO_SRC_PORT, NO_DEST_PORT, 0,
2360 proto);
2362 if (lnk != NULL) {
2363 lnk->flags |= LINK_PERMANENT;
2365 #ifdef LIBALIAS_DEBUG
2366 else {
2367 fprintf(stderr, "PacketAliasRedirectProto(): "
2368 "call to AddLink() failed\n");
2370 #endif
2372 LIBALIAS_UNLOCK(la);
2373 return (lnk);
2376 /* Static address translation */
2377 struct alias_link *
2378 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2379 struct in_addr alias_addr)
2381 struct alias_link *lnk;
2383 LIBALIAS_LOCK(la);
2384 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2385 0, 0, 0,
2386 LINK_ADDR);
2388 if (lnk != NULL) {
2389 lnk->flags |= LINK_PERMANENT;
2391 #ifdef LIBALIAS_DEBUG
2392 else {
2393 fprintf(stderr, "PacketAliasRedirectAddr(): "
2394 "call to AddLink() failed\n");
2396 #endif
2398 LIBALIAS_UNLOCK(la);
2399 return (lnk);
2403 /* Mark the aliasing link dynamic */
2405 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2407 int res;
2409 LIBALIAS_LOCK(la);
2410 (void)la;
2412 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2413 res = -1;
2414 else {
2415 lnk->flags &= ~LINK_PERMANENT;
2416 res = 0;
2418 LIBALIAS_UNLOCK(la);
2419 return (res);
2423 void
2424 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2426 /* This is a dangerous function to put in the API,
2427 because an invalid pointer can crash the program. */
2429 LIBALIAS_LOCK(la);
2430 la->deleteAllLinks = 1;
2431 DeleteLink(lnk);
2432 la->deleteAllLinks = 0;
2433 LIBALIAS_UNLOCK(la);
2437 void
2438 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2441 LIBALIAS_LOCK(la);
2442 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2443 && la->aliasAddress.s_addr != addr.s_addr)
2444 CleanupAliasData(la);
2446 la->aliasAddress = addr;
2447 LIBALIAS_UNLOCK(la);
2451 void
2452 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2455 LIBALIAS_LOCK(la);
2456 la->targetAddress = target_addr;
2457 LIBALIAS_UNLOCK(la);
2460 static void
2461 finishoff(void)
2464 while (!LIST_EMPTY(&instancehead))
2465 LibAliasUninit(LIST_FIRST(&instancehead));
2468 struct libalias *
2469 LibAliasInit(struct libalias *la)
2471 int i;
2472 #ifndef _KERNEL
2473 struct timeval tv;
2474 struct timezone tz;
2475 #endif
2477 if (la == NULL) {
2478 la = kmalloc(sizeof *la,M_ALIAS, M_WAITOK | M_ZERO);
2479 if (la == NULL)
2480 return (la);
2482 #ifndef _KERNEL /* kernel cleans up on module unload */
2483 if (LIST_EMPTY(&instancehead))
2484 atexit(finishoff);
2485 #endif
2486 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2488 #ifdef _KERNEL
2489 la->timeStamp = time_uptime;
2490 la->lastCleanupTime = time_uptime;
2491 #else
2492 gettimeofday(&tv, &tz);
2493 la->timeStamp = tv.tv_sec;
2494 la->lastCleanupTime = tv.tv_sec;
2495 #endif
2497 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2498 LIST_INIT(&la->linkTableOut[i]);
2499 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2500 LIST_INIT(&la->linkTableIn[i]);
2501 LIBALIAS_LOCK_INIT(la);
2502 LIBALIAS_LOCK(la);
2503 } else {
2504 LIBALIAS_LOCK(la);
2505 la->deleteAllLinks = 1;
2506 CleanupAliasData(la);
2507 la->deleteAllLinks = 0;
2510 la->aliasAddress.s_addr = INADDR_ANY;
2511 la->targetAddress.s_addr = INADDR_ANY;
2513 la->icmpLinkCount = 0;
2514 la->udpLinkCount = 0;
2515 la->tcpLinkCount = 0;
2516 la->pptpLinkCount = 0;
2517 la->protoLinkCount = 0;
2518 la->fragmentIdLinkCount = 0;
2519 la->fragmentPtrLinkCount = 0;
2520 la->sockCount = 0;
2522 la->cleanupIndex = 0;
2524 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2525 #ifndef NO_USE_SOCKETS
2526 | PKT_ALIAS_USE_SOCKETS
2527 #endif
2528 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2529 #ifndef NO_FW_PUNCH
2530 la->fireWallFD = -1;
2531 #endif
2532 #ifndef _KERNEL
2533 LibAliasRefreshModules();
2534 #endif
2535 LIBALIAS_UNLOCK(la);
2536 return (la);
2539 void
2540 LibAliasUninit(struct libalias *la)
2543 LIBALIAS_LOCK(la);
2544 la->deleteAllLinks = 1;
2545 CleanupAliasData(la);
2546 la->deleteAllLinks = 0;
2547 UninitPacketAliasLog(la);
2548 #ifndef NO_FW_PUNCH
2549 UninitPunchFW(la);
2550 #endif
2551 LIST_REMOVE(la, instancelist);
2552 LIBALIAS_UNLOCK(la);
2553 LIBALIAS_LOCK_DESTROY(la);
2554 kfree(la,M_ALIAS);
2557 /* Change mode for some operations */
2558 unsigned int
2559 LibAliasSetMode(
2560 struct libalias *la,
2561 unsigned int flags, /* Which state to bring flags to */
2562 unsigned int mask /* Mask of which flags to affect (use 0 to
2563 * do a probe for flag values) */
2566 int res = -1;
2568 LIBALIAS_LOCK(la);
2569 /* Enable logging? */
2570 if (flags & mask & PKT_ALIAS_LOG) {
2571 /* Do the enable */
2572 if (InitPacketAliasLog(la) == ENOMEM)
2573 goto getout;
2574 } else
2575 /* _Disable_ logging? */
2576 if (~flags & mask & PKT_ALIAS_LOG) {
2577 UninitPacketAliasLog(la);
2579 #ifndef NO_FW_PUNCH
2580 /* Start punching holes in the firewall? */
2581 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2582 InitPunchFW(la);
2583 } else
2584 /* Stop punching holes in the firewall? */
2585 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2586 UninitPunchFW(la);
2588 #endif
2590 /* Other flags can be set/cleared without special action */
2591 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2592 res = la->packetAliasMode;
2593 getout:
2594 LIBALIAS_UNLOCK(la);
2595 return (res);
2600 LibAliasCheckNewLink(struct libalias *la)
2602 int res;
2604 LIBALIAS_LOCK(la);
2605 res = la->newDefaultLink;
2606 LIBALIAS_UNLOCK(la);
2607 return (res);
2611 #ifndef NO_FW_PUNCH
2613 /*****************
2614 Code to support firewall punching. This shouldn't really be in this
2615 file, but making variables global is evil too.
2616 ****************/
2618 /* Firewall include files */
2619 #include <net/if.h>
2620 #include <netinet/ip_fw.h>
2621 #include <string.h>
2622 #include <err.h>
2625 * helper function, updates the pointer to cmd with the length
2626 * of the current command, and also cleans up the first word of
2627 * the new command in case it has been clobbered before.
2629 static ipfw_insn *
2630 next_cmd(ipfw_insn * cmd)
2632 cmd += F_LEN(cmd);
2633 bzero(cmd, sizeof(*cmd));
2634 return (cmd);
2638 * A function to fill simple commands of size 1.
2639 * Existing flags are preserved.
2641 static ipfw_insn *
2642 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2643 int flags, u_int16_t arg)
2645 cmd->opcode = opcode;
2646 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2647 cmd->arg1 = arg;
2648 return next_cmd(cmd);
2651 static ipfw_insn *
2652 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2654 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2656 cmd->addr.s_addr = addr;
2657 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2660 static ipfw_insn *
2661 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2663 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2665 cmd->ports[0] = cmd->ports[1] = port;
2666 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2669 static int
2670 fill_rule(void *buf, int bufsize, int rulenum,
2671 enum ipfw_opcodes action, int proto,
2672 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2674 struct ip_fw *rule = (struct ip_fw *)buf;
2675 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2677 bzero(buf, bufsize);
2678 rule->rulenum = rulenum;
2680 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2681 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2682 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2683 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2684 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2686 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2687 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2689 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2691 return ((char *)cmd - (char *)buf);
2694 static void ClearAllFWHoles(struct libalias *la);
2697 #define fw_setfield(la, field, num) \
2698 do { \
2699 (field)[(num) - la->fireWallBaseNum] = 1; \
2700 } /*lint -save -e717 */ while(0)/* lint -restore */
2702 #define fw_clrfield(la, field, num) \
2703 do { \
2704 (field)[(num) - la->fireWallBaseNum] = 0; \
2705 } /*lint -save -e717 */ while(0)/* lint -restore */
2707 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2709 static void
2710 InitPunchFW(struct libalias *la)
2713 LIBALIAS_LOCK_ASSERT(la);
2714 la->fireWallField = kmalloc(la->fireWallNumNums,M_ALIAS, M_WAITOK | M_ZERO);
2715 if (la->fireWallField) {
2716 memset(la->fireWallField, 0, la->fireWallNumNums);
2717 if (la->fireWallFD < 0) {
2718 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2720 ClearAllFWHoles(la);
2721 la->fireWallActiveNum = la->fireWallBaseNum;
2725 static void
2726 UninitPunchFW(struct libalias *la)
2729 LIBALIAS_LOCK_ASSERT(la);
2730 ClearAllFWHoles(la);
2731 if (la->fireWallFD >= 0)
2732 close(la->fireWallFD);
2733 la->fireWallFD = -1;
2734 if (la->fireWallField)
2735 kfree(la->fireWallField,M_ALIAS);
2736 la->fireWallField = NULL;
2737 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2740 /* Make a certain link go through the firewall */
2741 void
2742 PunchFWHole(struct alias_link *lnk)
2744 struct libalias *la;
2745 int r; /* Result code */
2746 struct ip_fw rule; /* On-the-fly built rule */
2747 int fwhole; /* Where to punch hole */
2749 LIBALIAS_LOCK_ASSERT(la);
2750 la = lnk->la;
2752 /* Don't do anything unless we are asked to */
2753 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2754 la->fireWallFD < 0 ||
2755 lnk->link_type != LINK_TCP)
2756 return;
2758 memset(&rule, 0, sizeof rule);
2760 /** Build rule **/
2762 /* Find empty slot */
2763 for (fwhole = la->fireWallActiveNum;
2764 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2765 fw_tstfield(la, la->fireWallField, fwhole);
2766 fwhole++);
2767 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2768 for (fwhole = la->fireWallBaseNum;
2769 fwhole < la->fireWallActiveNum &&
2770 fw_tstfield(la, la->fireWallField, fwhole);
2771 fwhole++);
2772 if (fwhole == la->fireWallActiveNum) {
2773 /* No rule point empty - we can't punch more holes. */
2774 la->fireWallActiveNum = la->fireWallBaseNum;
2775 #ifdef LIBALIAS_DEBUG
2776 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2777 #endif
2778 return;
2781 /* Start next search at next position */
2782 la->fireWallActiveNum = fwhole + 1;
2785 * generate two rules of the form
2787 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2788 * accept tcp from DAddr DPort to OAddr OPort
2790 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2791 u_int32_t rulebuf[255];
2792 int i;
2794 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2795 O_ACCEPT, IPPROTO_TCP,
2796 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2797 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2798 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2799 if (r)
2800 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2802 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2803 O_ACCEPT, IPPROTO_TCP,
2804 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2805 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2806 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2807 if (r)
2808 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2811 /* Indicate hole applied */
2812 lnk->data.tcp->fwhole = fwhole;
2813 fw_setfield(la, la->fireWallField, fwhole);
2816 /* Remove a hole in a firewall associated with a particular alias
2817 lnk. Calling this too often is harmless. */
2818 static void
2819 ClearFWHole(struct alias_link *lnk)
2821 struct libalias *la;
2823 LIBALIAS_LOCK_ASSERT(la);
2824 la = lnk->la;
2825 if (lnk->link_type == LINK_TCP) {
2826 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2827 * hole? */
2828 struct ip_fw rule;
2830 if (fwhole < 0)
2831 return;
2833 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2834 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2835 &fwhole, sizeof fwhole));
2836 fw_clrfield(la, la->fireWallField, fwhole);
2837 lnk->data.tcp->fwhole = -1;
2841 /* Clear out the entire range dedicated to firewall holes. */
2842 static void
2843 ClearAllFWHoles(struct libalias *la)
2845 struct ip_fw rule; /* On-the-fly built rule */
2846 int i;
2848 LIBALIAS_LOCK_ASSERT(la);
2849 if (la->fireWallFD < 0)
2850 return;
2852 memset(&rule, 0, sizeof rule);
2853 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2854 int r = i;
2856 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2858 /* XXX: third arg correct here ? /phk */
2859 memset(la->fireWallField, 0, la->fireWallNumNums);
2862 #endif
2864 void
2865 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2868 LIBALIAS_LOCK(la);
2869 #ifndef NO_FW_PUNCH
2870 la->fireWallBaseNum = base;
2871 la->fireWallNumNums = num;
2872 #endif
2873 LIBALIAS_UNLOCK(la);
2876 void
2877 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2880 LIBALIAS_LOCK(la);
2881 la->skinnyPort = port;
2882 LIBALIAS_UNLOCK(la);