VirtualBox

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

Last change on this file since 21718 was 21718, checked in by vboxsync, 16 years ago

NAT: timing to Slirp's terms

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