VirtualBox

Changeset 79610 in vbox


Ignore:
Timestamp:
Jul 8, 2019 11:29:30 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
131912
Message:

Main/IDHCPServer: Added a FindLeaseByMAC method that can be used to query the lease database and help the ValKit finding the TXS running inside a VM it just started using natnet or host-only. This uses a reserved method as it will be backported to 6.0 in a bit. bugref:9288 bugref:9151

Location:
trunk/src/VBox/Main
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/UnattendedTemplates/ubuntu_preseed.cfg

    r79419 r79610  
    4646d-i apt-setup/universe boolean true
    4747d-i pkgsel/install-language-support boolean false
     48# Stuff we need to build additions modules:
     49d-i pkgsel/include string build-essential linux-headers-generic perl make
    4850
    4951# Users
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r79605 r79610  
    18341834    uuid="ea2d467f-b6c2-4b9a-8eb5-6e2f275dd72e"
    18351835    wsmap="managed"
    1836     reservedMethods="2" reservedAttributes="6"
     1836    reservedMethods="1" reservedAttributes="6"
    18371837    >
    18381838    <desc>
     
    20432043      </desc>
    20442044    </method>
     2045
     2046    <method name="findLeaseByMAC">
     2047      <desc>
     2048        Queries the persistent lease database by MAC address.
     2049
     2050        This is handy if the host wants to connect to a server running inside
     2051        a VM on a host only network.
     2052
     2053        <result name="VBOX_E_OBJECT_NOT_FOUND">If MAC address not in the database.</result>
     2054        <result name="VBOX_E_FILE_ERROR">If not able to read the lease database file.</result>
     2055      </desc>
     2056      <param name="mac" type="wstring" dir="in">
     2057        <desc>The MAC address to look up.</desc>
     2058      </param>
     2059      <param name="type" type="long" dir="in">
     2060        <desc>Reserved, MBZ.</desc>
     2061      </param>
     2062      <param name="address" type="wstring" dir="out">
     2063        <desc>The assigned address.</desc>
     2064      </param>
     2065      <param name="state" type="wstring" dir="out">
     2066        <desc>The lease state.</desc>
     2067      </param>
     2068      <param name="issued" type="long long" dir="out">
     2069        <desc>Timestamp of when the lease was issued, in seconds since 1970-01-01 UTC.</desc>
     2070      </param>
     2071      <param name="expire" type="long long" dir="out">
     2072        <desc>Timestamp of when the lease expires/expired, in seconds since 1970-01-01 UTC.</desc>
     2073      </param>
     2074    </method>
     2075
     2076    <!-- @todo Add variant of queryLeaseByMac that goes by VM name and optionally slot. -->
     2077    <!-- @todo Add min/default/max lease time settings -->
     2078    <!-- @todo Add lease database attribute (readonly) -->
     2079    <!-- @todo Add methods for complex group operations, that includes lists of mac address,
     2080               client ids, vendor/user class ids as selection criteria -->
     2081    <!-- @todo Add fake DHCP option for assigning fixed IP addresses.  Figure out a way to
     2082               do it for the host only trunk interface too (possible special group operation). -->
     2083
    20452084  </interface>
    20462085
  • trunk/src/VBox/Main/include/DHCPServerImpl.h

    r76562 r79610  
    3636#endif
    3737
    38 #ifdef RT_OS_WINDOWS
     38#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    3939# define DHCP_EXECUTABLE_NAME "VBoxNetDHCP.exe"
    4040#else
     
    4242#endif
    4343
    44 class DHCPServerRunner: public NetworkServiceRunner
     44class DHCPServerRunner : public NetworkServiceRunner
    4545{
    4646public:
    47     DHCPServerRunner():NetworkServiceRunner(DHCP_EXECUTABLE_NAME){}
    48     virtual ~DHCPServerRunner(){};
     47    DHCPServerRunner() : NetworkServiceRunner(DHCP_EXECUTABLE_NAME) {}
     48    virtual ~DHCPServerRunner() {};
    4949
    5050    static const std::string kDsrKeyGateway;
     
    6868 */
    6969
    70 class ATL_NO_VTABLE DHCPServer :
    71     public DHCPServerWrap
     70class ATL_NO_VTABLE DHCPServer
     71    : public DHCPServerWrap
    7272{
    7373public:
     
    134134    HRESULT stop();
    135135    HRESULT restart();
     136    HRESULT findLeaseByMAC(const com::Utf8Str &aMac, LONG aType,
     137                           com::Utf8Str &aAddress, com::Utf8Str &aState, LONG64 *aIssued, LONG64 *aExpire) RT_OVERRIDE;
     138
     139    /** @name Helpers
     140     * @{  */
     141    HRESULT i_calcLeaseFilename(const com::Utf8Str &aNetwork) RT_NOEXCEPT;
     142    /** @} */
    136143
    137144    struct Data;
  • trunk/src/VBox/Main/src-server/DHCPServerImpl.cpp

    r76592 r79610  
    2626#include <iprt/net.h>
    2727#include <iprt/path.h>
     28#include <iprt/cpp/path.h>
    2829#include <iprt/cpp/utils.h>
    2930#include <iprt/cpp/xml.h>
     
    3637// constructor / destructor
    3738/////////////////////////////////////////////////////////////////////////////
     39/** @todo Convert to C strings as this is wastefull:    */
    3840const std::string DHCPServerRunner::kDsrKeyGateway = "--gateway";
    3941const std::string DHCPServerRunner::kDsrKeyLowerIp = "--lower-ip";
     
    6466
    6567    char tempConfigFileName[RTPATH_MAX];
     68    com::Utf8Str strLeaseFilename;
    6669    com::Utf8Str networkName;
    6770    com::Utf8Str trunkName;
     
    665668{
    666669    if (!m->dhcp.isRunning())
    667         return E_FAIL;
     670        return setErrorBoth(E_FAIL, VERR_PROCESS_NOT_FOUND, tr("not running"));
     671
    668672    /*
    669         * Disabled servers will be brought down, but won't be restarted.
    670         * (see DHCPServer::start)
    671         */
     673     * Disabled servers will be brought down, but won't be restarted.
     674     * (see DHCPServer::start)
     675     */
    672676    HRESULT hrc = stop();
    673677    if (SUCCEEDED(hrc))
     
    685689        return S_OK;
    686690
    687     /*
     691    /**
    688692     * @todo: the existing code cannot handle concurrent attempts to start DHCP server.
    689693     * Note that technically it may receive different parameters from different callers.
    690694     */
    691695    m->networkName = aNetworkName;
    692     m->trunkName = aTrunkName;
    693     m->trunkType = aTrunkType;
    694 
    695     m->dhcp.clearOptions();
     696    m->trunkName   = aTrunkName;
     697    m->trunkType   = aTrunkType;
     698    HRESULT hrc = i_calcLeaseFilename(aNetworkName);
     699    if (FAILED(hrc))
     700        return hrc;
     701
     702    m->dhcp.clearOptions(); /* (Not DHCP options, but command line options for the service) */
     703
    696704#ifdef VBOX_WITH_DHCPD
     705
     706    /*
     707     * Create configuration file path.
     708     */
     709    /** @todo put this next to the leases file.   */
    697710    int rc = RTPathTemp(m->tempConfigFileName, sizeof(m->tempConfigFileName));
    698     if (RT_FAILURE(rc))
    699         return E_FAIL;
    700     rc = RTPathAppend(m->tempConfigFileName, sizeof(m->tempConfigFileName), "dhcp-config-XXXXX.xml");
     711    if (RT_SUCCESS(rc))
     712        rc = RTPathAppend(m->tempConfigFileName, sizeof(m->tempConfigFileName), "dhcp-config-XXXXX.xml");
     713    if (RT_SUCCESS(rc))
     714        rc = RTFileCreateTemp(m->tempConfigFileName, 0600);
    701715    if (RT_FAILURE(rc))
    702716    {
     
    704718        return E_FAIL;
    705719    }
    706     rc = RTFileCreateTemp(m->tempConfigFileName, 0600);
    707     if (RT_FAILURE(rc))
    708     {
    709         m->tempConfigFileName[0] = '\0';
    710         return E_FAIL;
    711     }
    712 
     720
     721    /*
     722     * Produce the DHCP server configuration.
     723     */
    713724    xml::Document doc;
    714725    xml::ElementNode *pElmRoot = doc.createRootElement("DHCPServer");
    715     pElmRoot->setAttribute("networkName", m->networkName.c_str());
    716     if (!m->trunkName.isEmpty())
    717         pElmRoot->setAttribute("trunkName", m->trunkName.c_str());
    718     pElmRoot->setAttribute("trunkType", m->trunkType.c_str());
    719     pElmRoot->setAttribute("IPAddress",  Utf8Str(m->IPAddress).c_str());
    720     pElmRoot->setAttribute("networkMask", Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
    721     pElmRoot->setAttribute("lowerIP", Utf8Str(m->lowerIP).c_str());
    722     pElmRoot->setAttribute("upperIP", Utf8Str(m->upperIP).c_str());
     726    pElmRoot->setAttribute("networkName", m->networkName);
     727    if (m->trunkName.isNotEmpty())
     728        pElmRoot->setAttribute("trunkName", m->trunkName);
     729    pElmRoot->setAttribute("trunkType", m->trunkType);
     730    pElmRoot->setAttribute("IPAddress",  m->IPAddress);
     731    pElmRoot->setAttribute("networkMask", m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text);
     732    pElmRoot->setAttribute("lowerIP", m->lowerIP);
     733    pElmRoot->setAttribute("upperIP", m->upperIP);
     734    pElmRoot->setAttribute("leaseFilename", m->strLeaseFilename);
    723735
    724736    /* Process global options */
    725737    xml::ElementNode *pOptions = pElmRoot->createChild("Options");
    726     // settings::DhcpOptionMap::const_iterator itGlobal;
    727     for (settings::DhcpOptionMap::const_iterator it = m->GlobalDhcpOptions.begin();
    728          it != m->GlobalDhcpOptions.end();
    729          ++it)
     738    for (settings::DhcpOptionMap::const_iterator it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it)
    730739        addOptionChild(pOptions, (*it).first, (*it).second);
    731740
    732741    /* Process network-adapter-specific options */
    733742    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    734     HRESULT hrc = S_OK;
     743    hrc = S_OK;
    735744    ComPtr<IMachine> machine;
    736745    ComPtr<INetworkAdapter> nic;
    737746    settings::VmSlot2OptionsIterator it;
    738     for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
     747    for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
    739748    {
    740749        alock.release();
     
    782791
    783792    xml::XmlFileWriter writer(doc);
    784     writer.write(m->tempConfigFileName, true);
    785 
    786     m->dhcp.setOption(DHCPServerRunner::kDsrKeyConfig, m->tempConfigFileName);
     793    writer.write(m->tempConfigFileName, false);
     794
     795    m->dhcp.setOption(DHCPServerRunner::kDsrKeyConfig, m->tempConfigFileName);    /* command line options, not dhcp ones. */
    787796    m->dhcp.setOption(DHCPServerRunner::kDsrKeyComment, m->networkName.c_str());
     797
    788798#else /* !VBOX_WITH_DHCPD */
    789799    /* Main is needed for NATNetwork */
     
    833843
    834844
     845HRESULT DHCPServer::findLeaseByMAC(const com::Utf8Str &aMac, LONG aType,
     846                                    com::Utf8Str &aAddress, com::Utf8Str &aState, LONG64 *aIssued, LONG64 *aExpire)
     847{
     848    /* Reset output before we start */
     849    *aIssued = 0;
     850    *aExpire = 0;
     851    aAddress.setNull();
     852    aState.setNull();
     853
     854    /*
     855     * Convert and check input.
     856     */
     857    RTMAC MacAddress;
     858    int vrc = RTStrConvertHexBytes(aMac.c_str(), &MacAddress, sizeof(MacAddress), RTSTRCONVERTHEXBYTES_F_SEP_COLON);
     859    if (vrc != VINF_SUCCESS)
     860        return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid MAC address '%s': %Rrc"), aMac.c_str(), vrc);
     861    if (aType != 0)
     862        return setError(E_INVALIDARG, tr("flags must be zero (not %#x)"), aType);
     863
     864    /*
     865     * Make sure we've got a lease filename to work with.
     866     */
     867    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     868    if (m->strLeaseFilename.isEmpty())
     869    {
     870        HRESULT hrc = i_calcLeaseFilename(m->networkName.isEmpty() ? mName : m->networkName);
     871        if (FAILED(hrc))
     872            return hrc;
     873    }
     874
     875    /*
     876     * Try at least twice to read the lease database, more if busy.
     877     */
     878    uint64_t const nsStart = RTTimeNanoTS();
     879    for (uint32_t uReadAttempt = 0; ; uReadAttempt++)
     880    {
     881        /*
     882         * Try read the file.
     883         */
     884        xml::Document doc;
     885        try
     886        {
     887            xml::XmlFileParser parser;
     888            parser.read(m->strLeaseFilename.c_str(), doc);
     889        }
     890        catch (const xml::EIPRTFailure &e)
     891        {
     892            vrc = e.rc();
     893            LogThisFunc(("caught xml::EIPRTFailure: rc=%Rrc (attempt %u, msg=%s)\n", vrc, uReadAttempt, e.what()));
     894            if (   (   vrc == VERR_FILE_NOT_FOUND
     895                    || vrc == VERR_OPEN_FAILED
     896                    || vrc == VERR_ACCESS_DENIED
     897                    || vrc == VERR_SHARING_VIOLATION
     898                    || vrc == VERR_READ_ERROR /*?*/)
     899                && (   uReadAttempt == 0
     900                    || (   uReadAttempt < 64
     901                        && RTTimeNanoTS() - nsStart < RT_NS_1SEC / 4)) )
     902            {
     903                alock.release();
     904
     905                if (uReadAttempt > 0)
     906                    RTThreadYield();
     907                RTThreadSleep(8/*ms*/);
     908
     909                alock.acquire();
     910                LogThisFunc(("Retrying...\n"));
     911                continue;
     912            }
     913            return setErrorBoth(VBOX_E_FILE_ERROR, vrc, "Reading '%s' failed: %Rrc - %s",
     914                                m->strLeaseFilename.c_str(), vrc, e.what());
     915        }
     916        catch (const RTCError &e)
     917        {
     918            if (e.what())
     919                return setError(VBOX_E_FILE_ERROR, "Reading '%s' failed: %s", m->strLeaseFilename.c_str(), e.what());
     920            return setError(VBOX_E_FILE_ERROR, "Reading '%s' failed: RTCError", m->strLeaseFilename.c_str());
     921        }
     922        catch (std::bad_alloc &)
     923        {
     924            return E_OUTOFMEMORY;
     925        }
     926        catch (...)
     927        {
     928            AssertFailed();
     929            return setError(VBOX_E_FILE_ERROR, tr("Reading '%s' failed: Unexpected exception"), m->strLeaseFilename.c_str());
     930        }
     931
     932        /*
     933         * Look for that mac address.
     934         */
     935        xml::ElementNode *pElmRoot = doc.getRootElement();
     936        if (pElmRoot && pElmRoot->nameEquals("Leases"))
     937        {
     938            xml::NodesLoop          it(*pElmRoot);
     939            const xml::ElementNode *pElmLease;
     940            while ((pElmLease = it.forAllNodes()) != NULL)
     941                if (pElmLease->nameEquals("Lease"))
     942                {
     943                    const char *pszCurMacAddress = pElmLease->findAttributeValue("mac");
     944                    RTMAC       CurMacAddress;
     945                    if (   pszCurMacAddress
     946                        && RT_SUCCESS(RTNetStrToMacAddr(pszCurMacAddress, &CurMacAddress))
     947                        && memcmp(&CurMacAddress, &MacAddress, sizeof(MacAddress)) == 0)
     948                    {
     949                        /*
     950                         * Found it!
     951                         */
     952                        xml::ElementNode const *pElmTime    = pElmLease->findChildElement("Time");
     953                        int64_t                 secIssued   = 0;
     954                        uint32_t                cSecsToLive = 0;
     955                        if (pElmTime)
     956                        {
     957                            pElmTime->getAttributeValue("issued", &secIssued);
     958                            pElmTime->getAttributeValue("expiration", &cSecsToLive);
     959                            *aIssued = secIssued;
     960                            *aExpire = secIssued + cSecsToLive;
     961                        }
     962                        try
     963                        {
     964                            aAddress = pElmLease->findChildElementAttributeValue("Address", "value");
     965                            aState   = pElmLease->findAttributeValue("state");
     966                        }
     967                        catch (std::bad_alloc &)
     968                        {
     969                            return E_OUTOFMEMORY;
     970                        }
     971
     972                        /* Check if the lease has expired in the mean time. */
     973                        HRESULT hrc = S_OK;
     974                        RTTIMESPEC Now;
     975                        if (   (aState.equals("acked") || aState.equals("offered") || aState.isEmpty())
     976                            && secIssued + cSecsToLive < RTTimeSpecGetSeconds(RTTimeNow(&Now)))
     977                            hrc = aState.assignNoThrow("expired");
     978                        return hrc;
     979                    }
     980                }
     981        }
     982        break;
     983    }
     984
     985    return setError(VBOX_E_OBJECT_NOT_FOUND, tr("Could not find a lease for %RTmac"), &MacAddress);
     986}
     987
     988
     989/**
     990 * Calculates and updates the value of strLeaseFilename given @a aNetwork.
     991 */
     992HRESULT DHCPServer::i_calcLeaseFilename(const com::Utf8Str &aNetwork)
     993{
     994    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     995
     996    /* The lease file must be the same as we used the last time, so careful when changing this code. */
     997    int vrc = m->strLeaseFilename.assignNoThrow(mVirtualBox->i_homeDir());
     998    if (RT_SUCCESS(vrc))
     999        vrc = RTPathAppendCxx(m->strLeaseFilename, aNetwork);
     1000    if (RT_SUCCESS(vrc))
     1001        vrc = m->strLeaseFilename.appendNoThrow("-Dhcpd.leases");
     1002    if (RT_SUCCESS(vrc))
     1003    {
     1004        RTPathPurgeFilename(RTPathFilename(m->strLeaseFilename.mutableRaw()), RTPATH_STR_F_STYLE_HOST);
     1005        m->strLeaseFilename.jolt();
     1006        return S_OK;
     1007    }
     1008    return setErrorBoth(E_FAIL, vrc, tr("Failed to construct lease filename: %Rrc"), vrc);
     1009}
     1010
    8351011settings::DhcpOptionMap &DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str &aVmName,
    8361012                                                              LONG aSlot)
     
    8381014    return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
    8391015}
     1016
  • trunk/src/VBox/Main/src-server/NetworkServiceRunner.cpp

    r76553 r79610  
    1616 */
    1717
     18
     19/*********************************************************************************************************************************
     20*   Header Files                                                                                                                 *
     21*********************************************************************************************************************************/
    1822#include <map>
    1923#include <string>
    2024#include "NetworkServiceRunner.h"
     25
    2126#include <iprt/process.h>
     27#include <iprt/path.h>
    2228#include <iprt/param.h>
    2329#include <iprt/env.h>
     
    2632
    2733
     34/*********************************************************************************************************************************
     35*   Global Variables                                                                                                             *
     36*********************************************************************************************************************************/
     37/** @todo Convert to C strings as this is wastefull:    */
    2838const std::string NetworkServiceRunner::kNsrKeyName      = "--name";
    2939const std::string NetworkServiceRunner::kNsrKeyNetwork   = "--network";
     
    3545const std::string NetworkServiceRunner::kNsrKeyNeedMain  = "--need-main";
    3646
     47
     48/*********************************************************************************************************************************
     49*   Structures and Typedefs                                                                                                      *
     50*********************************************************************************************************************************/
    3751struct NetworkServiceRunner::Data
    3852{
     
    4458    const char *mProcName;
    4559    RTPROCESS mProcess;
    46     std::map<std::string, std::string> mOptions;
     60    std::map<std::string, std::string> mOptions; /**< @todo r=bird: A map for command line option/value pairs? really?
     61                                                  * Wouldn't a simple argument list have done it much much more efficiently? */
    4762    bool mKillProcOnStop;
    4863};
     64
     65
    4966
    5067NetworkServiceRunner::NetworkServiceRunner(const char *aProcName)
     
    86103        return VINF_ALREADY_INITIALIZED;
    87104
    88     const char * args[10*2];
    89 
    90     AssertReturn(m->mOptions.size() < 10, VERR_INTERNAL_ERROR);
    91 
    92     /* get the path to the executable */
    93     char exePathBuf[RTPATH_MAX];
    94     const char *exePath = RTProcGetExecutablePath(exePathBuf, RTPATH_MAX);
    95     char *substrSl = strrchr(exePathBuf, '/');
    96     char *substrBs = strrchr(exePathBuf, '\\');
    97     char *suffix = substrSl ? substrSl : substrBs;
    98 
    99     if (suffix)
     105    /*
     106     * Construct the path to the executable.  ASSUME it is relative to the
     107     * directory that holds VBoxSVC.
     108     */
     109    char szExePath[RTPATH_MAX];
     110    AssertReturn(RTProcGetExecutablePath(szExePath, RTPATH_MAX), VERR_FILENAME_TOO_LONG);
     111    RTPathStripFilename(szExePath);
     112    int vrc = RTPathAppend(szExePath, sizeof(szExePath), m->mProcName);
     113    AssertLogRelRCReturn(vrc, vrc);
     114
     115    /*
     116     * Allocate the argument array and construct the argument vector.
     117     */
     118    size_t const cArgs     = 1 + m->mOptions.size() * 2 + 1;
     119    char const **papszArgs = (char const **)RTMemTmpAllocZ(sizeof(papszArgs[0]) * cArgs);
     120    AssertReturn(papszArgs, VERR_NO_TMP_MEMORY);
     121
     122    size_t iArg = 0;
     123    papszArgs[iArg++] = szExePath;
     124    for (std::map<std::string, std::string>::const_iterator it = m->mOptions.begin(); it != m->mOptions.end(); ++it)
    100125    {
    101         suffix++;
    102         strcpy(suffix, m->mProcName);
     126        papszArgs[iArg++] = it->first.c_str();
     127        papszArgs[iArg++] = it->second.c_str();
    103128    }
    104 
    105     int index = 0;
    106 
    107     args[index++] = exePath;
    108 
    109     std::map<std::string, std::string>::const_iterator it;
    110     for(it = m->mOptions.begin(); it != m->mOptions.end(); ++it)
    111     {
    112         args[index++] = it->first.c_str();
    113         args[index++] = it->second.c_str();
    114     }
    115 
    116     args[index++] = NULL;
    117 
    118     int rc = RTProcCreate(suffix ? exePath : m->mProcName, args, RTENV_DEFAULT, 0, &m->mProcess);
     129    Assert(iArg + 1 == cArgs);
     130    Assert(papszArgs[iArg] == NULL);
     131
     132    /*
     133     * Start the process:
     134     */
     135    int rc = RTProcCreate(szExePath, papszArgs, RTENV_DEFAULT, 0, &m->mProcess);
    119136    if (RT_FAILURE(rc))
    120137        m->mProcess = NIL_RTPROCESS;
    121138
    122139    m->mKillProcOnStop = aKillProcOnStop;
     140
     141    RTMemTmpFree(papszArgs);
    123142    return rc;
    124143}
Note: See TracChangeset for help on using the changeset viewer.

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