VirtualBox

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

最後變更 在這個檔案從25119是 25119,由 vboxsync 提交於 15 年 前

NAT: typo.

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

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