VirtualBox

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

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

NAT:libalias: tabs.

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

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