VBoxNetDHCP.cpp revision 95e20cd18dc1a5f7d437bbe2d7c72980c4e0caf7
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * VBoxNetDHCP - DHCP Service for connecting to IntNet.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Copyright (C) 2009 Oracle Corporation
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * available from http://www.virtualbox.org. This file is free software;
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * General Public License (GPL) as published by the Free Software
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync/** @page pg_net_dhcp VBoxNetDHCP
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * Write a few words...
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync/*******************************************************************************
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync* Header Files *
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync*******************************************************************************/
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync/*******************************************************************************
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync* Structures and Typedefs *
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync*******************************************************************************/
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * DHCP configuration item.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * This is all public data because I'm too lazy to do it properly right now.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /** The etheret addresses this matches config applies to.
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync * An empty vector means 'ANY'. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /** The upper address in the range. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /** The lower address in the range. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /** Option 1: The net mask. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 2: The time offset. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /** Option 3: Routers for the subnet. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 4: Time server. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 5: Name server. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /** Option 6: Domain Name Server (DNS) */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 7: Log server. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 8: Cookie server. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 9: LPR server. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 10: Impress server. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 11: Resource location server. */
deb4998ba50060c48cce222fd18a8eed053918d7vboxsync /* * Option 12: Host name. */
int validate(void)
RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: Too many IPs between --upper-ip and --lower-ip! %d (max 1024)\n"
cIPs,
bool isOneSpecificClient(void) const
class VBoxNetDhcpLease
typedef enum State
kState_Invalid = 0,
} State;
void activate(void);
void release(void);
bool hasExpired(void) const;
if (!pNow)
bool isOneSpecificClient(void) const
return m_pCfg
bool isBeingOffered(void) const
&& isInUse();
bool isInCurrentConfig(void) const
class VBoxNetDhcp
VBoxNetDhcp();
virtual ~VBoxNetDhcp();
int tryGoOnline(void);
int run(void);
void explodeConfig(void);
VBoxNetDhcpLease *findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState);
static uint8_t const *findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, size_t *pcbMaxOpt);
static bool findOptionIPv4Addr(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, PRTNETADDRIPV4 pIPv4Addr);
RTTimeSpecAddSeconds(&m_ExpireTime, m_pCfg ? m_pCfg->m_cSecLease : 60); /* m_pCfg can be NULL right now... */
activate();
m_cVerbosity = 0;
m_cbCurMsg = 0;
if (m_pSession)
int rc = 0;
if (pCfg)
if (!rc)
delete pCfg;
return rc;
Itr++;
while (iCfg-- > 0)
if (pLease)
int rc = RTGetOptInit(&State, argc, argv, &s_aOptionDefs[0], RT_ELEMENTS(s_aOptionDefs), 0, 0 /*fFlags*/);
if (!rc)
switch (rc)
m_cVerbosity++;
if (rc)
if (!pCurCfg)
if (!pCurCfg)
switch (rc)
RTBldCfgVersion());
return rc;
if (!rc)
return rc;
rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0, &GetBufferPtrsReq.Hdr);
RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc);
RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS,) failed, rc=%Rrc\n", rc);
RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_OPEN,) failed, rc=%Rrc\n", rc);
WaitReq.cMillies = 2000; /* 2 secs - the sleep is for some reason uninterruptible... */ /** @todo fix interruptability in SrvIntNet! */
debugPrint(1, true, "VBoxNetDHCP: Skipping invalid DHCP packet.\n"); /** @todo handle pure bootp clients too? */
m_cbCurMsg = 0;
switch (uMsgType)
case RTNET_DHCP_MT_DISCOVER:
case RTNET_DHCP_MT_REQUEST:
case RTNET_DHCP_MT_DECLINE:
case RTNET_DHCP_MT_RELEASE:
case RTNET_DHCP_MT_INFORM:
if (!pLease)
if (fReqAddr)
fReqAddr = true;
if ( !pLease
pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */);
#if 0 /** @todo client id stuff - it doesn't make sense here imho, we need IP + MAC. What would make sense
if (!pLease)
if ( pbClientID
pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */);
bool fAckIt = false;
if (pLease)
fAckIt = true;
fAckIt = true;
if (fAckIt)
class VBoxNetDhcpWriteCursor
m_fUsed(0),
m_fOverflowed(false)
bool useBpFile(void)
if ( m_pfOverload
bool overloadMore(void)
if (!m_pfOverload)
if (!overloadMore())
m_fOverflowed = true;
m_fOverflowed = true;
for (size_t i = 0; i < c; i++)
if (!cch)
bool hasOverflowed(void) const
return m_fOverflowed;
bool optEnd(void)
return !hasOverflowed();
void VBoxNetDhcp::makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb)
size_t cbReply = RTNET_DHCP_NORMAL_SIZE; /** @todo respect the RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE option */
pReply->bp_siaddr.u = pLease && pLease->m_pCfg ? pLease->m_pCfg->m_TftpServerAddr.u : 0; /* (next server == TFTP)*/
RTStrPrintf((char *)&pReply->bp_file[0], sizeof(pReply->bp_file), "%s", pCfg->m_BootfileName.c_str());
int rc;
if (!(pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST)) /** @todo need to see someone set this flag to check that it's correct. */
while (iLease-- > 0)
if ( pLease
&& ( fAnyState
return pLease;
return NULL;
VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState)
while (iLease-- > 0)
if ( pLease
&& ( fAnyState
return pLease;
return NULL;
if ( !pBest
if ( !pOld
if ( !pFree
if (!pNew)
if (!pNew)
if (!pNew)
return NULL;
return pNew;
return NULL;
return NULL;
bool fExtended = false;
cbLeft--;
pb++;
if (pcbOpt)
return NULL;
VBoxNetDhcp::findOptionIPv4Addr(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, PRTNETADDRIPV4 pIPv4Addr)
if (pbOpt)
RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy);
if ( fMsg
&& m_pCurMsg)
RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: debug: %8s chaddr=%.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d siaddr=%d.%d.%d.%d xid=%#x\n",
m_pCurMsg->bp_ciaddr.au8[0], m_pCurMsg->bp_ciaddr.au8[1], m_pCurMsg->bp_ciaddr.au8[2], m_pCurMsg->bp_ciaddr.au8[3],
m_pCurMsg->bp_yiaddr.au8[0], m_pCurMsg->bp_yiaddr.au8[1], m_pCurMsg->bp_yiaddr.au8[2], m_pCurMsg->bp_yiaddr.au8[3],
m_pCurMsg->bp_siaddr.au8[0], m_pCurMsg->bp_siaddr.au8[1], m_pCurMsg->bp_siaddr.au8[2], m_pCurMsg->bp_siaddr.au8[3],
switch (uMsgType)
if (!pDhcp)
if (rc)
return rc;
if (rc)
delete pDhcp;
return rc;
delete pDhcp;
return rc;
#ifndef VBOX_WITH_HARDENING
# ifdef RT_OS_WINDOWS
PostQuitMessage(0);
bool bExit = false;
if (atomWindowClass != 0)
if (hwnd)
bExit = true;
if(bExit)
/* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
exit(0);