VirtualBox

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

最後變更 在這個檔案從38905是 38345,由 vboxsync 提交於 14 年 前

NAT: logging. (vbox/#9346).

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

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