VirtualBox

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

Last change on this file since 40583 was 40583, checked in by vboxsync, 13 years ago

NAT: verification that sockets always stay on right queues.

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

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