VirtualBox

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

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

NAT: #7342: debug assertion in sofree() triggered by ftp connections.
Do a minimal stop-gap fix by compiling libalias with NO_USE_SOCKETS.
Two wrongs don't make a right, but this at least averts harm.

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

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