VirtualBox

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

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

NAT: warnings [-Wunused-macros]

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