VirtualBox

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

Last change on this file since 46260 was 41855, checked in by vboxsync, 13 years ago

NAT: collapsing EAGAIN,EWOULDBLOCK,EINPROGRESS conditions to soIgnorableErrorCode inline function.

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

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