VirtualBox

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

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

NAT/libalias: disabling libalias socket managment

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