VBoxNetLwipNAT.cpp revision 1a54d69e735ad5a219b09a52cf9e1d4e57cf9f29
/* $Id$ */
/** @file
* VBoxNetNAT - NAT Service for connecting to IntNet.
*/
/*
* Copyright (C) 2009 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "winutils.h"
#include <iprt/initterm.h>
#ifndef RT_OS_WINDOWS
#endif
#include <iprt/semaphore.h>
#define LOG_GROUP LOG_GROUP_NAT_SERVICE
#include <VBox/intnetinline.h>
#ifndef RT_OS_WINDOWS
#endif
#include <vector>
#include <string>
#include "../NetLib/VBoxNetLib.h"
#include "../NetLib/VBoxNetBaseService.h"
#include "VBoxLwipCore.h"
extern "C"
{
/* bunch of LWIP headers */
#ifdef LWIP_SOCKET
# define LWIP_SOCKET 0
#endif
#include "lwip/tcp_impl.h"
#include "proxytest.h"
#include "pxremap.h"
#include "portfwd.h"
}
#include "../NetLib/VBoxPortForwardString.h"
static RTGETOPTDEF g_aGetOptDef[] =
{
};
typedef struct NATSEVICEPORTFORWARDRULE
{
struct ip4address2off
{
struct sockaddr_in addr;
};
class PortForwardListener;
class VBoxNetLwipNAT: public VBoxNetBaseService
{
friend class PortForwardListener;
public:
virtual ~VBoxNetLwipNAT();
void usage(){ /* @todo: should be implemented */ };
int run();
virtual int init(void);
/* @todo: when configuration would be really needed */
private:
struct proxy_options m_ProxyOptions;
struct sockaddr_in m_src4;
struct sockaddr_in6 m_src6;
/**
* place for registered local interfaces.
*/
/* Queues */
/* thread where we're waiting for a frames, no semaphores needed */
/* Our NAT network descriptor in Main */
/* Only for debug needs, by default NAT service should load rules from SVC
* on startup, and then on sync them on events.
*/
bool fDontLoadRulesOnStartup;
static void onLwipTcpIpInit(void *arg);
static void onLwipTcpIpFini(void *arg);
static int intNetThreadRecv(RTTHREAD, void *);
static void vboxNetLwipNATProcessXmit(void);
};
class PortForwardListener
{
public:
virtual ~PortForwardListener(){}
void uninit(){}
private:
};
static VBoxNetLwipNAT *g_pLwipNat;
{
switch (aEventType)
{
{
RT_ZERO(r);
{
hrc = E_INVALIDARG;
goto port_forward_done;
}
switch (proto)
{
case NATProtocol_TCP:
break;
case NATProtocol_UDP:
break;
default:
goto port_forward_done;
}
"%s",
"%s",
/* XXX: limits should be checked */
"%s",
/* XXX: limits should be checked */
if (fCreateFW) /* Addition */
{
}
else /* Deletion */
{
{
/* compare */
{
if (!pFwCopy)
{
break;
}
/* We shouldn't care about pFwCopy this memory will be freed when
* will message will arrive to the destination.
*/
break;
}
} /* loop over vector elements */
} /* condition add or delete */
/* clean up strings */
break;
}
}
return hrc;
}
{
/* lwip thread */
&LwipIpAddr /* IP address*/,
&LwipIpNetMask /* Network mask */,
&LwipIpAddr /* gateway address, @todo: is self IP acceptable? */,
g_pLwipNat /* state */,
lwip_tcpip_input /* netif_input_fn */);
/*
* XXX: lwIP currently only ever calls mld6_joingroup() in
* nd6_tmr() for fresh tentative addresses, which is a wrong place
* to do it - but I'm not keen on fixing this properly for now
* (with correct handling of interface up and down transitions,
* etc). So stick it here as a kludge.
*/
for (int i = 0; i <= 1; ++i) {
}
/*
* XXX: We must join the solicited-node multicast for the
* addresses we do IPv6 NA-proxy for. We map IPv6 loopback to
* proxy address + 1. We only need the low 24 bits, and those are
* fixed.
*/
{
/* last 24 bits of the address */
PP_HTONL(0x00000002));
}
}
{
/* XXX: proxy finalization */
}
/*
* Callback for netif_add() to initialize the interface.
*/
{
/* validity */
| NETIF_FLAG_ETHARP /* Don't bother driver with ARP and let Lwip resolve ARP handling */
| NETIF_FLAG_ETHERNET; /* Lwip works with ethernet too */
/* IPv6 link-local address in slot 0 */
/*
* RFC 4193 Locally Assigned Global ID (ULA) in slot 1
* [fd17:625c:f037:XXXX::1] where XXXX, 16 bit Subnet ID, are two
* bytes from the middle of the IPv4 address, e.g. :dead: for
* 10.222.173.1
*/
#endif
return rcLwip;
}
/**
* Intnet-recv thread
*/
{
int rc = VINF_SUCCESS;
/* 1. initialization and connection */
/* Well we're ready */
for (;;)
{
/*
* Wait for a packet to become available.
*/
/* 2. waiting for request for */
if (RT_FAILURE(rc))
{
{
/* do we want interrupt anyone ??? */
continue;
}
}
/*
* Process the receive buffer.
*/
{
switch (u8Type)
{
case INTNETHDR_TYPE_FRAME:
/* @todo:should it be really here?
* Well well well, we're accessing lwip code here
*/
if (!pPbuf)
{
break;
}
while(pPbuf)
{
}
break;
case INTNETHDR_TYPE_GSO:
{
cbFrame - sizeof(PDMNETWORKGSO)))
break;
cbFrame -= sizeof(PDMNETWORKGSO);
cbFrame);
{
void *pvSegFrame =
iSeg,
&cbSegFrame);
if (!pPbuf)
{
break;
}
}
}
break;
case INTNETHDR_TYPE_PADDING:
break;
default:
break;
}
} /* loop */
}
/* 3. deinitilization and termination */
return rc;
}
/**
*
*/
{
int rc = VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
LogFlowFunc(("ENTER: pNetif[%c%c%d], pPbuf:%p\n",
pPBuf));
/*
* We're on the lwip thread ...
* try accure Xmit lock (actually we DO accure the lock ... )
* 1. we've entered csXmit so we should create frame
* 1.a. Frame creation success see 2.
* 1.b. (hm ... what about queue processing in place)
* 1.c. 2nd attempt create frame
* 1.d. Unlock the Xmit
* 1.e. goto BUSY.1
* 2. Copy pbuf to the frame
* 3. Send
* 4. leave csXmit & return.
*
* @todo: perhaps we can use it for optimization,
* e.g. drop UDP and reoccure lock on TCP NOTE: now BUSY is unachievable!
* Otherwise (BUSY)
* 1. Unbuffered (drop)
* (buffered)
* 1. Copy pbuf to entermediate buffer.
* 2. Add call buffer to the queue
* 3. return.
*/
/* see p.1 */
rc = VINF_SUCCESS;
int offFrame = 0;
int idxSg = 0;
/* Allocate frame, and pad it if required. */
rc = IntNetRingAllocateFrame(&g_pLwipNat->m_pIfBuf->Send, pPBuf->tot_len, &pHdr, (void **)&pu8Frame);
if (RT_SUCCESS(rc))
{
/* see p. 2 */
while (pPBufPtr)
{
}
}
if (RT_FAILURE(rc))
{
/* Could it be that some frames are still in the ring buffer */
/* 1.c */
AssertMsgFailed(("Debug Me!"));
}
/* Commit - what really this function do */
return rcLwip;
}
{
#if HAVE_SA_LEN
#endif
for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
}
{
{
}
}
{
int lrc = 0;
int rc = VINF_SUCCESS;
int socketSpec = SOCK_STREAM;
char *pszHostAddr;
{
case IPPROTO_TCP:
break;
case IPPROTO_UDP:
break;
default:
return VERR_IGNORED; /* Ah, just ignore the garbage */
}
/* XXX: workaround for inet_pton and an empty ipv4 address
* in rule declaration.
*/
if ( sockFamily == PF_INET
&& pszHostAddr[0] == 0)
/*
* We need pass the copy, because we can't be sure
* how much this pointer will be valid in LWIP environment.
*/
return VINF_SUCCESS;
}
{
if (RT_FAILURE(rc))
{
continue;
}
}
return VINF_SUCCESS;
}
int VBoxNetLwipNAT::init()
{
int rc = VINF_SUCCESS;
/* virtualbox initialized in super class */
net.asOutParam());
#if !defined(RT_OS_WINDOWS)
/* XXX: Temporaly disabled this code on Windows for further debugging */
#endif
{
if (RT_SUCCESS(rc))
{
}
}
if (!fDontLoadRulesOnStartup)
{
/* XXX: extract function and do not duplicate */
{
}
{
}
#if 0 /* fetching local mappings */
int count_strs;
{
unsigned int j = 0;
int i;
{
char aszAddr[17];
char *pszTerm;
if ( !pszTerm
continue;
if (RT_FAILURE(rc))
continue;
if (u32Off == 0)
continue;
++j;
}
}
#endif
} /* if (!fDontLoadRulesOnStartup) */
{
char *pszStrTemp; // avoid const char ** vs char **
}
/* end of COM initialization */
NULL, /* user data */
RTTHREADTYPE_IO, /* type */
0, /* flags, @todo: waitable ?*/
"INTNET-RECV");
return rc;
}
{
switch (rc)
{
case 'p':
case 'P':
{
fDontLoadRulesOnStartup = true;
return VINF_SUCCESS;
}
default:;
}
return VERR_NOT_FOUND;
}
int VBoxNetLwipNAT::run()
{
while(true)
{
}
/* @todo: clean up of port-forward rules */
return VINF_SUCCESS;
}
/**
* Entry point.
*/
{
#ifdef RT_OS_WINDOWS
int err;
if (err)
{
return 1;
}
#endif
#ifdef VBOX_WITH_XPCOM
if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
{
return RTMsgErrorExit(RTEXITCODE_FAILURE,
"Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
}
#endif
g_pLwipNat = new VBoxNetLwipNAT();
Log2(("NAT: initialization\n"));
if (!rc)
{
g_pLwipNat->init();
g_pLwipNat->run();
}
delete g_pLwipNat;
return 0;
}
#ifndef VBOX_WITH_HARDENING
{
if (RT_FAILURE(rc))
return RTMsgInitFailure(rc);
}
# if defined(RT_OS_WINDOWS)
)
{
if(uMsg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
}
{
bool bExit = false;
/* Register the Window Class. */
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(void *);
if (atomWindowClass != 0)
{
/* Create the window. */
if (hwnd)
{
{
}
bExit = true;
}
}
if(bExit)
{
/* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
exit(0);
}
return 0;
}
/** (We don't want a console usually.) */
{
#if 0
NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
0, /*__in SIZE_T dwStackSize, */
MsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
NULL, /*__in_opt LPVOID lpParameter,*/
0, /*__in DWORD dwCreationFlags,*/
NULL /*__out_opt LPDWORD lpThreadId*/
);
#endif
}
# endif /* RT_OS_WINDOWS */
#endif /* !VBOX_WITH_HARDENING */