VirtualBox

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

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

Devices: whitespace cleanup

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

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