VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/libalias/alias_db.c@ 21671

Last change on this file since 21671 was 21671, checked in by vboxsync, 15 years ago

NAT: time storage corresponds to Slirp requirements, and time conversion for HouseKeeping

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.4 KB
Line 
1/*-
2 * Copyright (c) 2001 Charles Mott <[email protected]>
3 * All rights reserved.
4 *
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.
13 *
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.
25 */
26
27#ifndef VBOX
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: src/sys/netinet/libalias/alias_db.c,v 1.71.2.2.4.1 2009/04/15 03:14:26 kensmith Exp $");
30#endif
31/*
32 Alias_db.c encapsulates all data structures used for storing
33 packet aliasing data. Other parts of the aliasing software
34 access data through functions provided in this file.
35
36 Data storage is based on the notion of a "link", which is
37 established for ICMP echo/reply packets, UDP datagrams and
38 TCP stream connections. A link stores the original source
39 and destination addresses. For UDP and TCP, it also stores
40 source and destination port numbers, as well as an alias
41 port number. Links are also used to store information about
42 fragments.
43
44 There is a facility for sweeping through and deleting old
45 links as new packets are sent through. A simple timeout is
46 used for ICMP and UDP links. TCP links are left alone unless
47 there is an incomplete connection, in which case the link
48 can be deleted after a certain amount of time.
49
50
51 Initial version: August, 1996 (cjm)
52
53 Version 1.4: September 16, 1996 (cjm)
54 Facility for handling incoming links added.
55
56 Version 1.6: September 18, 1996 (cjm)
57 ICMP data handling simplified.
58
59 Version 1.7: January 9, 1997 (cjm)
60 Fragment handling simplified.
61 Saves pointers for unresolved fragments.
62 Permits links for unspecified remote ports
63 or unspecified remote addresses.
64 Fixed bug which did not properly zero port
65 table entries after a link was deleted.
66 Cleaned up some obsolete comments.
67
68 Version 1.8: January 14, 1997 (cjm)
69 Fixed data type error in StartPoint().
70 (This error did not exist prior to v1.7
71 and was discovered and fixed by Ari Suutari)
72
73 Version 1.9: February 1, 1997
74 Optionally, connections initiated from packet aliasing host
75 machine will will not have their port number aliased unless it
76 conflicts with an aliasing port already being used. (cjm)
77
78 All options earlier being #ifdef'ed are now available through
79 a new interface, SetPacketAliasMode(). This allows run time
80 control (which is now available in PPP+pktAlias through the
81 'alias' keyword). (ee)
82
83 Added ability to create an alias port without
84 either destination address or port specified.
85 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
86
87 Removed K&R style function headers
88 and general cleanup. (ee)
89
90 Added packetAliasMode to replace compiler #defines's (ee)
91
92 Allocates sockets for partially specified
93 ports if ALIAS_USE_SOCKETS defined. (cjm)
94
95 Version 2.0: March, 1997
96 SetAliasAddress() will now clean up alias links
97 if the aliasing address is changed. (cjm)
98
99 PacketAliasPermanentLink() function added to support permanent
100 links. (J. Fortes suggested the need for this.)
101 Examples:
102
103 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port
104
105 (192.168.0.2, port 21) <-> alias port 3604, known dest addr
106 unknown dest port
107
108 These permanent links allow for incoming connections to
109 machines on the local network. They can be given with a
110 user-chosen amount of specificity, with increasing specificity
111 meaning more security. (cjm)
112
113 Quite a bit of rework to the basic engine. The portTable[]
114 array, which kept track of which ports were in use was replaced
115 by a table/linked list structure. (cjm)
116
117 SetExpire() function added. (cjm)
118
119 DeleteLink() no longer frees memory association with a pointer
120 to a fragment (this bug was first recognized by E. Eklund in
121 v1.9).
122
123 Version 2.1: May, 1997 (cjm)
124 Packet aliasing engine reworked so that it can handle
125 multiple external addresses rather than just a single
126 host address.
127
128 PacketAliasRedirectPort() and PacketAliasRedirectAddr()
129 added to the API. The first function is a more generalized
130 version of PacketAliasPermanentLink(). The second function
131 implements static network address translation.
132
133 Version 3.2: July, 2000 (salander and satoh)
134 Added FindNewPortGroup to get contiguous range of port values.
135
136 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
137 link but not actually add one.
138
139 Added FindRtspOut, which is closely derived from FindUdpTcpOut,
140 except that the alias port (from FindNewPortGroup) is provided
141 as input.
142
143 See HISTORY file for additional revisions.
144*/
145
146#ifndef VBOX
147#ifdef _KERNEL
148#include <machine/stdarg.h>
149#include <sys/param.h>
150#include <sys/kernel.h>
151#include <sys/module.h>
152#include <sys/syslog.h>
153#else
154#include <stdarg.h>
155#include <stdlib.h>
156#include <stdio.h>
157#include <sys/errno.h>
158#include <sys/time.h>
159#include <unistd.h>
160#endif
161
162#include <sys/socket.h>
163#include <netinet/tcp.h>
164
165#ifdef _KERNEL
166#include <netinet/libalias/alias.h>
167#include <netinet/libalias/alias_local.h>
168#include <netinet/libalias/alias_mod.h>
169#include <net/if.h>
170#else
171#include "alias.h"
172#include "alias_local.h"
173#include "alias_mod.h"
174#endif
175#else /* !VBOX */
176# include <iprt/assert.h>
177# include <slirp.h>
178# include "alias.h"
179# include "alias_local.h"
180# include "alias_mod.h"
181#endif /* VBOX */
182
183#ifndef VBOX
184static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
185#endif
186
187
188/*
189 Constants (note: constants are also defined
190 near relevant functions or structs)
191*/
192
193/* Parameters used for cleanup of expired links */
194/* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
195#define ALIAS_CLEANUP_INTERVAL_SECS 64
196#define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5)
197
198/* Timeouts (in seconds) for different link types */
199#define ICMP_EXPIRE_TIME 60
200#define UDP_EXPIRE_TIME 60
201#define PROTO_EXPIRE_TIME 60
202#define FRAGMENT_ID_EXPIRE_TIME 10
203#define FRAGMENT_PTR_EXPIRE_TIME 30
204
205/* TCP link expire time for different cases */
206/* When the link has been used and closed - minimal grace time to
207 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */
208#ifndef TCP_EXPIRE_DEAD
209#define TCP_EXPIRE_DEAD 10
210#endif
211
212/* When the link has been used and closed on one side - the other side
213 is allowed to still send data */
214#ifndef TCP_EXPIRE_SINGLEDEAD
215#define TCP_EXPIRE_SINGLEDEAD 90
216#endif
217
218/* When the link isn't yet up */
219#ifndef TCP_EXPIRE_INITIAL
220#define TCP_EXPIRE_INITIAL 300
221#endif
222
223/* When the link is up */
224#ifndef TCP_EXPIRE_CONNECTED
225#define TCP_EXPIRE_CONNECTED 86400
226#endif
227
228
229/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
230 These constants can be anything except zero, which indicates an
231 unknown port number. */
232
233#define NO_DEST_PORT 1
234#define NO_SRC_PORT 1
235
236
237
238/* Data Structures
239
240 The fundamental data structure used in this program is
241 "struct alias_link". Whenever a TCP connection is made,
242 a UDP datagram is sent out, or an ICMP echo request is made,
243 a link record is made (if it has not already been created).
244 The link record is identified by the source address/port
245 and the destination address/port. In the case of an ICMP
246 echo request, the source port is treated as being equivalent
247 with the 16-bit ID number of the ICMP packet.
248
249 The link record also can store some auxiliary data. For
250 TCP connections that have had sequence and acknowledgment
251 modifications, data space is available to track these changes.
252 A state field is used to keep track in changes to the TCP
253 connection state. ID numbers of fragments can also be
254 stored in the auxiliary space. Pointers to unresolved
255 fragments can also be stored.
256
257 The link records support two independent chainings. Lookup
258 tables for input and out tables hold the initial pointers
259 the link chains. On input, the lookup table indexes on alias
260 port and link type. On output, the lookup table indexes on
261 source address, destination address, source port, destination
262 port and link type.
263*/
264
265struct ack_data_record { /* used to save changes to ACK/sequence
266 * numbers */
267 u_long ack_old;
268 u_long ack_new;
269 int delta;
270 int active;
271};
272
273struct tcp_state { /* Information about TCP connection */
274 int in; /* State for outside -> inside */
275 int out; /* State for inside -> outside */
276 int index; /* Index to ACK data array */
277 int ack_modified; /* Indicates whether ACK and
278 * sequence numbers */
279 /* been modified */
280};
281
282#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes
283 * saved for a modified TCP stream */
284struct tcp_dat {
285 struct tcp_state state;
286 struct ack_data_record ack[N_LINK_TCP_DATA];
287 int fwhole; /* Which firewall record is used for this
288 * hole? */
289};
290
291struct server { /* LSNAT server pool (circular list) */
292 struct in_addr addr;
293 u_short port;
294 struct server *next;
295};
296
297struct alias_link { /* Main data structure */
298 struct libalias *la;
299 struct in_addr src_addr; /* Address and port information */
300 struct in_addr dst_addr;
301 struct in_addr alias_addr;
302 struct in_addr proxy_addr;
303 u_short src_port;
304 u_short dst_port;
305 u_short alias_port;
306 u_short proxy_port;
307 struct server *server;
308
309 int link_type; /* Type of link: TCP, UDP, ICMP,
310 * proto, frag */
311
312/* values for link_type */
313#define LINK_ICMP IPPROTO_ICMP
314#define LINK_UDP IPPROTO_UDP
315#define LINK_TCP IPPROTO_TCP
316#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1)
317#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2)
318#define LINK_ADDR (IPPROTO_MAX + 3)
319#define LINK_PPTP (IPPROTO_MAX + 4)
320
321 int flags; /* indicates special characteristics */
322 int pflags; /* protocol-specific flags */
323
324/* flag bits */
325#define LINK_UNKNOWN_DEST_PORT 0x01
326#define LINK_UNKNOWN_DEST_ADDR 0x02
327#define LINK_PERMANENT 0x04
328#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */
329#define LINK_UNFIREWALLED 0x08
330
331 int timestamp; /* Time link was last accessed */
332 int expire_time; /* Expire time for link */
333#ifndef NO_USE_SOCKETS
334# ifndef VBOX
335 /*
336 * in VBox we do not use host's sockets here, which are managed
337 * inside slirp. yes we have to create new sockets here but latter
338 * managment and deletion are in repsponsible of Slirp.
339 */
340 int sockfd; /* socket descriptor */
341# endif
342#endif
343 LIST_ENTRY (alias_link) list_out; /* Linked list of
344 * pointers for */
345 LIST_ENTRY (alias_link) list_in; /* input and output
346 * lookup tables */
347
348 union { /* Auxiliary data */
349 char *frag_ptr;
350 struct in_addr frag_addr;
351 struct tcp_dat *tcp;
352 } data;
353};
354
355/* Clean up procedure. */
356#ifndef VBOX
357static void finishoff(void);
358#endif
359
360/* Kernel module definition. */
361#ifdef _KERNEL
362MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
363
364MODULE_VERSION(libalias, 1);
365
366static int
367alias_mod_handler(module_t mod, int type, void *data)
368{
369 int error;
370
371 switch (type) {
372 case MOD_LOAD:
373 error = 0;
374 handler_chain_init();
375 break;
376 case MOD_QUIESCE:
377 case MOD_UNLOAD:
378 handler_chain_destroy();
379 finishoff();
380 error = 0;
381 break;
382 default:
383 error = EINVAL;
384 }
385
386 return (error);
387}
388
389static moduledata_t alias_mod = {
390 "alias", alias_mod_handler, NULL
391};
392
393DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
394#endif
395
396/* Internal utility routines (used only in alias_db.c)
397
398Lookup table starting points:
399 StartPointIn() -- link table initial search point for
400 incoming packets
401 StartPointOut() -- link table initial search point for
402 outgoing packets
403
404Miscellaneous:
405 SeqDiff() -- difference between two TCP sequences
406 ShowAliasStats() -- send alias statistics to a monitor file
407*/
408
409
410/* Local prototypes */
411static u_int StartPointIn(struct in_addr, u_short, int);
412
413static u_int
414StartPointOut(struct in_addr, struct in_addr,
415 u_short, u_short, int);
416
417static int SeqDiff(u_long, u_long);
418
419#ifndef NO_FW_PUNCH
420/* Firewall control */
421static void InitPunchFW(struct libalias *);
422static void UninitPunchFW(struct libalias *);
423static void ClearFWHole(struct alias_link *);
424
425#endif
426
427/* Log file control */
428static void ShowAliasStats(struct libalias *);
429static int InitPacketAliasLog(struct libalias *);
430static void UninitPacketAliasLog(struct libalias *);
431
432static u_int
433StartPointIn(struct in_addr alias_addr,
434 u_short alias_port,
435 int link_type)
436{
437 u_int n;
438
439 n = alias_addr.s_addr;
440 if (link_type != LINK_PPTP)
441 n += alias_port;
442 n += link_type;
443 return (n % LINK_TABLE_IN_SIZE);
444}
445
446
447static u_int
448StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
449 u_short src_port, u_short dst_port, int link_type)
450{
451 u_int n;
452
453 n = src_addr.s_addr;
454 n += dst_addr.s_addr;
455 if (link_type != LINK_PPTP) {
456 n += src_port;
457 n += dst_port;
458 }
459 n += link_type;
460
461 return (n % LINK_TABLE_OUT_SIZE);
462}
463
464
465static int
466SeqDiff(u_long x, u_long y)
467{
468/* Return the difference between two TCP sequence numbers */
469
470/*
471 This function is encapsulated in case there are any unusual
472 arithmetic conditions that need to be considered.
473*/
474
475 return (ntohl(y) - ntohl(x));
476}
477
478#ifdef _KERNEL
479
480static void
481AliasLog(char *str, const char *format, ...)
482{
483 va_list ap;
484
485 va_start(ap, format);
486 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
487 va_end(ap);
488}
489#else
490static void
491AliasLog(FILE *stream, const char *format, ...)
492{
493# ifndef VBOX
494 va_list ap;
495
496 va_start(ap, format);
497 vfprintf(stream, format, ap);
498 va_end(ap);
499 fflush(stream);
500# else
501
502 va_list args;
503 char buffer[1024];
504 memset(buffer, 0, 1024);
505 va_start(args, format);
506 RTStrPrintfV(buffer, 1024, format, args);
507 va_end(args);
508 /*make it grepable */
509 Log2(("NAT:ALIAS: %s\n", buffer));
510# endif
511}
512#endif
513
514static void
515ShowAliasStats(struct libalias *la)
516{
517
518 LIBALIAS_LOCK_ASSERT(la);
519/* Used for debugging */
520 if (la->logDesc) {
521 int tot = la->icmpLinkCount + la->udpLinkCount +
522 la->tcpLinkCount + la->pptpLinkCount +
523 la->protoLinkCount + la->fragmentIdLinkCount +
524 la->fragmentPtrLinkCount;
525
526 AliasLog(la->logDesc,
527 "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
528 la->icmpLinkCount,
529 la->udpLinkCount,
530 la->tcpLinkCount,
531 la->pptpLinkCount,
532 la->protoLinkCount,
533 la->fragmentIdLinkCount,
534 la->fragmentPtrLinkCount, tot);
535#ifndef _KERNEL
536 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount);
537#endif
538 }
539}
540
541/* Internal routines for finding, deleting and adding links
542
543Port Allocation:
544 GetNewPort() -- find and reserve new alias port number
545 GetSocket() -- try to allocate a socket for a given port
546
547Link creation and deletion:
548 CleanupAliasData() - remove all link chains from lookup table
549 IncrementalCleanup() - look for stale links in a single chain
550 DeleteLink() - remove link
551 AddLink() - add link
552 ReLink() - change link
553
554Link search:
555 FindLinkOut() - find link for outgoing packets
556 FindLinkIn() - find link for incoming packets
557
558Port search:
559 FindNewPortGroup() - find an available group of ports
560*/
561
562/* Local prototypes */
563static int GetNewPort(struct libalias *, struct alias_link *, int);
564#ifndef NO_USE_SOCKETS
565static u_short GetSocket(struct libalias *, u_short, int *, int);
566#endif
567static void CleanupAliasData(struct libalias *);
568
569static void IncrementalCleanup(struct libalias *);
570
571static void DeleteLink(struct alias_link *);
572
573static struct alias_link *
574AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
575 u_short, u_short, int, int);
576
577static struct alias_link *
578ReLink(struct alias_link *,
579 struct in_addr, struct in_addr, struct in_addr,
580 u_short, u_short, int, int);
581
582static struct alias_link *
583 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
584
585static struct alias_link *
586 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
587
588
589#define ALIAS_PORT_BASE 0x08000
590#define ALIAS_PORT_MASK 0x07fff
591#define ALIAS_PORT_MASK_EVEN 0x07ffe
592#define GET_NEW_PORT_MAX_ATTEMPTS 20
593
594#define GET_ALIAS_PORT -1
595#define GET_ALIAS_ID GET_ALIAS_PORT
596
597#define FIND_EVEN_ALIAS_BASE 1
598
599/* GetNewPort() allocates port numbers. Note that if a port number
600 is already in use, that does not mean that it cannot be used by
601 another link concurrently. This is because GetNewPort() looks for
602 unused triplets: (dest addr, dest port, alias port). */
603
604static int
605GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
606{
607 int i;
608 int max_trials;
609 u_short port_sys;
610 u_short port_net;
611
612 LIBALIAS_LOCK_ASSERT(la);
613/*
614 Description of alias_port_param for GetNewPort(). When
615 this parameter is zero or positive, it precisely specifies
616 the port number. GetNewPort() will return this number
617 without check that it is in use.
618
619 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
620 selected port number.
621*/
622
623 if (alias_port_param == GET_ALIAS_PORT) {
624 /*
625 * The aliasing port is automatically selected by one of
626 * two methods below:
627 */
628 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
629
630 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
631 /*
632 * When the PKT_ALIAS_SAME_PORTS option is chosen,
633 * the first try will be the actual source port. If
634 * this is already in use, the remainder of the
635 * trials will be random.
636 */
637 port_net = lnk->src_port;
638 port_sys = ntohs(port_net);
639 } else {
640 /* First trial and all subsequent are random. */
641 port_sys = arc4random() & ALIAS_PORT_MASK;
642 port_sys += ALIAS_PORT_BASE;
643 port_net = htons(port_sys);
644 }
645 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
646 lnk->alias_port = (u_short) alias_port_param;
647 return (0);
648 } else {
649#ifdef LIBALIAS_DEBUG
650 fprintf(stderr, "PacketAlias/GetNewPort(): ");
651 fprintf(stderr, "input parameter error\n");
652#endif
653 return (-1);
654 }
655
656
657/* Port number search */
658 for (i = 0; i < max_trials; i++) {
659 int go_ahead;
660 struct alias_link *search_result;
661
662 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
663 lnk->dst_port, port_net,
664 lnk->link_type, 0);
665
666 if (search_result == NULL)
667 go_ahead = 1;
668 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
669 && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
670 go_ahead = 1;
671 else
672 go_ahead = 0;
673
674 if (go_ahead) {
675#ifndef NO_USE_SOCKETS
676 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
677 && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
678 && ((lnk->link_type == LINK_TCP) ||
679 (lnk->link_type == LINK_UDP))) {
680#ifndef VBOX
681 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
682#else
683 if (GetSocket(la, port_net, NULL, lnk->link_type)) {
684#endif
685 lnk->alias_port = port_net;
686 return (0);
687 }
688 } else {
689#endif
690 lnk->alias_port = port_net;
691 return (0);
692#ifndef NO_USE_SOCKETS
693 }
694#endif
695 }
696 port_sys = arc4random() & ALIAS_PORT_MASK;
697 port_sys += ALIAS_PORT_BASE;
698 port_net = htons(port_sys);
699 }
700
701#ifdef LIBALIAS_DEBUG
702 fprintf(stderr, "PacketAlias/GetnewPort(): ");
703 fprintf(stderr, "could not find free port\n");
704#endif
705
706 return (-1);
707}
708
709#ifndef NO_USE_SOCKETS
710static u_short
711GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
712{
713 int err;
714 int sock;
715 struct sockaddr_in sock_addr;
716#ifdef VBOX
717 int opt = 1;
718 int status = 0;
719 struct socket *so = NULL;
720 struct sockaddr sa_addr;
721 socklen_t socklen = sizeof(struct sockaddr);
722#endif
723
724 LIBALIAS_LOCK_ASSERT(la);
725#ifdef VBOX
726 so = socreate();
727 if (so == NULL)
728 {
729 return 0;
730 }
731#endif
732 if (link_type == LINK_TCP)
733 sock = socket(AF_INET, SOCK_STREAM, 0);
734 else if (link_type == LINK_UDP)
735 sock = socket(AF_INET, SOCK_DGRAM, 0);
736 else {
737#ifdef LIBALIAS_DEBUG
738 fprintf(stderr, "PacketAlias/GetSocket(): ");
739 fprintf(stderr, "incorrect link type\n");
740#endif
741#ifdef VBOX
742 free(so);
743#endif
744 return (0);
745 }
746
747 if (sock < 0) {
748#ifdef LIBALIAS_DEBUG
749 fprintf(stderr, "PacketAlias/GetSocket(): ");
750 fprintf(stderr, "socket() error %d\n", *sockfd);
751#endif
752 return (0);
753 }
754#ifdef VBOX
755 so->s = sock;
756 fd_nonblock(so->s);
757#endif
758 memset(&sock_addr, 0, sizeof(struct sockaddr_in));
759 sock_addr.sin_family = AF_INET;
760 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
761 sock_addr.sin_port = htons(port_net);
762#ifdef RT_OS_DARWIN
763 sock_addr.sin_len = sizeof(struct sockaddr_in);
764#endif
765
766 err = bind(sock,
767 (struct sockaddr *)&sock_addr,
768 sizeof(sock_addr));
769 if (err == 0) {
770 la->sockCount++;
771#ifdef VBOX
772 so->so_expire = la->curtime + SO_EXPIRE;
773 setsockopt(so->s, SOL_SOCKET, SO_BROADCAST,
774 (const char *)&opt, sizeof(opt));
775 status = getsockname(so->s, &sa_addr, &socklen);
776 if (status != 0 || sa_addr.sa_family != AF_INET)
777 {
778 closesocket(so->s);
779 RTMemFree(so);
780 return 0;
781 }
782 so->so_hlport = ((struct sockaddr_in *)&sa_addr)->sin_port;
783 so->so_hladdr.s_addr =
784 ((struct sockaddr_in *)&sa_addr)->sin_addr.s_addr;
785 NSOCK_INC_EX(la);
786 if (link_type == LINK_TCP)
787 {
788 insque(la->pData, so, &la->tcb);
789 }
790 else if (link_type == LINK_UDP)
791 {
792 insque(la->pData, so, &la->udb);
793 }
794 else {
795 Assert(!"Shouldn't be here");
796 }
797
798#else
799 *sockfd = sock;
800#endif
801 return (1);
802 } else {
803 close(sock);
804 return (0);
805 }
806}
807#endif
808
809/* FindNewPortGroup() returns a base port number for an available
810 range of contiguous port numbers. Note that if a port number
811 is already in use, that does not mean that it cannot be used by
812 another link concurrently. This is because FindNewPortGroup()
813 looks for unused triplets: (dest addr, dest port, alias port). */
814
815int
816FindNewPortGroup(struct libalias *la,
817 struct in_addr dst_addr,
818 struct in_addr alias_addr,
819 u_short src_port,
820 u_short dst_port,
821 u_short port_count,
822 u_char proto,
823 u_char align)
824{
825 int i, j;
826 int max_trials;
827 u_short port_sys;
828 int link_type;
829
830 LIBALIAS_LOCK_ASSERT(la);
831 /*
832 * Get link_type from protocol
833 */
834
835 switch (proto) {
836 case IPPROTO_UDP:
837 link_type = LINK_UDP;
838 break;
839 case IPPROTO_TCP:
840 link_type = LINK_TCP;
841 break;
842 default:
843 return (0);
844 break;
845 }
846
847 /*
848 * The aliasing port is automatically selected by one of two
849 * methods below:
850 */
851 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
852
853 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
854 /*
855 * When the ALIAS_SAME_PORTS option is chosen, the first
856 * try will be the actual source port. If this is already
857 * in use, the remainder of the trials will be random.
858 */
859 port_sys = ntohs(src_port);
860
861 } else {
862
863 /* First trial and all subsequent are random. */
864 if (align == FIND_EVEN_ALIAS_BASE)
865 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
866 else
867 port_sys = arc4random() & ALIAS_PORT_MASK;
868
869 port_sys += ALIAS_PORT_BASE;
870 }
871
872/* Port number search */
873 for (i = 0; i < max_trials; i++) {
874
875 struct alias_link *search_result;
876
877 for (j = 0; j < port_count; j++)
878 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
879 dst_port, htons(port_sys + j),
880 link_type, 0)))
881 break;
882
883 /* Found a good range, return base */
884 if (j == port_count)
885 return (htons(port_sys));
886
887 /* Find a new base to try */
888 if (align == FIND_EVEN_ALIAS_BASE)
889 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
890 else
891 port_sys = arc4random() & ALIAS_PORT_MASK;
892
893 port_sys += ALIAS_PORT_BASE;
894 }
895
896#ifdef LIBALIAS_DEBUG
897 fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
898 fprintf(stderr, "could not find free port(s)\n");
899#endif
900
901 return (0);
902}
903
904static void
905CleanupAliasData(struct libalias *la)
906{
907 struct alias_link *lnk;
908 int i;
909
910 LIBALIAS_LOCK_ASSERT(la);
911 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
912 lnk = LIST_FIRST(&la->linkTableOut[i]);
913 while (lnk != NULL) {
914 struct alias_link *link_next = LIST_NEXT(lnk, list_out);
915 DeleteLink(lnk);
916 lnk = link_next;
917 }
918 }
919
920 la->cleanupIndex = 0;
921}
922
923
924static void
925IncrementalCleanup(struct libalias *la)
926{
927 struct alias_link *lnk, *lnk_tmp;
928
929 LIBALIAS_LOCK_ASSERT(la);
930 LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
931 list_out, lnk_tmp) {
932#ifndef VBOX
933 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
934#else
935 /* libalias counts time in seconds while slirp in millis */
936 if (la->timeStamp - lnk->timestamp > (1000 * lnk->expire_time))
937#endif
938 DeleteLink(lnk);
939 }
940
941 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
942 la->cleanupIndex = 0;
943}
944
945static void
946DeleteLink(struct alias_link *lnk)
947{
948 struct libalias *la = lnk->la;
949
950 LIBALIAS_LOCK_ASSERT(la);
951/* Don't do anything if the link is marked permanent */
952 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
953 return;
954
955#ifndef NO_FW_PUNCH
956/* Delete associated firewall hole, if any */
957 ClearFWHole(lnk);
958#endif
959
960/* Free memory allocated for LSNAT server pool */
961 if (lnk->server != NULL) {
962 struct server *head, *curr, *next;
963
964 head = curr = lnk->server;
965 do {
966 next = curr->next;
967 free(curr);
968 } while ((curr = next) != head);
969 }
970/* Adjust output table pointers */
971 LIST_REMOVE(lnk, list_out);
972
973/* Adjust input table pointers */
974 LIST_REMOVE(lnk, list_in);
975#ifndef NO_USE_SOCKETS
976/* Close socket, if one has been allocated */
977# ifndef VBOX
978 if (lnk->sockfd != -1) {
979 la->sockCount--;
980 close(lnk->sockfd);
981 }
982# else
983 /* Slirp will close the socket in its own way */
984# endif
985#endif
986/* Link-type dependent cleanup */
987 switch (lnk->link_type) {
988 case LINK_ICMP:
989 la->icmpLinkCount--;
990 break;
991 case LINK_UDP:
992 la->udpLinkCount--;
993 break;
994 case LINK_TCP:
995 la->tcpLinkCount--;
996 free(lnk->data.tcp);
997 break;
998 case LINK_PPTP:
999 la->pptpLinkCount--;
1000 break;
1001 case LINK_FRAGMENT_ID:
1002 la->fragmentIdLinkCount--;
1003 break;
1004 case LINK_FRAGMENT_PTR:
1005 la->fragmentPtrLinkCount--;
1006 if (lnk->data.frag_ptr != NULL)
1007 free(lnk->data.frag_ptr);
1008 break;
1009 case LINK_ADDR:
1010 break;
1011 default:
1012 la->protoLinkCount--;
1013 break;
1014 }
1015
1016/* Free memory */
1017 free(lnk);
1018
1019/* Write statistics, if logging enabled */
1020 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1021 ShowAliasStats(la);
1022 }
1023}
1024
1025
1026static struct alias_link *
1027AddLink(struct libalias *la, struct in_addr src_addr,
1028 struct in_addr dst_addr,
1029 struct in_addr alias_addr,
1030 u_short src_port,
1031 u_short dst_port,
1032 int alias_port_param, /* if less than zero, alias */
1033 int link_type)
1034{ /* port will be automatically *//* chosen.
1035 * If greater than */
1036 u_int start_point; /* zero, equal to alias port */
1037 struct alias_link *lnk;
1038
1039 LIBALIAS_LOCK_ASSERT(la);
1040 lnk = malloc(sizeof(struct alias_link));
1041 if (lnk != NULL) {
1042 /* Basic initialization */
1043 lnk->la = la;
1044 lnk->src_addr = src_addr;
1045 lnk->dst_addr = dst_addr;
1046 lnk->alias_addr = alias_addr;
1047 lnk->proxy_addr.s_addr = INADDR_ANY;
1048 lnk->src_port = src_port;
1049 lnk->dst_port = dst_port;
1050 lnk->proxy_port = 0;
1051 lnk->server = NULL;
1052 lnk->link_type = link_type;
1053#ifndef NO_USE_SOCKETS
1054# ifndef VBOX
1055 lnk->sockfd = -1;
1056# endif
1057#endif
1058 lnk->flags = 0;
1059 lnk->pflags = 0;
1060 lnk->timestamp = la->timeStamp;
1061
1062 /* Expiration time */
1063 switch (link_type) {
1064 case LINK_ICMP:
1065 lnk->expire_time = ICMP_EXPIRE_TIME;
1066 break;
1067 case LINK_UDP:
1068 lnk->expire_time = UDP_EXPIRE_TIME;
1069 break;
1070 case LINK_TCP:
1071 lnk->expire_time = TCP_EXPIRE_INITIAL;
1072 break;
1073 case LINK_PPTP:
1074 lnk->flags |= LINK_PERMANENT; /* no timeout. */
1075 break;
1076 case LINK_FRAGMENT_ID:
1077 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1078 break;
1079 case LINK_FRAGMENT_PTR:
1080 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1081 break;
1082 case LINK_ADDR:
1083 break;
1084 default:
1085 lnk->expire_time = PROTO_EXPIRE_TIME;
1086 break;
1087 }
1088
1089 /* Determine alias flags */
1090 if (dst_addr.s_addr == INADDR_ANY)
1091 lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
1092 if (dst_port == 0)
1093 lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1094
1095 /* Determine alias port */
1096 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1097 free(lnk);
1098 return (NULL);
1099 }
1100 /* Link-type dependent initialization */
1101 switch (link_type) {
1102 struct tcp_dat *aux_tcp;
1103
1104 case LINK_ICMP:
1105 la->icmpLinkCount++;
1106 break;
1107 case LINK_UDP:
1108 la->udpLinkCount++;
1109 break;
1110 case LINK_TCP:
1111 aux_tcp = malloc(sizeof(struct tcp_dat));
1112 if (aux_tcp != NULL) {
1113 int i;
1114
1115 la->tcpLinkCount++;
1116 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1117 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1118 aux_tcp->state.index = 0;
1119 aux_tcp->state.ack_modified = 0;
1120 for (i = 0; i < N_LINK_TCP_DATA; i++)
1121 aux_tcp->ack[i].active = 0;
1122 aux_tcp->fwhole = -1;
1123 lnk->data.tcp = aux_tcp;
1124 } else {
1125#ifdef LIBALIAS_DEBUG
1126 fprintf(stderr, "PacketAlias/AddLink: ");
1127 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1128#endif
1129 free(lnk);
1130 return (NULL);
1131 }
1132 break;
1133 case LINK_PPTP:
1134 la->pptpLinkCount++;
1135 break;
1136 case LINK_FRAGMENT_ID:
1137 la->fragmentIdLinkCount++;
1138 break;
1139 case LINK_FRAGMENT_PTR:
1140 la->fragmentPtrLinkCount++;
1141 break;
1142 case LINK_ADDR:
1143 break;
1144 default:
1145 la->protoLinkCount++;
1146 break;
1147 }
1148
1149 /* Set up pointers for output lookup table */
1150 start_point = StartPointOut(src_addr, dst_addr,
1151 src_port, dst_port, link_type);
1152 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1153
1154 /* Set up pointers for input lookup table */
1155 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1156 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1157 } else {
1158#ifdef LIBALIAS_DEBUG
1159 fprintf(stderr, "PacketAlias/AddLink(): ");
1160 fprintf(stderr, "malloc() call failed.\n");
1161#endif
1162 }
1163 if (la->packetAliasMode & PKT_ALIAS_LOG) {
1164 ShowAliasStats(la);
1165 }
1166 return (lnk);
1167}
1168
1169static struct alias_link *
1170ReLink(struct alias_link *old_lnk,
1171 struct in_addr src_addr,
1172 struct in_addr dst_addr,
1173 struct in_addr alias_addr,
1174 u_short src_port,
1175 u_short dst_port,
1176 int alias_port_param, /* if less than zero, alias */
1177 int link_type)
1178{ /* port will be automatically *//* chosen.
1179 * If greater than */
1180 struct alias_link *new_lnk; /* zero, equal to alias port */
1181 struct libalias *la = old_lnk->la;
1182
1183 LIBALIAS_LOCK_ASSERT(la);
1184 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1185 src_port, dst_port, alias_port_param,
1186 link_type);
1187#ifndef NO_FW_PUNCH
1188 if (new_lnk != NULL &&
1189 old_lnk->link_type == LINK_TCP &&
1190 old_lnk->data.tcp->fwhole > 0) {
1191 PunchFWHole(new_lnk);
1192 }
1193#endif
1194 DeleteLink(old_lnk);
1195 return (new_lnk);
1196}
1197
1198static struct alias_link *
1199_FindLinkOut(struct libalias *la, struct in_addr src_addr,
1200 struct in_addr dst_addr,
1201 u_short src_port,
1202 u_short dst_port,
1203 int link_type,
1204 int replace_partial_links)
1205{
1206 u_int i;
1207 struct alias_link *lnk;
1208
1209 LIBALIAS_LOCK_ASSERT(la);
1210 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1211 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1212 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1213 lnk->src_addr.s_addr == src_addr.s_addr &&
1214 lnk->src_port == src_port &&
1215 lnk->dst_port == dst_port &&
1216 lnk->link_type == link_type &&
1217 lnk->server == NULL) {
1218 lnk->timestamp = la->timeStamp;
1219 break;
1220 }
1221 }
1222
1223/* Search for partially specified links. */
1224 if (lnk == NULL && replace_partial_links) {
1225 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1226 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1227 link_type, 0);
1228 if (lnk == NULL)
1229 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1230 dst_port, link_type, 0);
1231 }
1232 if (lnk == NULL &&
1233 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1234 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1235 link_type, 0);
1236 }
1237 if (lnk != NULL) {
1238 lnk = ReLink(lnk,
1239 src_addr, dst_addr, lnk->alias_addr,
1240 src_port, dst_port, lnk->alias_port,
1241 link_type);
1242 }
1243 }
1244 return (lnk);
1245}
1246
1247static struct alias_link *
1248FindLinkOut(struct libalias *la, struct in_addr src_addr,
1249 struct in_addr dst_addr,
1250 u_short src_port,
1251 u_short dst_port,
1252 int link_type,
1253 int replace_partial_links)
1254{
1255 struct alias_link *lnk;
1256
1257 LIBALIAS_LOCK_ASSERT(la);
1258 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1259 link_type, replace_partial_links);
1260
1261 if (lnk == NULL) {
1262 /*
1263 * The following allows permanent links to be specified as
1264 * using the default source address (i.e. device interface
1265 * address) without knowing in advance what that address
1266 * is.
1267 */
1268 if (la->aliasAddress.s_addr != INADDR_ANY &&
1269 src_addr.s_addr == la->aliasAddress.s_addr) {
1270 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1271 link_type, replace_partial_links);
1272 }
1273 }
1274 return (lnk);
1275}
1276
1277
1278static struct alias_link *
1279_FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1280 struct in_addr alias_addr,
1281 u_short dst_port,
1282 u_short alias_port,
1283 int link_type,
1284 int replace_partial_links)
1285{
1286 int flags_in;
1287 u_int start_point;
1288 struct alias_link *lnk;
1289 struct alias_link *lnk_fully_specified;
1290 struct alias_link *lnk_unknown_all;
1291 struct alias_link *lnk_unknown_dst_addr;
1292 struct alias_link *lnk_unknown_dst_port;
1293
1294 LIBALIAS_LOCK_ASSERT(la);
1295/* Initialize pointers */
1296 lnk_fully_specified = NULL;
1297 lnk_unknown_all = NULL;
1298 lnk_unknown_dst_addr = NULL;
1299 lnk_unknown_dst_port = NULL;
1300
1301/* If either the dest addr or port is unknown, the search
1302 loop will have to know about this. */
1303
1304 flags_in = 0;
1305 if (dst_addr.s_addr == INADDR_ANY)
1306 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1307 if (dst_port == 0)
1308 flags_in |= LINK_UNKNOWN_DEST_PORT;
1309
1310/* Search loop */
1311 start_point = StartPointIn(alias_addr, alias_port, link_type);
1312 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1313 int flags;
1314
1315 flags = flags_in | lnk->flags;
1316 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1317 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1318 && lnk->alias_port == alias_port
1319 && lnk->dst_addr.s_addr == dst_addr.s_addr
1320 && lnk->dst_port == dst_port
1321 && lnk->link_type == link_type) {
1322 lnk_fully_specified = lnk;
1323 break;
1324 }
1325 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1326 && (flags & LINK_UNKNOWN_DEST_PORT)) {
1327 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1328 && lnk->alias_port == alias_port
1329 && lnk->link_type == link_type) {
1330 if (lnk_unknown_all == NULL)
1331 lnk_unknown_all = lnk;
1332 }
1333 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1334 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1335 && lnk->alias_port == alias_port
1336 && lnk->link_type == link_type
1337 && lnk->dst_port == dst_port) {
1338 if (lnk_unknown_dst_addr == NULL)
1339 lnk_unknown_dst_addr = lnk;
1340 }
1341 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1342 if (lnk->alias_addr.s_addr == alias_addr.s_addr
1343 && lnk->alias_port == alias_port
1344 && lnk->link_type == link_type
1345 && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1346 if (lnk_unknown_dst_port == NULL)
1347 lnk_unknown_dst_port = lnk;
1348 }
1349 }
1350 }
1351
1352
1353
1354 if (lnk_fully_specified != NULL) {
1355 lnk_fully_specified->timestamp = la->timeStamp;
1356 lnk = lnk_fully_specified;
1357 } else if (lnk_unknown_dst_port != NULL)
1358 lnk = lnk_unknown_dst_port;
1359 else if (lnk_unknown_dst_addr != NULL)
1360 lnk = lnk_unknown_dst_addr;
1361 else if (lnk_unknown_all != NULL)
1362 lnk = lnk_unknown_all;
1363 else
1364 return (NULL);
1365
1366 if (replace_partial_links &&
1367 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1368 struct in_addr src_addr;
1369 u_short src_port;
1370
1371 if (lnk->server != NULL) { /* LSNAT link */
1372 src_addr = lnk->server->addr;
1373 src_port = lnk->server->port;
1374 lnk->server = lnk->server->next;
1375 } else {
1376 src_addr = lnk->src_addr;
1377 src_port = lnk->src_port;
1378 }
1379
1380 lnk = ReLink(lnk,
1381 src_addr, dst_addr, alias_addr,
1382 src_port, dst_port, alias_port,
1383 link_type);
1384 }
1385 return (lnk);
1386}
1387
1388static struct alias_link *
1389FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1390 struct in_addr alias_addr,
1391 u_short dst_port,
1392 u_short alias_port,
1393 int link_type,
1394 int replace_partial_links)
1395{
1396 struct alias_link *lnk;
1397
1398 LIBALIAS_LOCK_ASSERT(la);
1399 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1400 link_type, replace_partial_links);
1401
1402 if (lnk == NULL) {
1403 /*
1404 * The following allows permanent links to be specified as
1405 * using the default aliasing address (i.e. device
1406 * interface address) without knowing in advance what that
1407 * address is.
1408 */
1409 if (la->aliasAddress.s_addr != INADDR_ANY &&
1410 alias_addr.s_addr == la->aliasAddress.s_addr) {
1411 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1412 link_type, replace_partial_links);
1413 }
1414 }
1415 return (lnk);
1416}
1417
1418
1419
1420
1421/* External routines for finding/adding links
1422
1423-- "external" means outside alias_db.c, but within alias*.c --
1424
1425 FindIcmpIn(), FindIcmpOut()
1426 FindFragmentIn1(), FindFragmentIn2()
1427 AddFragmentPtrLink(), FindFragmentPtr()
1428 FindProtoIn(), FindProtoOut()
1429 FindUdpTcpIn(), FindUdpTcpOut()
1430 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1431 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1432 FindOriginalAddress(), FindAliasAddress()
1433
1434(prototypes in alias_local.h)
1435*/
1436
1437
1438struct alias_link *
1439FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1440 struct in_addr alias_addr,
1441 u_short id_alias,
1442 int create)
1443{
1444 struct alias_link *lnk;
1445
1446 LIBALIAS_LOCK_ASSERT(la);
1447 lnk = FindLinkIn(la, dst_addr, alias_addr,
1448 NO_DEST_PORT, id_alias,
1449 LINK_ICMP, 0);
1450 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1451 struct in_addr target_addr;
1452
1453 target_addr = FindOriginalAddress(la, alias_addr);
1454 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1455 id_alias, NO_DEST_PORT, id_alias,
1456 LINK_ICMP);
1457 }
1458 return (lnk);
1459}
1460
1461
1462struct alias_link *
1463FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1464 struct in_addr dst_addr,
1465 u_short id,
1466 int create)
1467{
1468 struct alias_link *lnk;
1469
1470 LIBALIAS_LOCK_ASSERT(la);
1471 lnk = FindLinkOut(la, src_addr, dst_addr,
1472 id, NO_DEST_PORT,
1473 LINK_ICMP, 0);
1474 if (lnk == NULL && create) {
1475 struct in_addr alias_addr;
1476
1477 alias_addr = FindAliasAddress(la, src_addr);
1478 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1479 id, NO_DEST_PORT, GET_ALIAS_ID,
1480 LINK_ICMP);
1481 }
1482 return (lnk);
1483}
1484
1485
1486struct alias_link *
1487FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1488 struct in_addr alias_addr,
1489 u_short ip_id)
1490{
1491 struct alias_link *lnk;
1492
1493 LIBALIAS_LOCK_ASSERT(la);
1494 lnk = FindLinkIn(la, dst_addr, alias_addr,
1495 NO_DEST_PORT, ip_id,
1496 LINK_FRAGMENT_ID, 0);
1497
1498 if (lnk == NULL) {
1499 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1500 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1501 LINK_FRAGMENT_ID);
1502 }
1503 return (lnk);
1504}
1505
1506
1507struct alias_link *
1508FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if
1509 * one */
1510 struct in_addr alias_addr, /* is not found. */
1511 u_short ip_id)
1512{
1513
1514 LIBALIAS_LOCK_ASSERT(la);
1515 return FindLinkIn(la, dst_addr, alias_addr,
1516 NO_DEST_PORT, ip_id,
1517 LINK_FRAGMENT_ID, 0);
1518}
1519
1520
1521struct alias_link *
1522AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1523 u_short ip_id)
1524{
1525
1526 LIBALIAS_LOCK_ASSERT(la);
1527 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1528 NO_SRC_PORT, NO_DEST_PORT, ip_id,
1529 LINK_FRAGMENT_PTR);
1530}
1531
1532
1533struct alias_link *
1534FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1535 u_short ip_id)
1536{
1537
1538 LIBALIAS_LOCK_ASSERT(la);
1539 return FindLinkIn(la, dst_addr, la->nullAddress,
1540 NO_DEST_PORT, ip_id,
1541 LINK_FRAGMENT_PTR, 0);
1542}
1543
1544
1545struct alias_link *
1546FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1547 struct in_addr alias_addr,
1548 u_char proto)
1549{
1550 struct alias_link *lnk;
1551
1552 LIBALIAS_LOCK_ASSERT(la);
1553 lnk = FindLinkIn(la, dst_addr, alias_addr,
1554 NO_DEST_PORT, 0,
1555 proto, 1);
1556
1557 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1558 struct in_addr target_addr;
1559
1560 target_addr = FindOriginalAddress(la, alias_addr);
1561 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1562 NO_SRC_PORT, NO_DEST_PORT, 0,
1563 proto);
1564 }
1565 return (lnk);
1566}
1567
1568
1569struct alias_link *
1570FindProtoOut(struct libalias *la, struct in_addr src_addr,
1571 struct in_addr dst_addr,
1572 u_char proto)
1573{
1574 struct alias_link *lnk;
1575
1576 LIBALIAS_LOCK_ASSERT(la);
1577 lnk = FindLinkOut(la, src_addr, dst_addr,
1578 NO_SRC_PORT, NO_DEST_PORT,
1579 proto, 1);
1580
1581 if (lnk == NULL) {
1582 struct in_addr alias_addr;
1583
1584 alias_addr = FindAliasAddress(la, src_addr);
1585 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1586 NO_SRC_PORT, NO_DEST_PORT, 0,
1587 proto);
1588 }
1589 return (lnk);
1590}
1591
1592
1593struct alias_link *
1594FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1595 struct in_addr alias_addr,
1596 u_short dst_port,
1597 u_short alias_port,
1598 u_char proto,
1599 int create)
1600{
1601 int link_type;
1602 struct alias_link *lnk;
1603
1604 LIBALIAS_LOCK_ASSERT(la);
1605 switch (proto) {
1606 case IPPROTO_UDP:
1607 link_type = LINK_UDP;
1608 break;
1609 case IPPROTO_TCP:
1610 link_type = LINK_TCP;
1611 break;
1612 default:
1613 return (NULL);
1614 break;
1615 }
1616
1617 lnk = FindLinkIn(la, dst_addr, alias_addr,
1618 dst_port, alias_port,
1619 link_type, create);
1620
1621 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1622 struct in_addr target_addr;
1623
1624 target_addr = FindOriginalAddress(la, alias_addr);
1625 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1626 alias_port, dst_port, alias_port,
1627 link_type);
1628 }
1629 return (lnk);
1630}
1631
1632
1633struct alias_link *
1634FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1635 struct in_addr dst_addr,
1636 u_short src_port,
1637 u_short dst_port,
1638 u_char proto,
1639 int create)
1640{
1641 int link_type;
1642 struct alias_link *lnk;
1643
1644 LIBALIAS_LOCK_ASSERT(la);
1645 switch (proto) {
1646 case IPPROTO_UDP:
1647 link_type = LINK_UDP;
1648 break;
1649 case IPPROTO_TCP:
1650 link_type = LINK_TCP;
1651 break;
1652 default:
1653 return (NULL);
1654 break;
1655 }
1656
1657 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1658
1659 if (lnk == NULL && create) {
1660 struct in_addr alias_addr;
1661
1662 alias_addr = FindAliasAddress(la, src_addr);
1663 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1664 src_port, dst_port, GET_ALIAS_PORT,
1665 link_type);
1666 }
1667 return (lnk);
1668}
1669
1670
1671struct alias_link *
1672AddPptp(struct libalias *la, struct in_addr src_addr,
1673 struct in_addr dst_addr,
1674 struct in_addr alias_addr,
1675 u_int16_t src_call_id)
1676{
1677 struct alias_link *lnk;
1678
1679 LIBALIAS_LOCK_ASSERT(la);
1680 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1681 src_call_id, 0, GET_ALIAS_PORT,
1682 LINK_PPTP);
1683
1684 return (lnk);
1685}
1686
1687
1688struct alias_link *
1689FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1690 struct in_addr dst_addr,
1691 u_int16_t src_call_id)
1692{
1693 u_int i;
1694 struct alias_link *lnk;
1695
1696 LIBALIAS_LOCK_ASSERT(la);
1697 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1698 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1699 if (lnk->link_type == LINK_PPTP &&
1700 lnk->src_addr.s_addr == src_addr.s_addr &&
1701 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1702 lnk->src_port == src_call_id)
1703 break;
1704
1705 return (lnk);
1706}
1707
1708
1709struct alias_link *
1710FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1711 struct in_addr dst_addr,
1712 u_int16_t dst_call_id)
1713{
1714 u_int i;
1715 struct alias_link *lnk;
1716
1717 LIBALIAS_LOCK_ASSERT(la);
1718 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1719 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1720 if (lnk->link_type == LINK_PPTP &&
1721 lnk->src_addr.s_addr == src_addr.s_addr &&
1722 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1723 lnk->dst_port == dst_call_id)
1724 break;
1725
1726 return (lnk);
1727}
1728
1729
1730struct alias_link *
1731FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1732 struct in_addr alias_addr,
1733 u_int16_t dst_call_id)
1734{
1735 u_int i;
1736 struct alias_link *lnk;
1737
1738 LIBALIAS_LOCK_ASSERT(la);
1739 i = StartPointIn(alias_addr, 0, LINK_PPTP);
1740 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1741 if (lnk->link_type == LINK_PPTP &&
1742 lnk->dst_addr.s_addr == dst_addr.s_addr &&
1743 lnk->alias_addr.s_addr == alias_addr.s_addr &&
1744 lnk->dst_port == dst_call_id)
1745 break;
1746
1747 return (lnk);
1748}
1749
1750
1751struct alias_link *
1752FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1753 struct in_addr alias_addr,
1754 u_int16_t alias_call_id)
1755{
1756 struct alias_link *lnk;
1757
1758 LIBALIAS_LOCK_ASSERT(la);
1759 lnk = FindLinkIn(la, dst_addr, alias_addr,
1760 0 /* any */ , alias_call_id,
1761 LINK_PPTP, 0);
1762
1763
1764 return (lnk);
1765}
1766
1767
1768struct alias_link *
1769FindRtspOut(struct libalias *la, struct in_addr src_addr,
1770 struct in_addr dst_addr,
1771 u_short src_port,
1772 u_short alias_port,
1773 u_char proto)
1774{
1775 int link_type;
1776 struct alias_link *lnk;
1777
1778 LIBALIAS_LOCK_ASSERT(la);
1779 switch (proto) {
1780 case IPPROTO_UDP:
1781 link_type = LINK_UDP;
1782 break;
1783 case IPPROTO_TCP:
1784 link_type = LINK_TCP;
1785 break;
1786 default:
1787 return (NULL);
1788 break;
1789 }
1790
1791 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1792
1793 if (lnk == NULL) {
1794 struct in_addr alias_addr;
1795
1796 alias_addr = FindAliasAddress(la, src_addr);
1797 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1798 src_port, 0, alias_port,
1799 link_type);
1800 }
1801 return (lnk);
1802}
1803
1804
1805struct in_addr
1806FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1807{
1808 struct alias_link *lnk;
1809
1810 LIBALIAS_LOCK_ASSERT(la);
1811 lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1812 0, 0, LINK_ADDR, 0);
1813 if (lnk == NULL) {
1814 la->newDefaultLink = 1;
1815 if (la->targetAddress.s_addr == INADDR_ANY)
1816 return (alias_addr);
1817 else if (la->targetAddress.s_addr == INADDR_NONE)
1818 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1819 la->aliasAddress : alias_addr;
1820 else
1821 return (la->targetAddress);
1822 } else {
1823 if (lnk->server != NULL) { /* LSNAT link */
1824 struct in_addr src_addr;
1825
1826 src_addr = lnk->server->addr;
1827 lnk->server = lnk->server->next;
1828 return (src_addr);
1829 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1830 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1831 la->aliasAddress : alias_addr;
1832 else
1833 return (lnk->src_addr);
1834 }
1835}
1836
1837
1838struct in_addr
1839FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1840{
1841 struct alias_link *lnk;
1842
1843 LIBALIAS_LOCK_ASSERT(la);
1844 lnk = FindLinkOut(la, original_addr, la->nullAddress,
1845 0, 0, LINK_ADDR, 0);
1846 if (lnk == NULL) {
1847 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1848 la->aliasAddress : original_addr;
1849 } else {
1850 if (lnk->alias_addr.s_addr == INADDR_ANY)
1851 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1852 la->aliasAddress : original_addr;
1853 else
1854 return (lnk->alias_addr);
1855 }
1856}
1857
1858
1859/* External routines for getting or changing link data
1860 (external to alias_db.c, but internal to alias*.c)
1861
1862 SetFragmentData(), GetFragmentData()
1863 SetFragmentPtr(), GetFragmentPtr()
1864 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1865 GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1866 GetOriginalPort(), GetAliasPort()
1867 SetAckModified(), GetAckModified()
1868 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1869 SetProtocolFlags(), GetProtocolFlags()
1870 SetDestCallId()
1871*/
1872
1873
1874void
1875SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1876{
1877 lnk->data.frag_addr = src_addr;
1878}
1879
1880
1881void
1882GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1883{
1884 *src_addr = lnk->data.frag_addr;
1885}
1886
1887
1888void
1889SetFragmentPtr(struct alias_link *lnk, char *fptr)
1890{
1891 lnk->data.frag_ptr = fptr;
1892}
1893
1894
1895void
1896GetFragmentPtr(struct alias_link *lnk, char **fptr)
1897{
1898 *fptr = lnk->data.frag_ptr;
1899}
1900
1901
1902void
1903SetStateIn(struct alias_link *lnk, int state)
1904{
1905 /* TCP input state */
1906 switch (state) {
1907 case ALIAS_TCP_STATE_DISCONNECTED:
1908 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1909 lnk->expire_time = TCP_EXPIRE_DEAD;
1910 else
1911 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1912 break;
1913 case ALIAS_TCP_STATE_CONNECTED:
1914 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1915 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1916 break;
1917 default:
1918#ifdef _KERNEL
1919 panic("libalias:SetStateIn() unknown state");
1920#else
1921 abort();
1922#endif
1923 }
1924 lnk->data.tcp->state.in = state;
1925}
1926
1927
1928void
1929SetStateOut(struct alias_link *lnk, int state)
1930{
1931 /* TCP output state */
1932 switch (state) {
1933 case ALIAS_TCP_STATE_DISCONNECTED:
1934 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1935 lnk->expire_time = TCP_EXPIRE_DEAD;
1936 else
1937 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1938 break;
1939 case ALIAS_TCP_STATE_CONNECTED:
1940 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1941 lnk->expire_time = TCP_EXPIRE_CONNECTED;
1942 break;
1943 default:
1944#ifdef _KERNEL
1945 panic("libalias:SetStateOut() unknown state");
1946#else
1947 abort();
1948#endif
1949 }
1950 lnk->data.tcp->state.out = state;
1951}
1952
1953
1954int
1955GetStateIn(struct alias_link *lnk)
1956{
1957 /* TCP input state */
1958 return (lnk->data.tcp->state.in);
1959}
1960
1961
1962int
1963GetStateOut(struct alias_link *lnk)
1964{
1965 /* TCP output state */
1966 return (lnk->data.tcp->state.out);
1967}
1968
1969
1970struct in_addr
1971GetOriginalAddress(struct alias_link *lnk)
1972{
1973 if (lnk->src_addr.s_addr == INADDR_ANY)
1974 return (lnk->la->aliasAddress);
1975 else
1976 return (lnk->src_addr);
1977}
1978
1979
1980struct in_addr
1981GetDestAddress(struct alias_link *lnk)
1982{
1983 return (lnk->dst_addr);
1984}
1985
1986
1987struct in_addr
1988GetAliasAddress(struct alias_link *lnk)
1989{
1990 if (lnk->alias_addr.s_addr == INADDR_ANY)
1991 return (lnk->la->aliasAddress);
1992 else
1993 return (lnk->alias_addr);
1994}
1995
1996
1997struct in_addr
1998GetDefaultAliasAddress(struct libalias *la)
1999{
2000
2001 LIBALIAS_LOCK_ASSERT(la);
2002 return (la->aliasAddress);
2003}
2004
2005
2006void
2007SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
2008{
2009
2010 LIBALIAS_LOCK_ASSERT(la);
2011 la->aliasAddress = alias_addr;
2012}
2013
2014
2015u_short
2016GetOriginalPort(struct alias_link *lnk)
2017{
2018 return (lnk->src_port);
2019}
2020
2021
2022u_short
2023GetAliasPort(struct alias_link *lnk)
2024{
2025 return (lnk->alias_port);
2026}
2027
2028#ifndef NO_FW_PUNCH
2029static u_short
2030GetDestPort(struct alias_link *lnk)
2031{
2032 return (lnk->dst_port);
2033}
2034
2035#endif
2036
2037void
2038SetAckModified(struct alias_link *lnk)
2039{
2040/* Indicate that ACK numbers have been modified in a TCP connection */
2041 lnk->data.tcp->state.ack_modified = 1;
2042}
2043
2044
2045struct in_addr
2046GetProxyAddress(struct alias_link *lnk)
2047{
2048 return (lnk->proxy_addr);
2049}
2050
2051
2052void
2053SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
2054{
2055 lnk->proxy_addr = addr;
2056}
2057
2058
2059u_short
2060GetProxyPort(struct alias_link *lnk)
2061{
2062 return (lnk->proxy_port);
2063}
2064
2065
2066void
2067SetProxyPort(struct alias_link *lnk, u_short port)
2068{
2069 lnk->proxy_port = port;
2070}
2071
2072
2073int
2074GetAckModified(struct alias_link *lnk)
2075{
2076/* See if ACK numbers have been modified */
2077 return (lnk->data.tcp->state.ack_modified);
2078}
2079
2080
2081int
2082GetDeltaAckIn(struct ip *pip, struct alias_link *lnk)
2083{
2084/*
2085Find out how much the ACK number has been altered for an incoming
2086TCP packet. To do this, a circular list of ACK numbers where the TCP
2087packet size was altered is searched.
2088*/
2089
2090 int i;
2091 struct tcphdr *tc;
2092 int delta, ack_diff_min;
2093 u_long ack;
2094
2095 tc = ip_next(pip);
2096 ack = tc->th_ack;
2097
2098 delta = 0;
2099 ack_diff_min = -1;
2100 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2101 struct ack_data_record x;
2102
2103 x = lnk->data.tcp->ack[i];
2104 if (x.active == 1) {
2105 int ack_diff;
2106
2107 ack_diff = SeqDiff(x.ack_new, ack);
2108 if (ack_diff >= 0) {
2109 if (ack_diff_min >= 0) {
2110 if (ack_diff < ack_diff_min) {
2111 delta = x.delta;
2112 ack_diff_min = ack_diff;
2113 }
2114 } else {
2115 delta = x.delta;
2116 ack_diff_min = ack_diff;
2117 }
2118 }
2119 }
2120 }
2121 return (delta);
2122}
2123
2124
2125int
2126GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
2127{
2128/*
2129Find out how much the sequence number has been altered for an outgoing
2130TCP packet. To do this, a circular list of ACK numbers where the TCP
2131packet size was altered is searched.
2132*/
2133
2134 int i;
2135 struct tcphdr *tc;
2136 int delta, seq_diff_min;
2137 u_long seq;
2138
2139 tc = ip_next(pip);
2140 seq = tc->th_seq;
2141
2142 delta = 0;
2143 seq_diff_min = -1;
2144 for (i = 0; i < N_LINK_TCP_DATA; i++) {
2145 struct ack_data_record x;
2146
2147 x = lnk->data.tcp->ack[i];
2148 if (x.active == 1) {
2149 int seq_diff;
2150
2151 seq_diff = SeqDiff(x.ack_old, seq);
2152 if (seq_diff >= 0) {
2153 if (seq_diff_min >= 0) {
2154 if (seq_diff < seq_diff_min) {
2155 delta = x.delta;
2156 seq_diff_min = seq_diff;
2157 }
2158 } else {
2159 delta = x.delta;
2160 seq_diff_min = seq_diff;
2161 }
2162 }
2163 }
2164 }
2165 return (delta);
2166}
2167
2168
2169void
2170AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
2171{
2172/*
2173When a TCP packet has been altered in length, save this
2174information in a circular list. If enough packets have
2175been altered, then this list will begin to overwrite itself.
2176*/
2177
2178 struct tcphdr *tc;
2179 struct ack_data_record x;
2180 int hlen, tlen, dlen;
2181 int i;
2182
2183 tc = ip_next(pip);
2184
2185 hlen = (pip->ip_hl + tc->th_off) << 2;
2186 tlen = ntohs(pip->ip_len);
2187 dlen = tlen - hlen;
2188
2189 x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2190 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2191 x.delta = delta;
2192 x.active = 1;
2193
2194 i = lnk->data.tcp->state.index;
2195 lnk->data.tcp->ack[i] = x;
2196
2197 i++;
2198 if (i == N_LINK_TCP_DATA)
2199 lnk->data.tcp->state.index = 0;
2200 else
2201 lnk->data.tcp->state.index = i;
2202}
2203
2204void
2205SetExpire(struct alias_link *lnk, int expire)
2206{
2207 if (expire == 0) {
2208 lnk->flags &= ~LINK_PERMANENT;
2209 DeleteLink(lnk);
2210 } else if (expire == -1) {
2211 lnk->flags |= LINK_PERMANENT;
2212 } else if (expire > 0) {
2213 lnk->expire_time = expire;
2214 } else {
2215#ifdef LIBALIAS_DEBUG
2216 fprintf(stderr, "PacketAlias/SetExpire(): ");
2217 fprintf(stderr, "error in expire parameter\n");
2218#endif
2219 }
2220}
2221
2222void
2223ClearCheckNewLink(struct libalias *la)
2224{
2225
2226 LIBALIAS_LOCK_ASSERT(la);
2227 la->newDefaultLink = 0;
2228}
2229
2230void
2231SetProtocolFlags(struct alias_link *lnk, int pflags)
2232{
2233
2234 lnk->pflags = pflags;;
2235}
2236
2237int
2238GetProtocolFlags(struct alias_link *lnk)
2239{
2240
2241 return (lnk->pflags);
2242}
2243
2244void
2245SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2246{
2247 struct libalias *la = lnk->la;
2248
2249 LIBALIAS_LOCK_ASSERT(la);
2250 la->deleteAllLinks = 1;
2251 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2252 lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2253 la->deleteAllLinks = 0;
2254}
2255
2256
2257/* Miscellaneous Functions
2258
2259 HouseKeeping()
2260 InitPacketAliasLog()
2261 UninitPacketAliasLog()
2262*/
2263
2264/*
2265 Whenever an outgoing or incoming packet is handled, HouseKeeping()
2266 is called to find and remove timed-out aliasing links. Logic exists
2267 to sweep through the entire table and linked list structure
2268 every 60 seconds.
2269
2270 (prototype in alias_local.h)
2271*/
2272
2273void
2274HouseKeeping(struct libalias *la)
2275{
2276 int i, n;
2277#ifndef VBOX
2278#ifndef _KERNEL
2279 struct timeval tv;
2280 struct timezone tz;
2281#endif
2282
2283 LIBALIAS_LOCK_ASSERT(la);
2284 /*
2285 * Save system time (seconds) in global variable timeStamp for use
2286 * by other functions. This is done so as not to unnecessarily
2287 * waste timeline by making system calls.
2288 */
2289#ifdef _KERNEL
2290 la->timeStamp = time_uptime;
2291#else
2292 gettimeofday(&tv, &tz);
2293 la->timeStamp = tv.tv_sec;
2294#endif
2295#else /* !VBOX */
2296 LIBALIAS_LOCK_ASSERT(la);
2297 la->timeStamp = la->curtime;
2298#endif
2299
2300 /* Compute number of spokes (output table link chains) to cover */
2301#ifndef VBOX
2302 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2303#else
2304 n = LINK_TABLE_OUT_SIZE * ((la->timeStamp - la->lastCleanupTime)/1000);
2305#endif
2306 n /= ALIAS_CLEANUP_INTERVAL_SECS;
2307
2308 /* Handle different cases */
2309 if (n > 0) {
2310 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2311 n = ALIAS_CLEANUP_MAX_SPOKES;
2312 la->lastCleanupTime = la->timeStamp;
2313 for (i = 0; i < n; i++)
2314 IncrementalCleanup(la);
2315 } else if (n < 0) {
2316#ifdef LIBALIAS_DEBUG
2317 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2318 fprintf(stderr, "something unexpected in time values\n");
2319#endif
2320 la->lastCleanupTime = la->timeStamp;
2321 }
2322}
2323
2324/* Init the log file and enable logging */
2325static int
2326InitPacketAliasLog(struct libalias *la)
2327{
2328
2329 LIBALIAS_LOCK_ASSERT(la);
2330 if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2331#ifndef VBOX
2332#ifdef _KERNEL
2333 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2334 ;
2335#else
2336 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2337 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2338#endif
2339 else
2340 return (ENOMEM); /* log initialization failed */
2341#else
2342 Log2(("NAT: PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"));
2343 la->logDesc = (void *)1; /* XXX: in vbox we don't use this param */
2344#endif
2345 la->packetAliasMode |= PKT_ALIAS_LOG;
2346 }
2347
2348 return (1);
2349}
2350
2351/* Close the log-file and disable logging. */
2352static void
2353UninitPacketAliasLog(struct libalias *la)
2354{
2355
2356 LIBALIAS_LOCK_ASSERT(la);
2357 if (la->logDesc) {
2358#ifndef VBOX
2359#ifdef _KERNEL
2360 free(la->logDesc);
2361#else
2362 fclose(la->logDesc);
2363#endif
2364#endif /* !VBOX */
2365 la->logDesc = NULL;
2366 }
2367 la->packetAliasMode &= ~PKT_ALIAS_LOG;
2368}
2369
2370/* Outside world interfaces
2371
2372-- "outside world" means other than alias*.c routines --
2373
2374 PacketAliasRedirectPort()
2375 PacketAliasAddServer()
2376 PacketAliasRedirectProto()
2377 PacketAliasRedirectAddr()
2378 PacketAliasRedirectDynamic()
2379 PacketAliasRedirectDelete()
2380 PacketAliasSetAddress()
2381 PacketAliasInit()
2382 PacketAliasUninit()
2383 PacketAliasSetMode()
2384
2385(prototypes in alias.h)
2386*/
2387
2388/* Redirection from a specific public addr:port to a
2389 private addr:port */
2390struct alias_link *
2391LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2392 struct in_addr dst_addr, u_short dst_port,
2393 struct in_addr alias_addr, u_short alias_port,
2394 u_char proto)
2395{
2396 int link_type;
2397 struct alias_link *lnk;
2398
2399 LIBALIAS_LOCK(la);
2400 switch (proto) {
2401 case IPPROTO_UDP:
2402 link_type = LINK_UDP;
2403 break;
2404 case IPPROTO_TCP:
2405 link_type = LINK_TCP;
2406 break;
2407 default:
2408#ifdef LIBALIAS_DEBUG
2409 fprintf(stderr, "PacketAliasRedirectPort(): ");
2410 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2411#endif
2412 lnk = NULL;
2413 goto getout;
2414 }
2415
2416 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2417 src_port, dst_port, alias_port,
2418 link_type);
2419
2420 if (lnk != NULL) {
2421 lnk->flags |= LINK_PERMANENT;
2422 }
2423#ifdef LIBALIAS_DEBUG
2424 else {
2425 fprintf(stderr, "PacketAliasRedirectPort(): "
2426 "call to AddLink() failed\n");
2427 }
2428#endif
2429
2430getout:
2431 LIBALIAS_UNLOCK(la);
2432 return (lnk);
2433}
2434
2435/* Add server to the pool of servers */
2436int
2437LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2438{
2439 struct server *server;
2440 int res;
2441
2442 LIBALIAS_LOCK(la);
2443 (void)la;
2444
2445 server = malloc(sizeof(struct server));
2446
2447 if (server != NULL) {
2448 struct server *head;
2449
2450 server->addr = addr;
2451 server->port = port;
2452
2453 head = lnk->server;
2454 if (head == NULL)
2455 server->next = server;
2456 else {
2457 struct server *s;
2458
2459 for (s = head; s->next != head; s = s->next);
2460 s->next = server;
2461 server->next = head;
2462 }
2463 lnk->server = server;
2464 res = 0;
2465 } else
2466 res = -1;
2467
2468 LIBALIAS_UNLOCK(la);
2469 return (res);
2470}
2471
2472/* Redirect packets of a given IP protocol from a specific
2473 public address to a private address */
2474struct alias_link *
2475LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2476 struct in_addr dst_addr,
2477 struct in_addr alias_addr,
2478 u_char proto)
2479{
2480 struct alias_link *lnk;
2481
2482 LIBALIAS_LOCK(la);
2483 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2484 NO_SRC_PORT, NO_DEST_PORT, 0,
2485 proto);
2486
2487 if (lnk != NULL) {
2488 lnk->flags |= LINK_PERMANENT;
2489 }
2490#ifdef LIBALIAS_DEBUG
2491 else {
2492 fprintf(stderr, "PacketAliasRedirectProto(): "
2493 "call to AddLink() failed\n");
2494 }
2495#endif
2496
2497 LIBALIAS_UNLOCK(la);
2498 return (lnk);
2499}
2500
2501/* Static address translation */
2502struct alias_link *
2503LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2504 struct in_addr alias_addr)
2505{
2506 struct alias_link *lnk;
2507
2508 LIBALIAS_LOCK(la);
2509 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2510 0, 0, 0,
2511 LINK_ADDR);
2512
2513 if (lnk != NULL) {
2514 lnk->flags |= LINK_PERMANENT;
2515 }
2516#ifdef LIBALIAS_DEBUG
2517 else {
2518 fprintf(stderr, "PacketAliasRedirectAddr(): "
2519 "call to AddLink() failed\n");
2520 }
2521#endif
2522
2523 LIBALIAS_UNLOCK(la);
2524 return (lnk);
2525}
2526
2527
2528/* Mark the aliasing link dynamic */
2529int
2530LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2531{
2532 int res;
2533
2534 LIBALIAS_LOCK(la);
2535 (void)la;
2536
2537 if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2538 res = -1;
2539 else {
2540 lnk->flags &= ~LINK_PERMANENT;
2541 res = 0;
2542 }
2543 LIBALIAS_UNLOCK(la);
2544 return (res);
2545}
2546
2547
2548void
2549LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2550{
2551/* This is a dangerous function to put in the API,
2552 because an invalid pointer can crash the program. */
2553
2554 LIBALIAS_LOCK(la);
2555 la->deleteAllLinks = 1;
2556 DeleteLink(lnk);
2557 la->deleteAllLinks = 0;
2558 LIBALIAS_UNLOCK(la);
2559}
2560
2561
2562void
2563LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2564{
2565
2566 LIBALIAS_LOCK(la);
2567 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2568 && la->aliasAddress.s_addr != addr.s_addr)
2569 CleanupAliasData(la);
2570
2571 la->aliasAddress = addr;
2572 LIBALIAS_UNLOCK(la);
2573}
2574
2575
2576void
2577LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2578{
2579
2580 LIBALIAS_LOCK(la);
2581 la->targetAddress = target_addr;
2582 LIBALIAS_UNLOCK(la);
2583}
2584
2585#ifndef VBOX
2586static void
2587finishoff(void)
2588{
2589
2590 while (!LIST_EMPTY(&instancehead))
2591 LibAliasUninit(LIST_FIRST(&instancehead));
2592}
2593#endif
2594
2595struct libalias *
2596#ifndef VBOX
2597LibAliasInit(struct libalias *la)
2598#else
2599LibAliasInit(PNATState pData, struct libalias *la)
2600#endif
2601{
2602 int i;
2603#ifndef VBOX
2604#ifndef _KERNEL
2605 struct timeval tv;
2606 struct timezone tz;
2607#endif
2608#endif /* !VBOX */
2609
2610 if (la == NULL) {
2611 la = calloc(sizeof *la, 1);
2612 if (la == NULL)
2613 return (la);
2614
2615#ifndef VBOX
2616#ifndef _KERNEL /* kernel cleans up on module unload */
2617 if (LIST_EMPTY(&instancehead))
2618 atexit(finishoff);
2619#endif
2620#endif /*!VBOX*/
2621 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2622
2623#ifndef VBOX
2624#ifdef _KERNEL
2625 la->timeStamp = time_uptime;
2626 la->lastCleanupTime = time_uptime;
2627#else
2628 gettimeofday(&tv, &tz);
2629 la->timeStamp = tv.tv_sec;
2630 la->lastCleanupTime = tv.tv_sec;
2631#endif
2632#else /* !VBOX */
2633 la->pData = pData;
2634 la->timeStamp = curtime;
2635 la->lastCleanupTime = curtime;
2636#endif /* VBOX */
2637
2638 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2639 LIST_INIT(&la->linkTableOut[i]);
2640 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2641 LIST_INIT(&la->linkTableIn[i]);
2642 LIBALIAS_LOCK_INIT(la);
2643 LIBALIAS_LOCK(la);
2644 } else {
2645 LIBALIAS_LOCK(la);
2646 la->deleteAllLinks = 1;
2647 CleanupAliasData(la);
2648 la->deleteAllLinks = 0;
2649 }
2650
2651 la->aliasAddress.s_addr = INADDR_ANY;
2652 la->targetAddress.s_addr = INADDR_ANY;
2653
2654 la->icmpLinkCount = 0;
2655 la->udpLinkCount = 0;
2656 la->tcpLinkCount = 0;
2657 la->pptpLinkCount = 0;
2658 la->protoLinkCount = 0;
2659 la->fragmentIdLinkCount = 0;
2660 la->fragmentPtrLinkCount = 0;
2661 la->sockCount = 0;
2662
2663 la->cleanupIndex = 0;
2664
2665 la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2666#ifndef NO_USE_SOCKETS
2667 | PKT_ALIAS_USE_SOCKETS
2668#endif
2669 | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2670#ifndef NO_FW_PUNCH
2671 la->fireWallFD = -1;
2672#endif
2673#ifndef _KERNEL
2674 LibAliasRefreshModules();
2675#endif
2676 LIBALIAS_UNLOCK(la);
2677 return (la);
2678}
2679
2680void
2681LibAliasUninit(struct libalias *la)
2682{
2683
2684 LIBALIAS_LOCK(la);
2685 la->deleteAllLinks = 1;
2686 CleanupAliasData(la);
2687 la->deleteAllLinks = 0;
2688 UninitPacketAliasLog(la);
2689#ifndef NO_FW_PUNCH
2690 UninitPunchFW(la);
2691#endif
2692 LIST_REMOVE(la, instancelist);
2693 LIBALIAS_UNLOCK(la);
2694 LIBALIAS_LOCK_DESTROY(la);
2695 free(la);
2696}
2697
2698/* Change mode for some operations */
2699unsigned int
2700LibAliasSetMode(
2701 struct libalias *la,
2702 unsigned int flags, /* Which state to bring flags to */
2703 unsigned int mask /* Mask of which flags to affect (use 0 to
2704 * do a probe for flag values) */
2705)
2706{
2707 int res = -1;
2708
2709 LIBALIAS_LOCK(la);
2710/* Enable logging? */
2711 if (flags & mask & PKT_ALIAS_LOG) {
2712 /* Do the enable */
2713 if (InitPacketAliasLog(la) == ENOMEM)
2714 goto getout;
2715 } else
2716/* _Disable_ logging? */
2717 if (~flags & mask & PKT_ALIAS_LOG) {
2718 UninitPacketAliasLog(la);
2719 }
2720#ifndef NO_FW_PUNCH
2721/* Start punching holes in the firewall? */
2722 if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2723 InitPunchFW(la);
2724 } else
2725/* Stop punching holes in the firewall? */
2726 if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2727 UninitPunchFW(la);
2728 }
2729#endif
2730
2731/* Other flags can be set/cleared without special action */
2732 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2733 res = la->packetAliasMode;
2734getout:
2735 LIBALIAS_UNLOCK(la);
2736 return (res);
2737}
2738
2739
2740int
2741LibAliasCheckNewLink(struct libalias *la)
2742{
2743 int res;
2744
2745 LIBALIAS_LOCK(la);
2746 res = la->newDefaultLink;
2747 LIBALIAS_UNLOCK(la);
2748 return (res);
2749}
2750
2751
2752#ifndef NO_FW_PUNCH
2753
2754/*****************
2755 Code to support firewall punching. This shouldn't really be in this
2756 file, but making variables global is evil too.
2757 ****************/
2758
2759/* Firewall include files */
2760#include <net/if.h>
2761#include <netinet/ip_fw.h>
2762#include <string.h>
2763#include <err.h>
2764
2765/*
2766 * helper function, updates the pointer to cmd with the length
2767 * of the current command, and also cleans up the first word of
2768 * the new command in case it has been clobbered before.
2769 */
2770static ipfw_insn *
2771next_cmd(ipfw_insn * cmd)
2772{
2773 cmd += F_LEN(cmd);
2774 bzero(cmd, sizeof(*cmd));
2775 return (cmd);
2776}
2777
2778/*
2779 * A function to fill simple commands of size 1.
2780 * Existing flags are preserved.
2781 */
2782static ipfw_insn *
2783fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2784 int flags, u_int16_t arg)
2785{
2786 cmd->opcode = opcode;
2787 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2788 cmd->arg1 = arg;
2789 return next_cmd(cmd);
2790}
2791
2792static ipfw_insn *
2793fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2794{
2795 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2796
2797 cmd->addr.s_addr = addr;
2798 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2799}
2800
2801static ipfw_insn *
2802fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2803{
2804 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2805
2806 cmd->ports[0] = cmd->ports[1] = port;
2807 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2808}
2809
2810static int
2811fill_rule(void *buf, int bufsize, int rulenum,
2812 enum ipfw_opcodes action, int proto,
2813 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2814{
2815 struct ip_fw *rule = (struct ip_fw *)buf;
2816 ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2817
2818 bzero(buf, bufsize);
2819 rule->rulenum = rulenum;
2820
2821 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2822 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2823 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2824 cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2825 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2826
2827 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2828 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2829
2830 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2831
2832 return ((char *)cmd - (char *)buf);
2833}
2834
2835static void ClearAllFWHoles(struct libalias *la);
2836
2837
2838#define fw_setfield(la, field, num) \
2839do { \
2840 (field)[(num) - la->fireWallBaseNum] = 1; \
2841} /*lint -save -e717 */ while(0)/* lint -restore */
2842
2843#define fw_clrfield(la, field, num) \
2844do { \
2845 (field)[(num) - la->fireWallBaseNum] = 0; \
2846} /*lint -save -e717 */ while(0)/* lint -restore */
2847
2848#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2849
2850static void
2851InitPunchFW(struct libalias *la)
2852{
2853
2854 LIBALIAS_LOCK_ASSERT(la);
2855 la->fireWallField = malloc(la->fireWallNumNums);
2856 if (la->fireWallField) {
2857 memset(la->fireWallField, 0, la->fireWallNumNums);
2858 if (la->fireWallFD < 0) {
2859 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2860 }
2861 ClearAllFWHoles(la);
2862 la->fireWallActiveNum = la->fireWallBaseNum;
2863 }
2864}
2865
2866static void
2867UninitPunchFW(struct libalias *la)
2868{
2869
2870 LIBALIAS_LOCK_ASSERT(la);
2871 ClearAllFWHoles(la);
2872 if (la->fireWallFD >= 0)
2873 close(la->fireWallFD);
2874 la->fireWallFD = -1;
2875 if (la->fireWallField)
2876 free(la->fireWallField);
2877 la->fireWallField = NULL;
2878 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2879}
2880
2881/* Make a certain link go through the firewall */
2882void
2883PunchFWHole(struct alias_link *lnk)
2884{
2885 struct libalias *la;
2886 int r; /* Result code */
2887 struct ip_fw rule; /* On-the-fly built rule */
2888 int fwhole; /* Where to punch hole */
2889
2890 LIBALIAS_LOCK_ASSERT(la);
2891 la = lnk->la;
2892
2893/* Don't do anything unless we are asked to */
2894 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2895 la->fireWallFD < 0 ||
2896 lnk->link_type != LINK_TCP)
2897 return;
2898
2899 memset(&rule, 0, sizeof rule);
2900
2901/** Build rule **/
2902
2903 /* Find empty slot */
2904 for (fwhole = la->fireWallActiveNum;
2905 fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2906 fw_tstfield(la, la->fireWallField, fwhole);
2907 fwhole++);
2908 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2909 for (fwhole = la->fireWallBaseNum;
2910 fwhole < la->fireWallActiveNum &&
2911 fw_tstfield(la, la->fireWallField, fwhole);
2912 fwhole++);
2913 if (fwhole == la->fireWallActiveNum) {
2914 /* No rule point empty - we can't punch more holes. */
2915 la->fireWallActiveNum = la->fireWallBaseNum;
2916#ifdef LIBALIAS_DEBUG
2917 fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2918#endif
2919 return;
2920 }
2921 }
2922 /* Start next search at next position */
2923 la->fireWallActiveNum = fwhole + 1;
2924
2925 /*
2926 * generate two rules of the form
2927 *
2928 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2929 * accept tcp from DAddr DPort to OAddr OPort
2930 */
2931 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2932 u_int32_t rulebuf[255];
2933 int i;
2934
2935 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2936 O_ACCEPT, IPPROTO_TCP,
2937 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2938 GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2939 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2940 if (r)
2941 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2942
2943 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2944 O_ACCEPT, IPPROTO_TCP,
2945 GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2946 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2947 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2948 if (r)
2949 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2950 }
2951
2952/* Indicate hole applied */
2953 lnk->data.tcp->fwhole = fwhole;
2954 fw_setfield(la, la->fireWallField, fwhole);
2955}
2956
2957/* Remove a hole in a firewall associated with a particular alias
2958 lnk. Calling this too often is harmless. */
2959static void
2960ClearFWHole(struct alias_link *lnk)
2961{
2962 struct libalias *la;
2963
2964 LIBALIAS_LOCK_ASSERT(la);
2965 la = lnk->la;
2966 if (lnk->link_type == LINK_TCP) {
2967 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall
2968 * hole? */
2969 struct ip_fw rule;
2970
2971 if (fwhole < 0)
2972 return;
2973
2974 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */
2975 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2976 &fwhole, sizeof fwhole));
2977 fw_clrfield(la, la->fireWallField, fwhole);
2978 lnk->data.tcp->fwhole = -1;
2979 }
2980}
2981
2982/* Clear out the entire range dedicated to firewall holes. */
2983static void
2984ClearAllFWHoles(struct libalias *la)
2985{
2986 struct ip_fw rule; /* On-the-fly built rule */
2987 int i;
2988
2989 LIBALIAS_LOCK_ASSERT(la);
2990 if (la->fireWallFD < 0)
2991 return;
2992
2993 memset(&rule, 0, sizeof rule);
2994 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2995 int r = i;
2996
2997 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2998 }
2999 /* XXX: third arg correct here ? /phk */
3000 memset(la->fireWallField, 0, la->fireWallNumNums);
3001}
3002
3003#endif
3004
3005void
3006LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
3007{
3008
3009 LIBALIAS_LOCK(la);
3010#ifndef NO_FW_PUNCH
3011 la->fireWallBaseNum = base;
3012 la->fireWallNumNums = num;
3013#endif
3014 LIBALIAS_UNLOCK(la);
3015}
3016
3017void
3018LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
3019{
3020
3021 LIBALIAS_LOCK(la);
3022 la->skinnyPort = port;
3023 LIBALIAS_UNLOCK(la);
3024}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette