sched_setaffinity.2: Small markup fix.
[dragonfly.git] / sys / net / libalias / alias_db.c
blobb8917819bd2d58dd47d5fcdaad7fc72d487ad8d0
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 #include <sys/param.h>
145 #include <sys/kernel.h>
146 #include <sys/module.h>
147 #include <sys/syslog.h>
148 #include <sys/queue.h>
150 #include <sys/socket.h>
151 #include <netinet/tcp.h>
153 #include "alias.h"
154 #include "alias_local.h"
155 #include "alias_mod.h"
158 static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
162 Constants (note: constants are also defined
163 near relevant functions or structs)
166 /* Parameters used for cleanup of expired links */
167 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
168 #define ALIAS_CLEANUP_INTERVAL_SECS 64
169 #define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
171 /* Timeouts (in seconds) for different link types */
172 #define ICMP_EXPIRE_TIME 60
173 #define UDP_EXPIRE_TIME 60
174 #define PROTO_EXPIRE_TIME 60
175 #define FRAGMENT_ID_EXPIRE_TIME 10
176 #define FRAGMENT_PTR_EXPIRE_TIME 30
178 /* TCP link expire time for different cases */
179 /* When the link has been used and closed - minimal grace time to
180 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
181 #ifndef TCP_EXPIRE_DEAD
182 #define TCP_EXPIRE_DEAD 10
183 #endif
185 /* When the link has been used and closed on one side - the other side
186 is allowed to still send data */
187 #ifndef TCP_EXPIRE_SINGLEDEAD
188 #define TCP_EXPIRE_SINGLEDEAD 90
189 #endif
191 /* When the link isn't yet up */
192 #ifndef TCP_EXPIRE_INITIAL
193 #define TCP_EXPIRE_INITIAL 300
194 #endif
196 /* When the link is up */
197 #ifndef TCP_EXPIRE_CONNECTED
198 #define TCP_EXPIRE_CONNECTED 86400
199 #endif
202 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
203 These constants can be anything except zero, which indicates an
204 unknown port number. */
206 #define NO_DEST_PORT 1
207 #define NO_SRC_PORT 1
209 /* Clean up procedure. */
210 static void finishoff(void);
212 /* Kernel module definition. */
213 #ifdef _KERNEL
214 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
216 MODULE_VERSION(libalias, 1);
218 static int
219 alias_mod_handler(module_t mod, int type, void *data)
221 int error;
223 switch (type) {
224 case MOD_LOAD:
225 error = 0;
226 handler_chain_init();
227 break;
228 case MOD_UNLOAD:
229 handler_chain_destroy();
230 finishoff();
231 error = 0;
232 break;
233 default:
234 error = EINVAL;
237 return (error);
240 static moduledata_t alias_mod = {
241 "alias", alias_mod_handler, NULL
244 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
245 #endif
247 /* Internal utility routines (used only in alias_db.c)
249 Lookup table starting points:
250 StartPointIn() -- link table initial search point for
251 incoming packets
252 StartPointOut() -- link table initial search point for
253 outgoing packets
255 Miscellaneous:
256 SeqDiff() -- difference between two TCP sequences
257 ShowAliasStats() -- send alias statistics to a monitor file
261 /* Local prototypes */
262 static u_int StartPointIn(struct in_addr, u_short, int);
264 static u_int
265 StartPointOut(struct in_addr, struct in_addr,
266 u_short, u_short, int);
268 static int SeqDiff(u_long, u_long);
270 #ifndef NO_FW_PUNCH
271 /* Firewall control */
272 static void InitPunchFW(struct libalias *);
273 static void UninitPunchFW(struct libalias *);
274 static void ClearFWHole(struct alias_link *);
276 #endif
278 /* Log file control */
279 static void ShowAliasStats(struct libalias *);
280 static int InitPacketAliasLog(struct libalias *);
281 static void UninitPacketAliasLog(struct libalias *);
283 static u_int
284 StartPointIn(struct in_addr alias_addr,
285 u_short alias_port,
286 int link_type)
288 u_int n;
290 n = alias_addr.s_addr;
291 if (link_type != LINK_PPTP)
292 n += alias_port;
293 n += link_type;
294 return (n % LINK_TABLE_IN_SIZE);
298 static u_int
299 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
300 u_short src_port, u_short dst_port, int link_type)
302 u_int n;
304 n = src_addr.s_addr;
305 n += dst_addr.s_addr;
306 if (link_type != LINK_PPTP) {
307 n += src_port;
308 n += dst_port;
310 n += link_type;
312 return (n % LINK_TABLE_OUT_SIZE);
316 static int
317 SeqDiff(u_long x, u_long y)
319 /* Return the difference between two TCP sequence numbers */
322 This function is encapsulated in case there are any unusual
323 arithmetic conditions that need to be considered.
326 return (ntohl(y) - ntohl(x));
329 #ifdef _KERNEL
331 static void
332 AliasLog(char *str, const char *format, ...)
334 __va_list ap;
336 __va_start(ap, format);
337 kvsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
338 __va_end(ap);
340 #else
341 static void
342 AliasLog(FILE *stream, const char *format, ...)
344 va_list ap;
346 va_start(ap, format);
347 vfprintf(stream, format, ap);
348 va_end(ap);
349 fflush(stream);
351 #endif
353 static void
354 ShowAliasStats(struct libalias *la)
357 LIBALIAS_LOCK_ASSERT(la);
358 /* Used for debugging */
359 if (la->logDesc) {
360 int tot = la->icmpLinkCount + la->udpLinkCount +
361 la->tcpLinkCount + la->pptpLinkCount +
362 la->protoLinkCount + la->fragmentIdLinkCount +
363 la->fragmentPtrLinkCount;
365 AliasLog(la->logDesc,
366 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
367 la->icmpLinkCount,
368 la->udpLinkCount,
369 la->tcpLinkCount,
370 la->pptpLinkCount,
371 la->protoLinkCount,
372 la->fragmentIdLinkCount,
373 la->fragmentPtrLinkCount, tot);
374 #ifndef _KERNEL
375 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
376 #endif
380 /* Internal routines for finding, deleting and adding links
382 Port Allocation:
383 GetNewPort() -- find and reserve new alias port number
384 GetSocket() -- try to allocate a socket for a given port
386 Link creation and deletion:
387 CleanupAliasData() - remove all link chains from lookup table
388 IncrementalCleanup() - look for stale links in a single chain
389 DeleteLink() - remove link
390 AddLink() - add link
391 ReLink() - change link
393 Link search:
394 FindLinkOut() - find link for outgoing packets
395 FindLinkIn() - find link for incoming packets
397 Port search:
398 FindNewPortGroup() - find an available group of ports
401 /* Local prototypes */
402 static int GetNewPort(struct libalias *, struct alias_link *, int);
403 #ifndef NO_USE_SOCKETS
404 static u_short GetSocket(struct libalias *, u_short, int *, int);
405 #endif
406 static void CleanupAliasData(struct libalias *);
408 static void IncrementalCleanup(struct libalias *);
410 static void DeleteLink(struct alias_link *);
412 static struct alias_link *
413 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
414 u_short, u_short, int, int);
416 static struct alias_link *
417 ReLink(struct alias_link *,
418 struct in_addr, struct in_addr, struct in_addr,
419 u_short, u_short, int, int);
421 static struct alias_link *
422 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
424 static struct alias_link *
425 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
428 #define ALIAS_PORT_BASE 0x08000
429 #define ALIAS_PORT_MASK 0x07fff
430 #define ALIAS_PORT_MASK_EVEN 0x07ffe
431 #define GET_NEW_PORT_MAX_ATTEMPTS 20
433 #define GET_ALIAS_PORT -1
434 #define GET_ALIAS_ID GET_ALIAS_PORT
436 #define FIND_EVEN_ALIAS_BASE 1
438 /* GetNewPort() allocates port numbers. Note that if a port number
439 is already in use, that does not mean that it cannot be used by
440 another link concurrently. This is because GetNewPort() looks for
441 unused triplets: (dest addr, dest port, alias port). */
443 static int
444 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
446 int i;
447 int max_trials;
448 u_short port_sys;
449 u_short port_net;
451 LIBALIAS_LOCK_ASSERT(la);
453 Description of alias_port_param for GetNewPort(). When
454 this parameter is zero or positive, it precisely specifies
455 the port number. GetNewPort() will return this number
456 without check that it is in use.
458 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
459 selected port number.
462 if (alias_port_param == GET_ALIAS_PORT) {
464 * The aliasing port is automatically selected by one of
465 * two methods below:
467 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
469 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
471 * When the PKT_ALIAS_SAME_PORTS option is chosen,
472 * the first try will be the actual source port. If
473 * this is already in use, the remainder of the
474 * trials will be random.
476 port_net = lnk->src_port;
477 port_sys = ntohs(port_net);
478 } else {
479 /* First trial and all subsequent are random. */
480 port_sys = krandom() & ALIAS_PORT_MASK;
481 port_sys += ALIAS_PORT_BASE;
482 port_net = htons(port_sys);
484 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
485 lnk->alias_port = (u_short) alias_port_param;
486 return (0);
487 } else {
488 #ifdef LIBALIAS_DEBUG
489 fprintf(stderr, "PacketAlias/GetNewPort(): ");
490 fprintf(stderr, "input parameter error\n");
491 #endif
492 return (-1);
496 /* Port number search */
497 for (i = 0; i < max_trials; i++) {
498 int go_ahead;
499 struct alias_link *search_result;
501 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
502 lnk->dst_port, port_net,
503 lnk->link_type, 0);
505 if (search_result == NULL)
506 go_ahead = 1;
507 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
508 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
509 go_ahead = 1;
510 else
511 go_ahead = 0;
513 if (go_ahead) {
514 #ifndef NO_USE_SOCKETS
515 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
516 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
517 && ((lnk->link_type == LINK_TCP) ||
518 (lnk->link_type == LINK_UDP))) {
519 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
520 lnk->alias_port = port_net;
521 return (0);
523 } else {
524 #endif
525 lnk->alias_port = port_net;
526 return (0);
527 #ifndef NO_USE_SOCKETS
529 #endif
531 port_sys = krandom() & ALIAS_PORT_MASK;
532 port_sys += ALIAS_PORT_BASE;
533 port_net = htons(port_sys);
536 #ifdef LIBALIAS_DEBUG
537 fprintf(stderr, "PacketAlias/GetnewPort(): ");
538 fprintf(stderr, "could not find free port\n");
539 #endif
541 return (-1);
544 #ifndef NO_USE_SOCKETS
545 static u_short
546 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
548 int err;
549 int sock;
550 struct sockaddr_in sock_addr;
552 LIBALIAS_LOCK_ASSERT(la);
553 if (link_type == LINK_TCP)
554 sock = socket(AF_INET, SOCK_STREAM, 0);
555 else if (link_type == LINK_UDP)
556 sock = socket(AF_INET, SOCK_DGRAM, 0);
557 else {
558 #ifdef LIBALIAS_DEBUG
559 fprintf(stderr, "PacketAlias/GetSocket(): ");
560 fprintf(stderr, "incorrect link type\n");
561 #endif
562 return (0);
565 if (sock < 0) {
566 #ifdef LIBALIAS_DEBUG
567 fprintf(stderr, "PacketAlias/GetSocket(): ");
568 fprintf(stderr, "socket() error %d\n", *sockfd);
569 #endif
570 return (0);
572 sock_addr.sin_family = AF_INET;
573 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
574 sock_addr.sin_port = port_net;
576 err = bind(sock,
577 (struct sockaddr *)&sock_addr,
578 sizeof(sock_addr));
579 if (err == 0) {
580 la->sockCount++;
581 *sockfd = sock;
582 return (1);
583 } else {
584 close(sock);
585 return (0);
588 #endif
590 /* FindNewPortGroup() returns a base port number for an available
591 range of contiguous port numbers. Note that if a port number
592 is already in use, that does not mean that it cannot be used by
593 another link concurrently. This is because FindNewPortGroup()
594 looks for unused triplets: (dest addr, dest port, alias port). */
597 FindNewPortGroup(struct libalias *la,
598 struct in_addr dst_addr,
599 struct in_addr alias_addr,
600 u_short src_port,
601 u_short dst_port,
602 u_short port_count,
603 u_char proto,
604 u_char align)
606 int i, j;
607 int max_trials;
608 u_short port_sys;
609 int link_type;
611 LIBALIAS_LOCK_ASSERT(la);
613 * Get link_type from protocol
616 switch (proto) {
617 case IPPROTO_UDP:
618 link_type = LINK_UDP;
619 break;
620 case IPPROTO_TCP:
621 link_type = LINK_TCP;
622 break;
623 default:
624 return (0);
625 break;
629 * The aliasing port is automatically selected by one of two
630 * methods below:
632 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
634 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
636 * When the ALIAS_SAME_PORTS option is chosen, the first
637 * try will be the actual source port. If this is already
638 * in use, the remainder of the trials will be random.
640 port_sys = ntohs(src_port);
642 } else {
644 /* First trial and all subsequent are random. */
645 if (align == FIND_EVEN_ALIAS_BASE)
646 port_sys = krandom() & ALIAS_PORT_MASK_EVEN;
647 else
648 port_sys = krandom() & ALIAS_PORT_MASK;
650 port_sys += ALIAS_PORT_BASE;
653 /* Port number search */
654 for (i = 0; i < max_trials; i++) {
656 struct alias_link *search_result;
658 for (j = 0; j < port_count; j++)
659 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
660 dst_port, htons(port_sys + j),
661 link_type, 0)))
662 break;
664 /* Found a good range, return base */
665 if (j == port_count)
666 return (htons(port_sys));
668 /* Find a new base to try */
669 if (align == FIND_EVEN_ALIAS_BASE)
670 port_sys = krandom() & ALIAS_PORT_MASK_EVEN;
671 else
672 port_sys = krandom() & ALIAS_PORT_MASK;
674 port_sys += ALIAS_PORT_BASE;
677 #ifdef LIBALIAS_DEBUG
678 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
679 fprintf(stderr, "could not find free port(s)\n");
680 #endif
682 return (0);
685 static void
686 CleanupAliasData(struct libalias *la)
688 struct alias_link *lnk;
689 int i;
691 LIBALIAS_LOCK_ASSERT(la);
692 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
693 lnk = LIST_FIRST(&la->linkTableOut[i]);
694 while (lnk != NULL) {
695 struct alias_link *link_next = LIST_NEXT(lnk, list_out);
696 DeleteLink(lnk);
697 lnk = link_next;
701 la->cleanupIndex = 0;
705 static void
706 IncrementalCleanup(struct libalias *la)
708 struct alias_link *lnk, *lnk_tmp;
710 LIBALIAS_LOCK_ASSERT(la);
712 LIST_FOREACH_MUTABLE(lnk, &la->linkTableOut[la->cleanupIndex++],list_out, lnk_tmp) {
713 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
714 DeleteLink(lnk);
717 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
718 la->cleanupIndex = 0;
721 static void
722 DeleteLink(struct alias_link *lnk)
724 struct libalias *la = lnk->la;
726 LIBALIAS_LOCK_ASSERT(la);
727 /* Don't do anything if the link is marked permanent */
728 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
729 return;
731 #ifndef NO_FW_PUNCH
732 /* Delete associated firewall hole, if any */
733 ClearFWHole(lnk);
734 #endif
736 /* Free memory allocated for LSNAT server pool */
737 if (lnk->server != NULL) {
738 struct server *head, *curr, *next;
740 head = curr = lnk->server;
741 do {
742 next = curr->next;
743 kfree(curr,M_ALIAS);
744 } while ((curr = next) != head);
746 /* Adjust output table pointers */
747 LIST_REMOVE(lnk, list_out);
749 /* Adjust input table pointers */
750 LIST_REMOVE(lnk, list_in);
751 #ifndef NO_USE_SOCKETS
752 /* Close socket, if one has been allocated */
753 if (lnk->sockfd != -1) {
754 la->sockCount--;
755 close(lnk->sockfd);
757 #endif
758 /* Link-type dependent cleanup */
759 switch (lnk->link_type) {
760 case LINK_ICMP:
761 la->icmpLinkCount--;
762 break;
763 case LINK_UDP:
764 la->udpLinkCount--;
765 break;
766 case LINK_TCP:
767 la->tcpLinkCount--;
768 kfree(lnk->data.tcp,M_ALIAS);
769 break;
770 case LINK_PPTP:
771 la->pptpLinkCount--;
772 break;
773 case LINK_FRAGMENT_ID:
774 la->fragmentIdLinkCount--;
775 break;
776 case LINK_FRAGMENT_PTR:
777 la->fragmentPtrLinkCount--;
778 if (lnk->data.frag_ptr != NULL)
779 kfree(lnk->data.frag_ptr,M_ALIAS);
780 break;
781 case LINK_ADDR:
782 break;
783 default:
784 la->protoLinkCount--;
785 break;
788 /* Free memory */
789 kfree(lnk,M_ALIAS);
791 /* Write statistics, if logging enabled */
792 if (la->packetAliasMode & PKT_ALIAS_LOG) {
793 ShowAliasStats(la);
798 static struct alias_link *
799 AddLink(struct libalias *la, struct in_addr src_addr,
800 struct in_addr dst_addr,
801 struct in_addr alias_addr,
802 u_short src_port,
803 u_short dst_port,
804 int alias_port_param, /* if less than zero, alias */
805 int link_type)
806 { /* port will be automatically *//* chosen.
807 * If greater than */
808 u_int start_point; /* zero, equal to alias port */
809 struct alias_link *lnk;
811 LIBALIAS_LOCK_ASSERT(la);
812 lnk = kmalloc(sizeof(struct alias_link),M_ALIAS, M_WAITOK | M_ZERO);
813 if (lnk != NULL) {
814 /* Basic initialization */
815 lnk->la = la;
816 lnk->src_addr = src_addr;
817 lnk->dst_addr = dst_addr;
818 lnk->alias_addr = alias_addr;
819 lnk->proxy_addr.s_addr = INADDR_ANY;
820 lnk->src_port = src_port;
821 lnk->dst_port = dst_port;
822 lnk->proxy_port = 0;
823 lnk->server = NULL;
824 lnk->link_type = link_type;
825 #ifndef NO_USE_SOCKETS
826 lnk->sockfd = -1;
827 #endif
828 lnk->flags = 0;
829 lnk->pflags = 0;
830 lnk->timestamp = la->timeStamp;
832 /* Expiration time */
833 switch (link_type) {
834 case LINK_ICMP:
835 lnk->expire_time = ICMP_EXPIRE_TIME;
836 break;
837 case LINK_UDP:
838 lnk->expire_time = UDP_EXPIRE_TIME;
839 break;
840 case LINK_TCP:
841 lnk->expire_time = TCP_EXPIRE_INITIAL;
842 break;
843 case LINK_PPTP:
844 lnk->flags |= LINK_PERMANENT; /* no timeout. */
845 break;
846 case LINK_FRAGMENT_ID:
847 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
848 break;
849 case LINK_FRAGMENT_PTR:
850 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
851 break;
852 case LINK_ADDR:
853 break;
854 default:
855 lnk->expire_time = PROTO_EXPIRE_TIME;
856 break;
859 /* Determine alias flags */
860 if (dst_addr.s_addr == INADDR_ANY)
861 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
862 if (dst_port == 0)
863 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
865 /* Determine alias port */
866 if (GetNewPort(la, lnk, alias_port_param) != 0) {
867 kfree(lnk,M_ALIAS);
868 return (NULL);
870 /* Link-type dependent initialization */
871 switch (link_type) {
872 struct tcp_dat *aux_tcp;
874 case LINK_ICMP:
875 la->icmpLinkCount++;
876 break;
877 case LINK_UDP:
878 la->udpLinkCount++;
879 break;
880 case LINK_TCP:
881 aux_tcp = kmalloc(sizeof(struct tcp_dat),M_ALIAS, M_WAITOK | M_ZERO);
882 if (aux_tcp != NULL) {
883 int i;
885 la->tcpLinkCount++;
886 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
887 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
888 aux_tcp->state.index = 0;
889 aux_tcp->state.ack_modified = 0;
890 for (i = 0; i < N_LINK_TCP_DATA; i++)
891 aux_tcp->ack[i].active = 0;
892 aux_tcp->fwhole = -1;
893 lnk->data.tcp = aux_tcp;
894 } else {
895 #ifdef LIBALIAS_DEBUG
896 fprintf(stderr, "PacketAlias/AddLink: ");
897 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
898 #endif
899 kfree(lnk,M_ALIAS);
900 return (NULL);
902 break;
903 case LINK_PPTP:
904 la->pptpLinkCount++;
905 break;
906 case LINK_FRAGMENT_ID:
907 la->fragmentIdLinkCount++;
908 break;
909 case LINK_FRAGMENT_PTR:
910 la->fragmentPtrLinkCount++;
911 break;
912 case LINK_ADDR:
913 break;
914 default:
915 la->protoLinkCount++;
916 break;
919 /* Set up pointers for output lookup table */
920 start_point = StartPointOut(src_addr, dst_addr,
921 src_port, dst_port, link_type);
922 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
924 /* Set up pointers for input lookup table */
925 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
926 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
927 } else {
928 #ifdef LIBALIAS_DEBUG
929 fprintf(stderr, "PacketAlias/AddLink(): ");
930 fprintf(stderr, "kmalloc() call failed.\n");
931 #endif
933 if (la->packetAliasMode & PKT_ALIAS_LOG) {
934 ShowAliasStats(la);
936 return (lnk);
939 static struct alias_link *
940 ReLink(struct alias_link *old_lnk,
941 struct in_addr src_addr,
942 struct in_addr dst_addr,
943 struct in_addr alias_addr,
944 u_short src_port,
945 u_short dst_port,
946 int alias_port_param, /* if less than zero, alias */
947 int link_type)
948 { /* port will be automatically *//* chosen.
949 * If greater than */
950 struct alias_link *new_lnk; /* zero, equal to alias port */
951 struct libalias *la = old_lnk->la;
953 LIBALIAS_LOCK_ASSERT(la);
954 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
955 src_port, dst_port, alias_port_param,
956 link_type);
957 #ifndef NO_FW_PUNCH
958 if (new_lnk != NULL &&
959 old_lnk->link_type == LINK_TCP &&
960 old_lnk->data.tcp->fwhole > 0) {
961 PunchFWHole(new_lnk);
963 #endif
964 DeleteLink(old_lnk);
965 return (new_lnk);
968 static struct alias_link *
969 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
970 struct in_addr dst_addr,
971 u_short src_port,
972 u_short dst_port,
973 int link_type,
974 int replace_partial_links)
976 u_int i;
977 struct alias_link *lnk;
979 LIBALIAS_LOCK_ASSERT(la);
980 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
981 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
982 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
983 lnk->src_addr.s_addr == src_addr.s_addr &&
984 lnk->src_port == src_port &&
985 lnk->dst_port == dst_port &&
986 lnk->link_type == link_type &&
987 lnk->server == NULL) {
988 lnk->timestamp = la->timeStamp;
989 break;
993 /* Search for partially specified links. */
994 if (lnk == NULL && replace_partial_links) {
995 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
996 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
997 link_type, 0);
998 if (lnk == NULL)
999 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1000 dst_port, link_type, 0);
1002 if (lnk == NULL &&
1003 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1004 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1005 link_type, 0);
1007 if (lnk != NULL) {
1008 lnk = ReLink(lnk,
1009 src_addr, dst_addr, lnk->alias_addr,
1010 src_port, dst_port, lnk->alias_port,
1011 link_type);
1014 return (lnk);
1017 static struct alias_link *
1018 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1019 struct in_addr dst_addr,
1020 u_short src_port,
1021 u_short dst_port,
1022 int link_type,
1023 int replace_partial_links)
1025 struct alias_link *lnk;
1027 LIBALIAS_LOCK_ASSERT(la);
1028 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1029 link_type, replace_partial_links);
1031 if (lnk == NULL) {
1033 * The following allows permanent links to be specified as
1034 * using the default source address (i.e. device interface
1035 * address) without knowing in advance what that address
1036 * is.
1038 if (la->aliasAddress.s_addr != INADDR_ANY &&
1039 src_addr.s_addr == la->aliasAddress.s_addr) {
1040 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1041 link_type, replace_partial_links);
1044 return (lnk);
1048 static struct alias_link *
1049 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1050 struct in_addr alias_addr,
1051 u_short dst_port,
1052 u_short alias_port,
1053 int link_type,
1054 int replace_partial_links)
1056 int flags_in;
1057 u_int start_point;
1058 struct alias_link *lnk;
1059 struct alias_link *lnk_fully_specified;
1060 struct alias_link *lnk_unknown_all;
1061 struct alias_link *lnk_unknown_dst_addr;
1062 struct alias_link *lnk_unknown_dst_port;
1064 LIBALIAS_LOCK_ASSERT(la);
1065 /* Initialize pointers */
1066 lnk_fully_specified = NULL;
1067 lnk_unknown_all = NULL;
1068 lnk_unknown_dst_addr = NULL;
1069 lnk_unknown_dst_port = NULL;
1071 /* If either the dest addr or port is unknown, the search
1072 loop will have to know about this. */
1074 flags_in = 0;
1075 if (dst_addr.s_addr == INADDR_ANY)
1076 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1077 if (dst_port == 0)
1078 flags_in |= LINK_UNKNOWN_DEST_PORT;
1080 /* Search loop */
1081 start_point = StartPointIn(alias_addr, alias_port, link_type);
1082 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1083 int flags;
1085 flags = flags_in | lnk->flags;
1086 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1087 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1088 && lnk->alias_port == alias_port
1089 && lnk->dst_addr.s_addr == dst_addr.s_addr
1090 && lnk->dst_port == dst_port
1091 && lnk->link_type == link_type) {
1092 lnk_fully_specified = lnk;
1093 break;
1095 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1096 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1097 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1098 && lnk->alias_port == alias_port
1099 && lnk->link_type == link_type) {
1100 if (lnk_unknown_all == NULL)
1101 lnk_unknown_all = lnk;
1103 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1104 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1105 && lnk->alias_port == alias_port
1106 && lnk->link_type == link_type
1107 && lnk->dst_port == dst_port) {
1108 if (lnk_unknown_dst_addr == NULL)
1109 lnk_unknown_dst_addr = lnk;
1111 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1112 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1113 && lnk->alias_port == alias_port
1114 && lnk->link_type == link_type
1115 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1116 if (lnk_unknown_dst_port == NULL)
1117 lnk_unknown_dst_port = lnk;
1124 if (lnk_fully_specified != NULL) {
1125 lnk_fully_specified->timestamp = la->timeStamp;
1126 lnk = lnk_fully_specified;
1127 } else if (lnk_unknown_dst_port != NULL)
1128 lnk = lnk_unknown_dst_port;
1129 else if (lnk_unknown_dst_addr != NULL)
1130 lnk = lnk_unknown_dst_addr;
1131 else if (lnk_unknown_all != NULL)
1132 lnk = lnk_unknown_all;
1133 else
1134 return (NULL);
1136 if (replace_partial_links &&
1137 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1138 struct in_addr src_addr;
1139 u_short src_port;
1141 if (lnk->server != NULL) { /* LSNAT link */
1142 src_addr = lnk->server->addr;
1143 src_port = lnk->server->port;
1144 lnk->server = lnk->server->next;
1145 } else {
1146 src_addr = lnk->src_addr;
1147 src_port = lnk->src_port;
1150 lnk = ReLink(lnk,
1151 src_addr, dst_addr, alias_addr,
1152 src_port, dst_port, alias_port,
1153 link_type);
1155 return (lnk);
1158 static struct alias_link *
1159 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1160 struct in_addr alias_addr,
1161 u_short dst_port,
1162 u_short alias_port,
1163 int link_type,
1164 int replace_partial_links)
1166 struct alias_link *lnk;
1168 LIBALIAS_LOCK_ASSERT(la);
1169 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1170 link_type, replace_partial_links);
1172 if (lnk == NULL) {
1174 * The following allows permanent links to be specified as
1175 * using the default aliasing address (i.e. device
1176 * interface address) without knowing in advance what that
1177 * address is.
1179 if (la->aliasAddress.s_addr != INADDR_ANY &&
1180 alias_addr.s_addr == la->aliasAddress.s_addr) {
1181 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1182 link_type, replace_partial_links);
1185 return (lnk);
1191 /* External routines for finding/adding links
1193 -- "external" means outside alias_db.c, but within alias*.c --
1195 FindIcmpIn(), FindIcmpOut()
1196 FindFragmentIn1(), FindFragmentIn2()
1197 AddFragmentPtrLink(), FindFragmentPtr()
1198 FindProtoIn(), FindProtoOut()
1199 FindUdpTcpIn(), FindUdpTcpOut()
1200 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1201 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1202 FindOriginalAddress(), FindAliasAddress()
1204 (prototypes in alias_local.h)
1208 struct alias_link *
1209 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1210 struct in_addr alias_addr,
1211 u_short id_alias,
1212 int create)
1214 struct alias_link *lnk;
1216 LIBALIAS_LOCK_ASSERT(la);
1217 lnk = FindLinkIn(la, dst_addr, alias_addr,
1218 NO_DEST_PORT, id_alias,
1219 LINK_ICMP, 0);
1220 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1221 struct in_addr target_addr;
1223 target_addr = FindOriginalAddress(la, alias_addr);
1224 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1225 id_alias, NO_DEST_PORT, id_alias,
1226 LINK_ICMP);
1228 return (lnk);
1232 struct alias_link *
1233 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1234 struct in_addr dst_addr,
1235 u_short id,
1236 int create)
1238 struct alias_link *lnk;
1240 LIBALIAS_LOCK_ASSERT(la);
1241 lnk = FindLinkOut(la, src_addr, dst_addr,
1242 id, NO_DEST_PORT,
1243 LINK_ICMP, 0);
1244 if (lnk == NULL && create) {
1245 struct in_addr alias_addr;
1247 alias_addr = FindAliasAddress(la, src_addr);
1248 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1249 id, NO_DEST_PORT, GET_ALIAS_ID,
1250 LINK_ICMP);
1252 return (lnk);
1256 struct alias_link *
1257 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1258 struct in_addr alias_addr,
1259 u_short ip_id)
1261 struct alias_link *lnk;
1263 LIBALIAS_LOCK_ASSERT(la);
1264 lnk = FindLinkIn(la, dst_addr, alias_addr,
1265 NO_DEST_PORT, ip_id,
1266 LINK_FRAGMENT_ID, 0);
1268 if (lnk == NULL) {
1269 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1270 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1271 LINK_FRAGMENT_ID);
1273 return (lnk);
1277 struct alias_link *
1278 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1279 * one */
1280 struct in_addr alias_addr, /* is not found. */
1281 u_short ip_id)
1284 LIBALIAS_LOCK_ASSERT(la);
1285 return FindLinkIn(la, dst_addr, alias_addr,
1286 NO_DEST_PORT, ip_id,
1287 LINK_FRAGMENT_ID, 0);
1291 struct alias_link *
1292 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1293 u_short ip_id)
1296 LIBALIAS_LOCK_ASSERT(la);
1297 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1298 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1299 LINK_FRAGMENT_PTR);
1303 struct alias_link *
1304 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1305 u_short ip_id)
1308 LIBALIAS_LOCK_ASSERT(la);
1309 return FindLinkIn(la, dst_addr, la->nullAddress,
1310 NO_DEST_PORT, ip_id,
1311 LINK_FRAGMENT_PTR, 0);
1315 struct alias_link *
1316 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1317 struct in_addr alias_addr,
1318 u_char proto)
1320 struct alias_link *lnk;
1322 LIBALIAS_LOCK_ASSERT(la);
1323 lnk = FindLinkIn(la, dst_addr, alias_addr,
1324 NO_DEST_PORT, 0,
1325 proto, 1);
1327 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1328 struct in_addr target_addr;
1330 target_addr = FindOriginalAddress(la, alias_addr);
1331 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1332 NO_SRC_PORT, NO_DEST_PORT, 0,
1333 proto);
1335 return (lnk);
1339 struct alias_link *
1340 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1341 struct in_addr dst_addr,
1342 u_char proto)
1344 struct alias_link *lnk;
1346 LIBALIAS_LOCK_ASSERT(la);
1347 lnk = FindLinkOut(la, src_addr, dst_addr,
1348 NO_SRC_PORT, NO_DEST_PORT,
1349 proto, 1);
1351 if (lnk == NULL) {
1352 struct in_addr alias_addr;
1354 alias_addr = FindAliasAddress(la, src_addr);
1355 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1356 NO_SRC_PORT, NO_DEST_PORT, 0,
1357 proto);
1359 return (lnk);
1363 struct alias_link *
1364 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1365 struct in_addr alias_addr,
1366 u_short dst_port,
1367 u_short alias_port,
1368 u_char proto,
1369 int create)
1371 int link_type;
1372 struct alias_link *lnk;
1374 LIBALIAS_LOCK_ASSERT(la);
1375 switch (proto) {
1376 case IPPROTO_UDP:
1377 link_type = LINK_UDP;
1378 break;
1379 case IPPROTO_TCP:
1380 link_type = LINK_TCP;
1381 break;
1382 default:
1383 return (NULL);
1384 break;
1387 lnk = FindLinkIn(la, dst_addr, alias_addr,
1388 dst_port, alias_port,
1389 link_type, create);
1391 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1392 struct in_addr target_addr;
1394 target_addr = FindOriginalAddress(la, alias_addr);
1395 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1396 alias_port, dst_port, alias_port,
1397 link_type);
1399 return (lnk);
1403 struct alias_link *
1404 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1405 struct in_addr dst_addr,
1406 u_short src_port,
1407 u_short dst_port,
1408 u_char proto,
1409 int create)
1411 int link_type;
1412 struct alias_link *lnk;
1414 LIBALIAS_LOCK_ASSERT(la);
1415 switch (proto) {
1416 case IPPROTO_UDP:
1417 link_type = LINK_UDP;
1418 break;
1419 case IPPROTO_TCP:
1420 link_type = LINK_TCP;
1421 break;
1422 default:
1423 return (NULL);
1424 break;
1427 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1429 if (lnk == NULL && create) {
1430 struct in_addr alias_addr;
1432 alias_addr = FindAliasAddress(la, src_addr);
1433 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1434 src_port, dst_port, GET_ALIAS_PORT,
1435 link_type);
1437 return (lnk);
1441 struct alias_link *
1442 AddPptp(struct libalias *la, struct in_addr src_addr,
1443 struct in_addr dst_addr,
1444 struct in_addr alias_addr,
1445 u_int16_t src_call_id)
1447 struct alias_link *lnk;
1449 LIBALIAS_LOCK_ASSERT(la);
1450 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1451 src_call_id, 0, GET_ALIAS_PORT,
1452 LINK_PPTP);
1454 return (lnk);
1458 struct alias_link *
1459 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1460 struct in_addr dst_addr,
1461 u_int16_t src_call_id)
1463 u_int i;
1464 struct alias_link *lnk;
1466 LIBALIAS_LOCK_ASSERT(la);
1467 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1468 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1469 if (lnk->link_type == LINK_PPTP &&
1470 lnk->src_addr.s_addr == src_addr.s_addr &&
1471 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1472 lnk->src_port == src_call_id)
1473 break;
1475 return (lnk);
1479 struct alias_link *
1480 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1481 struct in_addr dst_addr,
1482 u_int16_t dst_call_id)
1484 u_int i;
1485 struct alias_link *lnk;
1487 LIBALIAS_LOCK_ASSERT(la);
1488 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1489 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1490 if (lnk->link_type == LINK_PPTP &&
1491 lnk->src_addr.s_addr == src_addr.s_addr &&
1492 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1493 lnk->dst_port == dst_call_id)
1494 break;
1496 return (lnk);
1500 struct alias_link *
1501 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1502 struct in_addr alias_addr,
1503 u_int16_t dst_call_id)
1505 u_int i;
1506 struct alias_link *lnk;
1508 LIBALIAS_LOCK_ASSERT(la);
1509 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1510 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1511 if (lnk->link_type == LINK_PPTP &&
1512 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1513 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1514 lnk->dst_port == dst_call_id)
1515 break;
1517 return (lnk);
1521 struct alias_link *
1522 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1523 struct in_addr alias_addr,
1524 u_int16_t alias_call_id)
1526 struct alias_link *lnk;
1528 LIBALIAS_LOCK_ASSERT(la);
1529 lnk = FindLinkIn(la, dst_addr, alias_addr,
1530 0 /* any */ , alias_call_id,
1531 LINK_PPTP, 0);
1534 return (lnk);
1538 struct alias_link *
1539 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1540 struct in_addr dst_addr,
1541 u_short src_port,
1542 u_short alias_port,
1543 u_char proto)
1545 int link_type;
1546 struct alias_link *lnk;
1548 LIBALIAS_LOCK_ASSERT(la);
1549 switch (proto) {
1550 case IPPROTO_UDP:
1551 link_type = LINK_UDP;
1552 break;
1553 case IPPROTO_TCP:
1554 link_type = LINK_TCP;
1555 break;
1556 default:
1557 return (NULL);
1558 break;
1561 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1563 if (lnk == NULL) {
1564 struct in_addr alias_addr;
1566 alias_addr = FindAliasAddress(la, src_addr);
1567 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1568 src_port, 0, alias_port,
1569 link_type);
1571 return (lnk);
1575 struct in_addr
1576 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1578 struct alias_link *lnk;
1580 LIBALIAS_LOCK_ASSERT(la);
1581 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1582 0, 0, LINK_ADDR, 0);
1583 if (lnk == NULL) {
1584 la->newDefaultLink = 1;
1585 if (la->targetAddress.s_addr == INADDR_ANY)
1586 return (alias_addr);
1587 else if (la->targetAddress.s_addr == INADDR_NONE)
1588 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1589 la->aliasAddress : alias_addr;
1590 else
1591 return (la->targetAddress);
1592 } else {
1593 if (lnk->server != NULL) { /* LSNAT link */
1594 struct in_addr src_addr;
1596 src_addr = lnk->server->addr;
1597 lnk->server = lnk->server->next;
1598 return (src_addr);
1599 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1600 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1601 la->aliasAddress : alias_addr;
1602 else
1603 return (lnk->src_addr);
1608 struct in_addr
1609 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1611 struct alias_link *lnk;
1613 LIBALIAS_LOCK_ASSERT(la);
1614 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1615 0, 0, LINK_ADDR, 0);
1616 if (lnk == NULL) {
1617 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1618 la->aliasAddress : original_addr;
1619 } else {
1620 if (lnk->alias_addr.s_addr == INADDR_ANY)
1621 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1622 la->aliasAddress : original_addr;
1623 else
1624 return (lnk->alias_addr);
1629 /* External routines for getting or changing link data
1630 (external to alias_db.c, but internal to alias*.c)
1632 SetFragmentData(), GetFragmentData()
1633 SetFragmentPtr(), GetFragmentPtr()
1634 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1635 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1636 GetOriginalPort(), GetAliasPort()
1637 SetAckModified(), GetAckModified()
1638 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1639 SetProtocolFlags(), GetProtocolFlags()
1640 SetDestCallId()
1644 void
1645 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1647 lnk->data.frag_addr = src_addr;
1651 void
1652 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1654 *src_addr = lnk->data.frag_addr;
1658 void
1659 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1661 lnk->data.frag_ptr = fptr;
1665 void
1666 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1668 *fptr = lnk->data.frag_ptr;
1672 void
1673 SetStateIn(struct alias_link *lnk, int state)
1675 /* TCP input state */
1676 switch (state) {
1677 case ALIAS_TCP_STATE_DISCONNECTED:
1678 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1679 lnk->expire_time = TCP_EXPIRE_DEAD;
1680 else
1681 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1682 break;
1683 case ALIAS_TCP_STATE_CONNECTED:
1684 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1685 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1686 break;
1687 default:
1688 #ifdef _KERNEL
1689 panic("libalias:SetStateIn() unknown state");
1690 #else
1691 abort();
1692 #endif
1694 lnk->data.tcp->state.in = state;
1698 void
1699 SetStateOut(struct alias_link *lnk, int state)
1701 /* TCP output state */
1702 switch (state) {
1703 case ALIAS_TCP_STATE_DISCONNECTED:
1704 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1705 lnk->expire_time = TCP_EXPIRE_DEAD;
1706 else
1707 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1708 break;
1709 case ALIAS_TCP_STATE_CONNECTED:
1710 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1711 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1712 break;
1713 default:
1714 #ifdef _KERNEL
1715 panic("libalias:SetStateOut() unknown state");
1716 #else
1717 abort();
1718 #endif
1720 lnk->data.tcp->state.out = state;
1725 GetStateIn(struct alias_link *lnk)
1727 /* TCP input state */
1728 return (lnk->data.tcp->state.in);
1733 GetStateOut(struct alias_link *lnk)
1735 /* TCP output state */
1736 return (lnk->data.tcp->state.out);
1740 struct in_addr
1741 GetOriginalAddress(struct alias_link *lnk)
1743 if (lnk->src_addr.s_addr == INADDR_ANY)
1744 return (lnk->la->aliasAddress);
1745 else
1746 return (lnk->src_addr);
1750 struct in_addr
1751 GetDestAddress(struct alias_link *lnk)
1753 return (lnk->dst_addr);
1757 struct in_addr
1758 GetAliasAddress(struct alias_link *lnk)
1760 if (lnk->alias_addr.s_addr == INADDR_ANY)
1761 return (lnk->la->aliasAddress);
1762 else
1763 return (lnk->alias_addr);
1767 struct in_addr
1768 GetDefaultAliasAddress(struct libalias *la)
1771 LIBALIAS_LOCK_ASSERT(la);
1772 return (la->aliasAddress);
1776 void
1777 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1780 LIBALIAS_LOCK_ASSERT(la);
1781 la->aliasAddress = alias_addr;
1785 u_short
1786 GetOriginalPort(struct alias_link *lnk)
1788 return (lnk->src_port);
1792 u_short
1793 GetAliasPort(struct alias_link *lnk)
1795 return (lnk->alias_port);
1798 #ifndef NO_FW_PUNCH
1799 static u_short
1800 GetDestPort(struct alias_link *lnk)
1802 return (lnk->dst_port);
1805 #endif
1807 void
1808 SetAckModified(struct alias_link *lnk)
1810 /* Indicate that ACK numbers have been modified in a TCP connection */
1811 lnk->data.tcp->state.ack_modified = 1;
1815 struct in_addr
1816 GetProxyAddress(struct alias_link *lnk)
1818 return (lnk->proxy_addr);
1822 void
1823 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1825 lnk->proxy_addr = addr;
1829 u_short
1830 GetProxyPort(struct alias_link *lnk)
1832 return (lnk->proxy_port);
1836 void
1837 SetProxyPort(struct alias_link *lnk, u_short port)
1839 lnk->proxy_port = port;
1844 GetAckModified(struct alias_link *lnk)
1846 /* See if ACK numbers have been modified */
1847 return (lnk->data.tcp->state.ack_modified);
1852 GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
1855 Find out how much the ACK number has been altered for an incoming
1856 TCP packet. To do this, a circular list of ACK numbers where the TCP
1857 packet size was altered is searched.
1860 int i;
1861 struct tcphdr *tc;
1862 int delta, ack_diff_min;
1863 u_long ack;
1865 tc = ip_next(pip);
1866 ack = tc->th_ack;
1868 delta = 0;
1869 ack_diff_min = -1;
1870 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1871 struct ack_data_record x;
1873 x = lnk->data.tcp->ack[i];
1874 if (x.active == 1) {
1875 int ack_diff;
1877 ack_diff = SeqDiff(x.ack_new, ack);
1878 if (ack_diff >= 0) {
1879 if (ack_diff_min >= 0) {
1880 if (ack_diff < ack_diff_min) {
1881 delta = x.delta;
1882 ack_diff_min = ack_diff;
1884 } else {
1885 delta = x.delta;
1886 ack_diff_min = ack_diff;
1891 return (delta);
1896 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
1899 Find out how much the sequence number has been altered for an outgoing
1900 TCP packet. To do this, a circular list of ACK numbers where the TCP
1901 packet size was altered is searched.
1904 int i;
1905 struct tcphdr *tc;
1906 int delta, seq_diff_min;
1907 u_long seq;
1909 tc = ip_next(pip);
1910 seq = tc->th_seq;
1912 delta = 0;
1913 seq_diff_min = -1;
1914 for (i = 0; i < N_LINK_TCP_DATA; i++) {
1915 struct ack_data_record x;
1917 x = lnk->data.tcp->ack[i];
1918 if (x.active == 1) {
1919 int seq_diff;
1921 seq_diff = SeqDiff(x.ack_old, seq);
1922 if (seq_diff >= 0) {
1923 if (seq_diff_min >= 0) {
1924 if (seq_diff < seq_diff_min) {
1925 delta = x.delta;
1926 seq_diff_min = seq_diff;
1928 } else {
1929 delta = x.delta;
1930 seq_diff_min = seq_diff;
1935 return (delta);
1939 void
1940 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
1943 When a TCP packet has been altered in length, save this
1944 information in a circular list. If enough packets have
1945 been altered, then this list will begin to overwrite itself.
1948 struct tcphdr *tc;
1949 struct ack_data_record x;
1950 int hlen, tlen, dlen;
1951 int i;
1953 tc = ip_next(pip);
1955 hlen = (pip->ip_hl + tc->th_off) << 2;
1956 tlen = ntohs(pip->ip_len);
1957 dlen = tlen - hlen;
1959 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1960 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1961 x.delta = delta;
1962 x.active = 1;
1964 i = lnk->data.tcp->state.index;
1965 lnk->data.tcp->ack[i] = x;
1967 i++;
1968 if (i == N_LINK_TCP_DATA)
1969 lnk->data.tcp->state.index = 0;
1970 else
1971 lnk->data.tcp->state.index = i;
1974 void
1975 SetExpire(struct alias_link *lnk, int expire)
1977 if (expire == 0) {
1978 lnk->flags &= ~LINK_PERMANENT;
1979 DeleteLink(lnk);
1980 } else if (expire == -1) {
1981 lnk->flags |= LINK_PERMANENT;
1982 } else if (expire > 0) {
1983 lnk->expire_time = expire;
1984 } else {
1985 #ifdef LIBALIAS_DEBUG
1986 fprintf(stderr, "PacketAlias/SetExpire(): ");
1987 fprintf(stderr, "error in expire parameter\n");
1988 #endif
1992 void
1993 ClearCheckNewLink(struct libalias *la)
1996 LIBALIAS_LOCK_ASSERT(la);
1997 la->newDefaultLink = 0;
2000 void
2001 SetProtocolFlags(struct alias_link *lnk, int pflags)
2004 lnk->pflags = pflags;;
2008 GetProtocolFlags(struct alias_link *lnk)
2011 return (lnk->pflags);
2014 void
2015 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2017 struct libalias *la = lnk->la;
2019 LIBALIAS_LOCK_ASSERT(la);
2020 la->deleteAllLinks = 1;
2021 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2022 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2023 la->deleteAllLinks = 0;
2027 /* Miscellaneous Functions
2029 HouseKeeping()
2030 InitPacketAliasLog()
2031 UninitPacketAliasLog()
2035 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2036 is called to find and remove timed-out aliasing links. Logic exists
2037 to sweep through the entire table and linked list structure
2038 every 60 seconds.
2040 (prototype in alias_local.h)
2043 void
2044 HouseKeeping(struct libalias *la)
2046 int i, n;
2047 #ifndef _KERNEL
2048 struct timeval tv;
2049 struct timezone tz;
2050 #endif
2052 LIBALIAS_LOCK_ASSERT(la);
2054 * Save system time (seconds) in global variable timeStamp for use
2055 * by other functions. This is done so as not to unnecessarily
2056 * waste timeline by making system calls.
2058 #ifdef _KERNEL
2059 la->timeStamp = time_uptime;
2060 #else
2061 gettimeofday(&tv, &tz);
2062 la->timeStamp = tv.tv_sec;
2063 #endif
2065 /* Compute number of spokes (output table link chains) to cover */
2066 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2067 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2069 /* Handle different cases */
2070 if (n > 0) {
2071 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2072 n = ALIAS_CLEANUP_MAX_SPOKES;
2073 la->lastCleanupTime = la->timeStamp;
2074 for (i = 0; i < n; i++)
2075 IncrementalCleanup(la);
2076 } else if (n < 0) {
2077 #ifdef LIBALIAS_DEBUG
2078 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2079 fprintf(stderr, "something unexpected in time values\n");
2080 #endif
2081 la->lastCleanupTime = la->timeStamp;
2085 /* Init the log file and enable logging */
2086 static int
2087 InitPacketAliasLog(struct libalias *la)
2090 LIBALIAS_LOCK_ASSERT(la);
2091 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2092 #ifdef _KERNEL
2093 if ((la->logDesc = kmalloc(LIBALIAS_BUF_SIZE,M_ALIAS, M_WAITOK | M_ZERO)))
2095 #else
2096 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2097 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2098 #endif
2099 else
2100 return (ENOMEM); /* log initialization failed */
2101 la->packetAliasMode |= PKT_ALIAS_LOG;
2104 return (1);
2107 /* Close the log-file and disable logging. */
2108 static void
2109 UninitPacketAliasLog(struct libalias *la)
2112 LIBALIAS_LOCK_ASSERT(la);
2113 if (la->logDesc) {
2114 #ifdef _KERNEL
2115 kfree(la->logDesc,M_ALIAS);
2116 #else
2117 fclose(la->logDesc);
2118 #endif
2119 la->logDesc = NULL;
2121 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2124 /* Outside world interfaces
2126 -- "outside world" means other than alias*.c routines --
2128 PacketAliasRedirectPort()
2129 PacketAliasAddServer()
2130 PacketAliasRedirectProto()
2131 PacketAliasRedirectAddr()
2132 PacketAliasRedirectDynamic()
2133 PacketAliasRedirectDelete()
2134 PacketAliasSetAddress()
2135 PacketAliasInit()
2136 PacketAliasUninit()
2137 PacketAliasSetMode()
2139 (prototypes in alias.h)
2142 /* Redirection from a specific public addr:port to a
2143 private addr:port */
2144 struct alias_link *
2145 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2146 struct in_addr dst_addr, u_short dst_port,
2147 struct in_addr alias_addr, u_short alias_port,
2148 u_char proto)
2150 int link_type;
2151 struct alias_link *lnk;
2153 LIBALIAS_LOCK(la);
2154 switch (proto) {
2155 case IPPROTO_UDP:
2156 link_type = LINK_UDP;
2157 break;
2158 case IPPROTO_TCP:
2159 link_type = LINK_TCP;
2160 break;
2161 default:
2162 #ifdef LIBALIAS_DEBUG
2163 fprintf(stderr, "PacketAliasRedirectPort(): ");
2164 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2165 #endif
2166 lnk = NULL;
2167 goto getout;
2170 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2171 src_port, dst_port, alias_port,
2172 link_type);
2174 if (lnk != NULL) {
2175 lnk->flags |= LINK_PERMANENT;
2177 #ifdef LIBALIAS_DEBUG
2178 else {
2179 fprintf(stderr, "PacketAliasRedirectPort(): "
2180 "call to AddLink() failed\n");
2182 #endif
2184 getout:
2185 LIBALIAS_UNLOCK(la);
2186 return (lnk);
2189 /* Add server to the pool of servers */
2191 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2193 struct server *server;
2194 int res;
2196 LIBALIAS_LOCK(la);
2197 (void)la;
2199 server = kmalloc(sizeof(struct server),M_ALIAS, M_WAITOK | M_ZERO);
2201 if (server != NULL) {
2202 struct server *head;
2204 server->addr = addr;
2205 server->port = port;
2207 head = lnk->server;
2208 if (head == NULL)
2209 server->next = server;
2210 else {
2211 struct server *s;
2213 for (s = head; s->next != head; s = s->next);
2214 s->next = server;
2215 server->next = head;
2217 lnk->server = server;
2218 res = 0;
2219 } else
2220 res = -1;
2222 LIBALIAS_UNLOCK(la);
2223 return (res);
2226 /* Redirect packets of a given IP protocol from a specific
2227 public address to a private address */
2228 struct alias_link *
2229 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2230 struct in_addr dst_addr,
2231 struct in_addr alias_addr,
2232 u_char proto)
2234 struct alias_link *lnk;
2236 LIBALIAS_LOCK(la);
2237 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2238 NO_SRC_PORT, NO_DEST_PORT, 0,
2239 proto);
2241 if (lnk != NULL) {
2242 lnk->flags |= LINK_PERMANENT;
2244 #ifdef LIBALIAS_DEBUG
2245 else {
2246 fprintf(stderr, "PacketAliasRedirectProto(): "
2247 "call to AddLink() failed\n");
2249 #endif
2251 LIBALIAS_UNLOCK(la);
2252 return (lnk);
2255 /* Static address translation */
2256 struct alias_link *
2257 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2258 struct in_addr alias_addr)
2260 struct alias_link *lnk;
2262 LIBALIAS_LOCK(la);
2263 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2264 0, 0, 0,
2265 LINK_ADDR);
2267 if (lnk != NULL) {
2268 lnk->flags |= LINK_PERMANENT;
2270 #ifdef LIBALIAS_DEBUG
2271 else {
2272 fprintf(stderr, "PacketAliasRedirectAddr(): "
2273 "call to AddLink() failed\n");
2275 #endif
2277 LIBALIAS_UNLOCK(la);
2278 return (lnk);
2282 /* Mark the aliasing link dynamic */
2284 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2286 int res;
2288 LIBALIAS_LOCK(la);
2289 (void)la;
2291 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2292 res = -1;
2293 else {
2294 lnk->flags &= ~LINK_PERMANENT;
2295 res = 0;
2297 LIBALIAS_UNLOCK(la);
2298 return (res);
2302 void
2303 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2305 /* This is a dangerous function to put in the API,
2306 because an invalid pointer can crash the program. */
2308 LIBALIAS_LOCK(la);
2309 la->deleteAllLinks = 1;
2310 DeleteLink(lnk);
2311 la->deleteAllLinks = 0;
2312 LIBALIAS_UNLOCK(la);
2316 void
2317 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2320 LIBALIAS_LOCK(la);
2321 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2322 && la->aliasAddress.s_addr != addr.s_addr)
2323 CleanupAliasData(la);
2325 la->aliasAddress = addr;
2326 LIBALIAS_UNLOCK(la);
2330 void
2331 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2334 LIBALIAS_LOCK(la);
2335 la->targetAddress = target_addr;
2336 LIBALIAS_UNLOCK(la);
2339 static void
2340 finishoff(void)
2343 while (!LIST_EMPTY(&instancehead))
2344 LibAliasUninit(LIST_FIRST(&instancehead));
2347 struct libalias *
2348 LibAliasInit(struct libalias *la)
2350 int i;
2351 #ifndef _KERNEL
2352 struct timeval tv;
2353 struct timezone tz;
2354 #endif
2356 if (la == NULL) {
2357 la = kmalloc(sizeof *la,M_ALIAS, M_WAITOK | M_ZERO);
2358 if (la == NULL)
2359 return (la);
2361 #ifndef _KERNEL /* kernel cleans up on module unload */
2362 if (LIST_EMPTY(&instancehead))
2363 atexit(finishoff);
2364 #endif
2365 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2367 #ifdef _KERNEL
2368 la->timeStamp = time_uptime;
2369 la->lastCleanupTime = time_uptime;
2370 #else
2371 gettimeofday(&tv, &tz);
2372 la->timeStamp = tv.tv_sec;
2373 la->lastCleanupTime = tv.tv_sec;
2374 #endif
2376 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2377 LIST_INIT(&la->linkTableOut[i]);
2378 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2379 LIST_INIT(&la->linkTableIn[i]);
2380 LIBALIAS_LOCK_INIT(la);
2381 LIBALIAS_LOCK(la);
2382 } else {
2383 LIBALIAS_LOCK(la);
2384 la->deleteAllLinks = 1;
2385 CleanupAliasData(la);
2386 la->deleteAllLinks = 0;
2389 la->aliasAddress.s_addr = INADDR_ANY;
2390 la->targetAddress.s_addr = INADDR_ANY;
2392 la->icmpLinkCount = 0;
2393 la->udpLinkCount = 0;
2394 la->tcpLinkCount = 0;
2395 la->pptpLinkCount = 0;
2396 la->protoLinkCount = 0;
2397 la->fragmentIdLinkCount = 0;
2398 la->fragmentPtrLinkCount = 0;
2399 la->sockCount = 0;
2401 la->cleanupIndex = 0;
2403 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2404 #ifndef NO_USE_SOCKETS
2405 | PKT_ALIAS_USE_SOCKETS
2406 #endif
2407 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2408 #ifndef NO_FW_PUNCH
2409 la->fireWallFD = -1;
2410 #endif
2411 #ifndef _KERNEL
2412 LibAliasRefreshModules();
2413 #endif
2414 LIBALIAS_UNLOCK(la);
2415 return (la);
2418 void
2419 LibAliasUninit(struct libalias *la)
2422 LIBALIAS_LOCK(la);
2423 la->deleteAllLinks = 1;
2424 CleanupAliasData(la);
2425 la->deleteAllLinks = 0;
2426 UninitPacketAliasLog(la);
2427 #ifndef NO_FW_PUNCH
2428 UninitPunchFW(la);
2429 #endif
2430 LIST_REMOVE(la, instancelist);
2431 LIBALIAS_UNLOCK(la);
2432 LIBALIAS_LOCK_DESTROY(la);
2433 kfree(la,M_ALIAS);
2436 /* Change mode for some operations */
2437 unsigned int
2438 LibAliasSetMode(
2439 struct libalias *la,
2440 unsigned int flags, /* Which state to bring flags to */
2441 unsigned int mask /* Mask of which flags to affect (use 0 to
2442 * do a probe for flag values) */
2445 int res = -1;
2447 LIBALIAS_LOCK(la);
2448 /* Enable logging? */
2449 if (flags & mask & PKT_ALIAS_LOG) {
2450 /* Do the enable */
2451 if (InitPacketAliasLog(la) == ENOMEM)
2452 goto getout;
2453 } else
2454 /* _Disable_ logging? */
2455 if (~flags & mask & PKT_ALIAS_LOG) {
2456 UninitPacketAliasLog(la);
2458 #ifndef NO_FW_PUNCH
2459 /* Start punching holes in the firewall? */
2460 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2461 InitPunchFW(la);
2462 } else
2463 /* Stop punching holes in the firewall? */
2464 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2465 UninitPunchFW(la);
2467 #endif
2469 /* Other flags can be set/cleared without special action */
2470 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2471 res = la->packetAliasMode;
2472 getout:
2473 LIBALIAS_UNLOCK(la);
2474 return (res);
2479 LibAliasCheckNewLink(struct libalias *la)
2481 int res;
2483 LIBALIAS_LOCK(la);
2484 res = la->newDefaultLink;
2485 LIBALIAS_UNLOCK(la);
2486 return (res);
2490 #ifndef NO_FW_PUNCH
2492 /*****************
2493 Code to support firewall punching. This shouldn't really be in this
2494 file, but making variables global is evil too.
2495 ****************/
2497 /* Firewall include files */
2498 #include <net/if.h>
2499 #include <netinet/ip_fw.h>
2500 #include <string.h>
2501 #include <err.h>
2504 * helper function, updates the pointer to cmd with the length
2505 * of the current command, and also cleans up the first word of
2506 * the new command in case it has been clobbered before.
2508 static ipfw_insn *
2509 next_cmd(ipfw_insn * cmd)
2511 cmd += F_LEN(cmd);
2512 bzero(cmd, sizeof(*cmd));
2513 return (cmd);
2517 * A function to fill simple commands of size 1.
2518 * Existing flags are preserved.
2520 static ipfw_insn *
2521 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2522 int flags, u_int16_t arg)
2524 cmd->opcode = opcode;
2525 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2526 cmd->arg1 = arg;
2527 return next_cmd(cmd);
2530 static ipfw_insn *
2531 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2533 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2535 cmd->addr.s_addr = addr;
2536 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2539 static ipfw_insn *
2540 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2542 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2544 cmd->ports[0] = cmd->ports[1] = port;
2545 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2548 static int
2549 fill_rule(void *buf, int bufsize, int rulenum,
2550 enum ipfw_opcodes action, int proto,
2551 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2553 struct ip_fw *rule = (struct ip_fw *)buf;
2554 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2556 bzero(buf, bufsize);
2557 rule->rulenum = rulenum;
2559 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2560 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2561 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2562 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2563 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2565 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2566 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2568 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2570 return ((char *)cmd - (char *)buf);
2573 static void ClearAllFWHoles(struct libalias *la);
2576 #define fw_setfield(la, field, num) \
2577 do { \
2578 (field)[(num) - la->fireWallBaseNum] = 1; \
2579 } /*lint -save -e717 */ while(0)/* lint -restore */
2581 #define fw_clrfield(la, field, num) \
2582 do { \
2583 (field)[(num) - la->fireWallBaseNum] = 0; \
2584 } /*lint -save -e717 */ while(0)/* lint -restore */
2586 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2588 static void
2589 InitPunchFW(struct libalias *la)
2592 LIBALIAS_LOCK_ASSERT(la);
2593 la->fireWallField = kmalloc(la->fireWallNumNums,M_ALIAS, M_WAITOK | M_ZERO);
2594 if (la->fireWallField) {
2595 memset(la->fireWallField, 0, la->fireWallNumNums);
2596 if (la->fireWallFD < 0) {
2597 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2599 ClearAllFWHoles(la);
2600 la->fireWallActiveNum = la->fireWallBaseNum;
2604 static void
2605 UninitPunchFW(struct libalias *la)
2608 LIBALIAS_LOCK_ASSERT(la);
2609 ClearAllFWHoles(la);
2610 if (la->fireWallFD >= 0)
2611 close(la->fireWallFD);
2612 la->fireWallFD = -1;
2613 if (la->fireWallField)
2614 kfree(la->fireWallField,M_ALIAS);
2615 la->fireWallField = NULL;
2616 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2619 /* Make a certain link go through the firewall */
2620 void
2621 PunchFWHole(struct alias_link *lnk)
2623 struct libalias *la;
2624 int r; /* Result code */
2625 struct ip_fw rule; /* On-the-fly built rule */
2626 int fwhole; /* Where to punch hole */
2628 LIBALIAS_LOCK_ASSERT(la);
2629 la = lnk->la;
2631 /* Don't do anything unless we are asked to */
2632 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2633 la->fireWallFD < 0 ||
2634 lnk->link_type != LINK_TCP)
2635 return;
2637 memset(&rule, 0, sizeof rule);
2639 /** Build rule **/
2641 /* Find empty slot */
2642 for (fwhole = la->fireWallActiveNum;
2643 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2644 fw_tstfield(la, la->fireWallField, fwhole);
2645 fwhole++);
2646 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2647 for (fwhole = la->fireWallBaseNum;
2648 fwhole < la->fireWallActiveNum &&
2649 fw_tstfield(la, la->fireWallField, fwhole);
2650 fwhole++);
2651 if (fwhole == la->fireWallActiveNum) {
2652 /* No rule point empty - we can't punch more holes. */
2653 la->fireWallActiveNum = la->fireWallBaseNum;
2654 #ifdef LIBALIAS_DEBUG
2655 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2656 #endif
2657 return;
2660 /* Start next search at next position */
2661 la->fireWallActiveNum = fwhole + 1;
2664 * generate two rules of the form
2666 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2667 * accept tcp from DAddr DPort to OAddr OPort
2669 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2670 u_int32_t rulebuf[255];
2671 int i;
2673 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2674 O_ACCEPT, IPPROTO_TCP,
2675 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2676 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2677 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2678 if (r)
2679 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2681 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2682 O_ACCEPT, IPPROTO_TCP,
2683 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2684 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2685 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2686 if (r)
2687 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2690 /* Indicate hole applied */
2691 lnk->data.tcp->fwhole = fwhole;
2692 fw_setfield(la, la->fireWallField, fwhole);
2695 /* Remove a hole in a firewall associated with a particular alias
2696 lnk. Calling this too often is harmless. */
2697 static void
2698 ClearFWHole(struct alias_link *lnk)
2700 struct libalias *la;
2702 LIBALIAS_LOCK_ASSERT(la);
2703 la = lnk->la;
2704 if (lnk->link_type == LINK_TCP) {
2705 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2706 * hole? */
2707 struct ip_fw rule;
2709 if (fwhole < 0)
2710 return;
2712 memset(&rule, 0, sizeof rule); /* useless for ipfw3 */
2713 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2714 &fwhole, sizeof fwhole));
2715 fw_clrfield(la, la->fireWallField, fwhole);
2716 lnk->data.tcp->fwhole = -1;
2720 /* Clear out the entire range dedicated to firewall holes. */
2721 static void
2722 ClearAllFWHoles(struct libalias *la)
2724 struct ip_fw rule; /* On-the-fly built rule */
2725 int i;
2727 LIBALIAS_LOCK_ASSERT(la);
2728 if (la->fireWallFD < 0)
2729 return;
2731 memset(&rule, 0, sizeof rule);
2732 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2733 int r = i;
2735 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2737 /* XXX: third arg correct here ? /phk */
2738 memset(la->fireWallField, 0, la->fireWallNumNums);
2741 #endif
2743 void
2744 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2747 LIBALIAS_LOCK(la);
2748 #ifndef NO_FW_PUNCH
2749 la->fireWallBaseNum = base;
2750 la->fireWallNumNums = num;
2751 #endif
2752 LIBALIAS_UNLOCK(la);
2755 void
2756 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2759 LIBALIAS_LOCK(la);
2760 la->skinnyPort = port;
2761 LIBALIAS_UNLOCK(la);