VirtualBox

Changeset 71689 in vbox


Ignore:
Timestamp:
Apr 5, 2018 3:20:32 PM (7 years ago)
Author:
vboxsync
Message:

NetworkServices/Dhcpd: implement reading config from a file.

Location:
trunk/src/VBox/NetworkServices/Dhcpd
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/Dhcpd/Config.cpp

    r71353 r71689  
    1616 */
    1717
     18#include "Config.h"
     19
    1820#include <iprt/types.h>
    1921#include <iprt/net.h>           /* NB: must come before getopt.h */
     
    2224#include <iprt/message.h>
    2325#include <iprt/string.h>
    24 
    25 #include "Config.h"
    26 
    27 
    28 bool Config::isSane()
    29 {
    30     int rc;
     26#include <iprt/uuid.h>
     27
     28#include <VBox/com/com.h>
     29
     30#include <iostream>
     31
     32class ConfigFileError
     33  : public RTCError
     34{
     35public:
     36    ConfigFileError(const char *pszMessage)
     37      : RTCError(pszMessage) {}
     38
     39    ConfigFileError(const RTCString &a_rstrMessage)
     40      : RTCError(a_rstrMessage) {}
     41};
     42
     43
     44Config::Config()
     45  : m_strHome(),
     46    m_strNetwork(),
     47    m_strBaseName(),
     48    m_strTrunk(),
     49    m_enmTrunkType(kIntNetTrunkType_Invalid),
     50    m_MacAddress(),
     51    m_IPv4Address(),
     52    m_IPv4Netmask(),
     53    m_IPv4PoolFirst(),
     54    m_IPv4PoolLast(),
     55    m_GlobalOptions(),
     56    m_VMMap()
     57{
     58    return;
     59}
     60
     61
     62int Config::init()
     63{
     64    int rc;
     65
     66    rc = homeInit();
     67    if (RT_FAILURE(rc))
     68        return rc;
     69
     70    return VINF_SUCCESS;
     71}
     72
     73
     74int Config::homeInit()
     75{
     76    int rc;
     77
     78    /* pathname of ~/.VirtualBox or equivalent */
     79    char szHome[RTPATH_MAX];
     80    rc = com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome), false);
     81    if (RT_FAILURE(rc))
     82    {
     83        LogDHCP(("unable to find VirtualBox home directory: %Rrs", rc));
     84        return rc;
     85    }
     86
     87    m_strHome.assign(szHome);
     88    return VINF_SUCCESS;
     89}
     90
     91
     92void Config::setNetwork(const std::string &aStrNetwork)
     93{
     94    AssertReturnVoid(m_strNetwork.empty());
     95
     96    m_strNetwork = aStrNetwork;
     97    sanitizeBaseName();
     98}
     99
     100
     101/*
     102 * Requires network name to be known as the log file name depends on
     103 * it.  Alternatively, consider passing the log file name via the
     104 * command line?
     105 */
     106int Config::logInit()
     107{
     108    int rc;
     109    size_t cch;
     110
     111    if (m_strHome.empty() || m_strBaseName.empty())
     112        return VERR_GENERAL_FAILURE;
     113
     114    /* default log file name */
     115    char szLogFile[RTPATH_MAX];
     116    cch = RTStrPrintf(szLogFile, sizeof(szLogFile),
     117                      "%s%c%s-Dhcpd.log",
     118                      m_strHome.c_str(), RTPATH_DELIMITER, m_strBaseName.c_str());
     119    if (cch >= sizeof(szLogFile))
     120        return VERR_BUFFER_OVERFLOW;
     121
     122
     123    /* get a writable copy of the base name */
     124    char szBaseName[RTPATH_MAX];
     125    rc = RTStrCopy(szBaseName, sizeof(szBaseName), m_strBaseName.c_str());
     126    if (RT_FAILURE(rc))
     127        return rc;
     128
     129    /* sanitize base name some more to be usable in an environment variable name */
     130    for (char *p = szBaseName; *p != '\0'; ++p)
     131    {
     132        if (   *p != '_'
     133            && (*p < '0' || '9' < *p)
     134            && (*p < 'a' || 'z' < *p)
     135            && (*p < 'A' || 'Z' < *p))
     136        {
     137            *p = '_';
     138        }
     139    }
     140
     141
     142    /* name of the environment variable to control logging */
     143    char szEnvVarBase[128];
     144    cch = RTStrPrintf(szEnvVarBase, sizeof(szEnvVarBase),
     145                      "VBOXDHCP_%s_RELEASE_LOG", szBaseName);
     146    if (cch >= sizeof(szEnvVarBase))
     147        return VERR_BUFFER_OVERFLOW;
     148
     149
     150    rc = com::VBoxLogRelCreate("DHCP Server",
     151                               szLogFile,
     152                               RTLOGFLAGS_PREFIX_TIME_PROG,
     153                               "all all.restrict -default.restrict",
     154                               szEnvVarBase,
     155                               RTLOGDEST_FILE
     156#ifdef DEBUG
     157                               | RTLOGDEST_STDERR
     158#endif
     159                               ,
     160                               32768 /* cMaxEntriesPerGroup */,
     161                               0 /* cHistory */,
     162                               0 /* uHistoryFileTime */,
     163                               0 /* uHistoryFileSize */,
     164                               NULL /* pErrInfo */);
     165
     166    return rc;
     167}
     168
     169
     170int Config::complete()
     171{
     172    int rc;
     173
     174    if (m_strNetwork.empty())
     175    {
     176        LogDHCP(("network name is not specified\n"));
     177        return false;
     178    }
     179
     180    logInit();
     181
     182    bool fMACGenerated = false;
     183    if (   m_MacAddress.au16[0] == 0
     184        && m_MacAddress.au16[1] == 0
     185        && m_MacAddress.au16[2] == 0)
     186    {
     187        RTUUID Uuid;
     188        RTUuidCreate(&Uuid);
     189
     190        m_MacAddress.au8[0] = 0x08;
     191        m_MacAddress.au8[1] = 0x00;
     192        m_MacAddress.au8[2] = 0x27;
     193        m_MacAddress.au8[3] = Uuid.Gen.au8Node[3];
     194        m_MacAddress.au8[4] = Uuid.Gen.au8Node[4];
     195        m_MacAddress.au8[5] = Uuid.Gen.au8Node[5];
     196
     197        LogDHCP(("MAC address is not specified: will use generated MAC %RTmac\n", &m_MacAddress));
     198        fMACGenerated = true;
     199    }
    31200
    32201    /* unicast MAC address */
    33202    if (m_MacAddress.au8[0] & 0x01)
    34         return false;
     203    {
     204        LogDHCP(("MAC address is not unicast: %RTmac\n", &m_MacAddress));
     205        return VERR_GENERAL_FAILURE;
     206    }
    35207
    36208    /* unicast IP address */
    37209    if ((m_IPv4Address.au8[0] & 0xe0) == 0xe0)
    38         return false;
     210    {
     211        LogDHCP(("IP address is not unicast: %RTnaipv4\n", m_IPv4Address.u));
     212        return VERR_GENERAL_FAILURE;
     213    }
    39214
    40215    /* valid netmask */
     
    42217    rc = RTNetMaskToPrefixIPv4(&m_IPv4Netmask, &iPrefixLengh);
    43218    if (RT_FAILURE(rc) || iPrefixLengh == 0)
    44         return false;
     219    {
     220        LogDHCP(("IP mask is not valid: %RTnaipv4\n", m_IPv4Netmask.u));
     221        return VERR_GENERAL_FAILURE;
     222    }
    45223
    46224    /* first IP is from the same network */
    47225    if ((m_IPv4PoolFirst.u & m_IPv4Netmask.u) != (m_IPv4Address.u & m_IPv4Netmask.u))
    48         return false;
     226    {
     227        LogDHCP(("first pool address is outside the network %RTnaipv4/%d: %RTnaipv4\n",
     228                 (m_IPv4Address.u & m_IPv4Netmask.u), iPrefixLengh,
     229                 m_IPv4PoolFirst.u));
     230        return VERR_GENERAL_FAILURE;
     231    }
    49232
    50233    /* last IP is from the same network */
    51234    if ((m_IPv4PoolLast.u & m_IPv4Netmask.u) != (m_IPv4Address.u & m_IPv4Netmask.u))
    52         return false;
     235    {
     236        LogDHCP(("last pool address is outside the network %RTnaipv4/%d: %RTnaipv4\n",
     237                 (m_IPv4Address.u & m_IPv4Netmask.u), iPrefixLengh,
     238                 m_IPv4PoolLast.u));
     239        return VERR_GENERAL_FAILURE;
     240    }
    53241
    54242    /* the pool is valid */
    55243    if (RT_N2H_U32(m_IPv4PoolLast.u) < RT_N2H_U32(m_IPv4PoolFirst.u))
    56         return false;
    57 
    58     return true;
     244    {
     245        LogDHCP(("pool range is invalid: %RTnaipv4 - %RTnaipv4\n",
     246                 m_IPv4PoolFirst.u, m_IPv4PoolLast.u));
     247        return VERR_GENERAL_FAILURE;
     248    }
     249
     250    /* our own address is not inside the pool */
     251    if (   RT_N2H_U32(m_IPv4PoolFirst.u) <= RT_N2H_U32(m_IPv4Address.u)
     252        && RT_N2H_U32(m_IPv4Address.u)  <= RT_N2H_U32(m_IPv4PoolLast.u))
     253    {
     254        LogDHCP(("server address inside the pool range %RTnaipv4 - %RTnaipv4: %RTnaipv4\n",
     255                 m_IPv4PoolFirst.u, m_IPv4PoolLast.u, m_IPv4Address.u));
     256        return VERR_GENERAL_FAILURE;
     257    }
     258
     259    if (!fMACGenerated)
     260        LogDHCP(("MAC address %RTmac\n", &m_MacAddress));
     261    LogDHCP(("IP address %RTnaipv4/%d\n", m_IPv4Address.u, iPrefixLengh));
     262    LogDHCP(("address pool %RTnaipv4 - %RTnaipv4\n", m_IPv4PoolFirst.u, m_IPv4PoolLast.u));
     263
     264    return VINF_SUCCESS;
    59265}
    60266
     
    62268Config *Config::hardcoded()
    63269{
     270    int rc;
     271
    64272    std::unique_ptr<Config> config(new Config());
    65 
    66     config->m_strNetwork.assign("HostInterfaceNetworking-vboxnet0");
    67     config->sanitizeBaseName(); /* nop, but be explicit */
    68 
     273    rc = config->init();
     274    if (RT_FAILURE(rc))
     275        return NULL;
     276
     277    config->setNetwork("HostInterfaceNetworking-vboxnet0");
    69278    config->m_strTrunk.assign("vboxnet0");
    70279    config->m_enmTrunkType = kIntNetTrunkType_NetFlt;
     
    90299#endif
    91300
    92     AssertReturn(config->isSane(), NULL);
     301    rc = config->complete();
     302    AssertRCReturn(rc, NULL);
     303
    93304    return config.release();
    94305}
     
    101312    { "--lower-ip",       'l',   RTGETOPT_REQ_IPV4ADDR },
    102313    { "--mac-address",    'a',   RTGETOPT_REQ_MACADDR },
     314    { "--need-main",      'M',   RTGETOPT_REQ_BOOL },
    103315    { "--netmask",        'm',   RTGETOPT_REQ_IPV4ADDR },
    104316    { "--network",        'n',   RTGETOPT_REQ_STRING },
     
    120332
    121333    std::unique_ptr<Config> config(new Config());
     334    rc = config->init();
     335    if (RT_FAILURE(rc))
     336        return NULL;
     337
    122338    for (;;)
    123339    {
     
    131347        {
    132348            case 'a': /* --mac-address */
     349                if (   config->m_MacAddress.au16[0] != 0
     350                    || config->m_MacAddress.au16[1] != 0
     351                    || config->m_MacAddress.au16[2] != 0)
     352                {
     353                    RTMsgError("Duplicate --mac-address option");
     354                    return NULL;
     355                }
    133356                config->m_MacAddress = Val.MacAddr;
    134357                break;
    135358
    136359            case 'i': /* --ip-address */
     360                if (config->m_IPv4Address.u != 0)
     361                {
     362                    RTMsgError("Duplicate --ip-address option");
     363                    return NULL;
     364                }
    137365                config->m_IPv4Address = Val.IPv4Addr;
    138366                break;
    139367
    140368            case 'l': /* --lower-ip */
     369                if (config->m_IPv4PoolFirst.u != 0)
     370                {
     371                    RTMsgError("Duplicate --lower-ip option");
     372                    return NULL;
     373                }
    141374                config->m_IPv4PoolFirst = Val.IPv4Addr;
    142375                break;
    143376
     377            case 'M': /* --need-main */
     378                /* for backward compatibility, ignored */
     379                break;
     380
    144381            case 'm': /* --netmask */
     382                if (config->m_IPv4Netmask.u != 0)
     383                {
     384                    RTMsgError("Duplicate --netmask option");
     385                    return NULL;
     386                }
    145387                config->m_IPv4Netmask = Val.IPv4Addr;
    146388                break;
    147389
    148390            case 'n': /* --network */
    149                 config->m_strNetwork.assign(Val.psz);
     391                if (!config->m_strNetwork.empty())
     392                {
     393                    RTMsgError("Duplicate --network option");
     394                    return NULL;
     395                }
     396                config->setNetwork(Val.psz);
    150397                break;
    151398
    152399            case 't': /* --trunk-name */
     400                if (!config->m_strTrunk.empty())
     401                {
     402                    RTMsgError("Duplicate --trunk-name option");
     403                    return NULL;
     404                }
    153405                config->m_strTrunk.assign(Val.psz);
    154406                break;
    155407
    156408            case 'T': /* --trunk-type */
    157                 if (strcmp(Val.psz, "none") == 0)
     409                if (config->m_enmTrunkType != kIntNetTrunkType_Invalid)
     410                {
     411                    RTMsgError("Duplicate --trunk-type option");
     412                    return NULL;
     413                }
     414                else if (strcmp(Val.psz, "none") == 0)
    158415                    config->m_enmTrunkType = kIntNetTrunkType_None;
    159416                else if (strcmp(Val.psz, "whatever") == 0)
     
    171428
    172429            case 'u': /* --upper-ip */
     430                if (config->m_IPv4PoolLast.u != 0)
     431                {
     432                    RTMsgError("Duplicate --upper-ip option");
     433                    return NULL;
     434                }
    173435                config->m_IPv4PoolLast = Val.IPv4Addr;
    174436                break;
     
    184446    }
    185447
    186     config->sanitizeBaseName();
    187 
    188     if (!config->isSane())
     448    rc = config->complete();
     449    if (RT_FAILURE(rc))
    189450        return NULL;
    190451
     
    247508        return NULL;
    248509
    249     if (!config->isSane())
    250         return NULL;
    251 
    252     config->sanitizeBaseName();
     510    rc = config->complete();
     511    if (RT_FAILURE(rc))
     512        return NULL;
    253513
    254514    return config.release();
     
    258518Config *Config::read(const char *pszFileName)
    259519{
     520    int rc;
     521
     522    if (pszFileName == NULL || pszFileName[0] == '\0')
     523        return NULL;
     524
     525    xml::Document doc;
     526    try
     527    {
     528        xml::XmlFileParser parser;
     529        parser.read(pszFileName, doc);
     530    }
     531    catch (const xml::EIPRTFailure &e)
     532    {
     533        LogDHCP(("%s\n", e.what()));
     534        return NULL;
     535    }
     536    catch (const RTCError &e)
     537    {
     538        LogDHCP(("%s\n", e.what()));
     539        return NULL;
     540    }
     541    catch (...)
     542    {
     543        LogDHCP(("Unknown exception while reading and parsing '%s'\n",
     544                 pszFileName));
     545        return NULL;
     546    }
     547
    260548    std::unique_ptr<Config> config(new Config());
    261 
    262     RT_NOREF(pszFileName);
     549    rc = config->init();
     550    if (RT_FAILURE(rc))
     551        return NULL;
     552
     553    try
     554    {
     555        config->parseConfig(doc.getRootElement());
     556    }
     557    catch (const RTCError &e)
     558    {
     559        LogDHCP(("%s\n", e.what()));
     560        return NULL;
     561    }
     562    catch (...)
     563    {
     564        LogDHCP(("Unexpected exception\n"));
     565        return NULL;
     566    }
     567
    263568    return config.release();
     569}
     570
     571
     572void Config::parseConfig(const xml::ElementNode *root)
     573{
     574    if (root == NULL)
     575        throw ConfigFileError("Empty config file");
     576
     577    /*
     578     * XXX: NAMESPACE API IS COMPLETELY BROKEN, SO IGNORE IT FOR NOW
     579     */
     580    if (!root->nameEquals("DHCPServer"))
     581    {
     582        const char *name = root->getName();
     583        throw ConfigFileError(RTCStringFmt("Unexpected root element \"%s\"",
     584                                           name ? name : "(null)"));
     585    }
     586
     587    parseServer(root);
     588
     589    // XXX: debug
     590    for (auto it: m_GlobalOptions) {
     591        std::shared_ptr<DhcpOption> opt(it.second);
     592
     593        octets_t data;
     594        opt->encode(data);
     595
     596        bool space = false;
     597        for (auto c: data) {
     598            if (space)
     599                std::cout << " ";
     600            else
     601                space = true;
     602            std::cout << (int)c;
     603        }
     604        std::cout << std::endl;
     605    }
     606}
     607
     608
     609static void getIPv4AddrAttribute(const xml::ElementNode *pNode, const char *pcszAttrName,
     610                                 RTNETADDRIPV4 *pAddr)
     611{
     612    RTCString strAddr;
     613    bool fHasAttr = pNode->getAttributeValue(pcszAttrName, &strAddr);
     614    if (!fHasAttr)
     615        throw ConfigFileError(RTCStringFmt("%s attribute missing",
     616                                           pcszAttrName));
     617
     618    int rc = RTNetStrToIPv4Addr(strAddr.c_str(), pAddr);
     619    if (RT_FAILURE(rc))
     620        throw ConfigFileError(RTCStringFmt("%s attribute invalid",
     621                                           pcszAttrName));
     622}
     623
     624
     625void Config::parseServer(const xml::ElementNode *server)
     626{
     627    /*
     628     * DHCPServer attributes
     629     */
     630    RTCString strNetworkName;
     631    bool fHasNetworkName = server->getAttributeValue("networkName", &strNetworkName);
     632    if (!fHasNetworkName)
     633        throw ConfigFileError("DHCPServer/@networkName missing");
     634
     635    setNetwork(strNetworkName.c_str());
     636
     637    getIPv4AddrAttribute(server, "IPAddress", &m_IPv4Address);
     638    getIPv4AddrAttribute(server, "networkMask", &m_IPv4Netmask);
     639    getIPv4AddrAttribute(server, "lowerIP", &m_IPv4PoolFirst);
     640    getIPv4AddrAttribute(server, "upperIP", &m_IPv4PoolLast);
     641
     642    /*
     643     * DHCPServer children
     644     */
     645    xml::NodesLoop it(*server);
     646    const xml::ElementNode *node;
     647    while ((node = it.forAllNodes()) != NULL)
     648    {
     649        /*
     650         * Global options
     651         */
     652        if (node->nameEquals("Options"))
     653        {
     654            parseGlobalOptions(node);
     655        }
     656
     657        /*
     658         * Per-VM configuration
     659         */
     660        else if (node->nameEquals("Config"))
     661        {
     662            parseVMConfig(node);
     663        }
     664    }
     665}
     666
     667
     668void Config::parseGlobalOptions(const xml::ElementNode *options)
     669{
     670    xml::NodesLoop it(*options);
     671    const xml::ElementNode *node;
     672    while ((node = it.forAllNodes()) != NULL)
     673    {
     674        if (node->nameEquals("Option"))
     675        {
     676            parseOption(node, m_GlobalOptions);
     677        }
     678        else
     679        {
     680            throw ConfigFileError(RTCStringFmt("Unexpected element \"%s\"",
     681                                               node->getName()));
     682        }
     683    }
     684}
     685
     686
     687/*
     688 * VM Config entries are generated automatically from VirtualBox.xml
     689 * with the MAC fetched from the VM config.  The client id is nowhere
     690 * in the picture there, so VM config is indexed with plain RTMAC, not
     691 * ClientId (also see getOptions below).
     692 */
     693void Config::parseVMConfig(const xml::ElementNode *config)
     694{
     695    RTMAC mac;
     696    int rc;
     697
     698    RTCString strMac;
     699    bool fHasMac = config->getAttributeValue("MACAddress", &strMac);
     700    if (!fHasMac)
     701        throw ConfigFileError(RTCStringFmt("Config missing MACAddress attribute"));
     702
     703    rc = parseMACAddress(mac, strMac);
     704    if (RT_FAILURE(rc))
     705    {
     706        throw ConfigFileError(RTCStringFmt("Malformed MACAddress attribute \"%s\"",
     707                                           strMac.c_str()));
     708    }
     709
     710    vmmap_t::iterator vmit( m_VMMap.find(mac) );
     711    if (vmit != m_VMMap.end())
     712    {
     713        throw ConfigFileError(RTCStringFmt("Duplicate Config for MACAddress \"%s\"",
     714                                           strMac.c_str()));
     715    }
     716
     717    optmap_t &vmopts = m_VMMap[mac];
     718
     719    xml::NodesLoop it(*config);
     720    const xml::ElementNode *node;
     721    while ((node = it.forAllNodes()) != NULL)
     722    {
     723        if (node->nameEquals("Option"))
     724        {
     725            parseOption(node, vmopts);
     726        }
     727        else
     728        {
     729            throw ConfigFileError(RTCStringFmt("Unexpected element \"%s\"",
     730                                               node->getName()));
     731        }
     732    }   
     733}
     734
     735
     736int Config::parseMACAddress(RTMAC &aMac, const RTCString &aStr)
     737{
     738    RTMAC mac;
     739    int rc;
     740
     741    rc = RTNetStrToMacAddr(aStr.c_str(), &mac);
     742    if (RT_FAILURE(rc))
     743        return rc;
     744    if (rc == VWRN_TRAILING_CHARS)
     745        return VERR_INVALID_PARAMETER;
     746
     747    aMac = mac;
     748    return VINF_SUCCESS;
     749}
     750
     751
     752int Config::parseClientId(OptClientId &aId, const RTCString &aStr)
     753{
     754    RT_NOREF(aId, aStr);
     755    return VERR_GENERAL_FAILURE;
     756}
     757
     758
     759/*
     760 * Parse <Option/> element and add the option to the specified optmap.
     761 */
     762void Config::parseOption(const xml::ElementNode *option, optmap_t &optmap)
     763{
     764    int rc;
     765
     766    uint8_t u8Opt;
     767    RTCString strName;
     768    bool fHasName = option->getAttributeValue("name", &strName);
     769    if (fHasName)
     770    {
     771        const char *pcszName = strName.c_str();
     772
     773        rc = RTStrToUInt8Full(pcszName, 10, &u8Opt);
     774        if (rc != VINF_SUCCESS) /* no warnings either */
     775            throw ConfigFileError(RTCStringFmt("Bad option \"%s\"", pcszName));
     776
     777    }
     778    else
     779        throw ConfigFileError("missing option name");
     780
     781
     782    uint32_t u32Enc = 0;        /* XXX: DhcpOptEncoding_Legacy */
     783    RTCString strEncoding;
     784    bool fHasEncoding = option->getAttributeValue("encoding", &strEncoding);
     785    if (fHasEncoding)
     786    {
     787        const char *pcszEnc = strEncoding.c_str();
     788
     789        rc = RTStrToUInt32Full(pcszEnc, 10, &u32Enc);
     790        if (rc != VINF_SUCCESS) /* no warnings either */
     791            throw ConfigFileError(RTCStringFmt("Bad encoding \"%s\"", pcszEnc));
     792
     793        switch (u32Enc)
     794        {
     795        case 0:                 /* XXX: DhcpOptEncoding_Legacy */
     796        case 1:                 /* XXX: DhcpOptEncoding_Hex */
     797            break;
     798        default:
     799            throw ConfigFileError(RTCStringFmt("Unknown encoding \"%s\"", pcszEnc));
     800        }
     801    }
     802
     803
     804    /* value may be omitted for OptNoValue options like rapid commit */
     805    RTCString strValue;
     806    option->getAttributeValue("value", &strValue);
     807
     808    /* XXX: TODO: encoding, handle hex */
     809    DhcpOption *opt = DhcpOption::parse(u8Opt, u32Enc, strValue.c_str());
     810    if (opt == NULL)
     811        throw ConfigFileError(RTCStringFmt("Bad option \"%s\"", strName.c_str()));
     812
     813    optmap << opt;
    264814}
    265815
     
    273823    int rc;
    274824
     825    if (m_strNetwork.empty())
     826        return;
     827
    275828    char szBaseName[RTPATH_MAX];
    276829    rc = RTStrCopy(szBaseName, sizeof(szBaseName), m_strNetwork.c_str());
     
    296849    optmap_t optmap;
    297850
    298     fillDefaultOptions(optmap, reqOpts);
    299     fillVendorOptions(optmap, reqOpts, vendor);
    300     fillHostOptions(optmap, reqOpts, id);
     851    const optmap_t *vmopts = NULL;
     852    vmmap_t::const_iterator vmit( m_VMMap.find(id.mac()) );
     853    if (vmit != m_VMMap.end())
     854        vmopts = &vmit->second;
     855
     856    RT_NOREF(vendor); /* not yet */
     857
     858
     859    optmap << new OptSubnetMask(m_IPv4Netmask);
     860
     861    for (auto optreq: reqOpts.value())
     862    {
     863        std::cout << ">>> requested option " << (int)optreq << std::endl;
     864
     865        if (optreq == OptSubnetMask::optcode)
     866        {
     867            std::cout << "... always supplied" << std::endl;
     868            continue;
     869        }
     870
     871        if (vmopts != NULL)
     872        {
     873            optmap_t::const_iterator it( vmopts->find(optreq) );
     874            if (it != vmopts->end())
     875            {
     876                optmap << it->second;
     877                std::cout << "... found in VM options" << std::endl;
     878                continue;
     879            }
     880        }
     881
     882        optmap_t::const_iterator it( m_GlobalOptions.find(optreq) );
     883        if (it != m_GlobalOptions.end())
     884        {
     885            optmap << it->second;
     886            std::cout << "... found in global options" << std::endl;
     887            continue;
     888        }
     889
     890        // std::cout << "... not found" << std::endl;
     891    }
     892
     893
     894    /* XXX: testing ... */
     895    if (vmopts != NULL)
     896    {
     897        for (auto it: *vmopts) {
     898            std::shared_ptr<DhcpOption> opt(it.second);
     899            if (optmap.count(opt->optcode()) == 0 && opt->optcode() > 127)
     900            {
     901                optmap << opt;
     902                std::cout << "... forcing VM option " << (int)opt->optcode() << std::endl;
     903            }
     904        }
     905    }
     906
     907    for (auto it: m_GlobalOptions) {
     908        std::shared_ptr<DhcpOption> opt(it.second);
     909        if (optmap.count(opt->optcode()) == 0 && opt->optcode() > 127)
     910        {
     911            optmap << opt;
     912            std::cout << "... forcing global option " << (int)opt->optcode() << std::endl;
     913        }
     914    }
    301915
    302916    return optmap;
    303917}
    304 
    305 
    306 void Config::fillDefaultOptions(optmap_t &optmap,
    307                                 const OptParameterRequest &reqOpts) const
    308 {
    309     RT_NOREF(reqOpts);
    310 
    311     optmap << new OptSubnetMask(m_IPv4Netmask);
    312 }
    313 
    314 
    315 void Config::fillHostOptions(optmap_t &optmap,
    316                              const OptParameterRequest &reqOpts,
    317                              const ClientId &id) const
    318 {
    319     /* not yet */
    320     RT_NOREF(optmap, reqOpts, id);
    321 }
    322 
    323 
    324 void Config::fillVendorOptions(optmap_t &optmap,
    325                                const OptParameterRequest &reqOpts,
    326                                const OptVendorClassId &vendor) const
    327 {
    328     if (!vendor.present())
    329         return;
    330 
    331     /* may be some day... */
    332     RT_NOREF(optmap, reqOpts);
    333 }
  • trunk/src/VBox/NetworkServices/Dhcpd/Config.h

    r71353 r71689  
    2121#include <iprt/types.h>
    2222#include <iprt/net.h>
     23#include <iprt/cpp/xml.h>
    2324
    2425#include <VBox/intnet.h>
     
    3334class Config
    3435{
    35     std::string m_strHome;
     36    /* XXX: TODO: also store fixed address assignments, etc? */
     37    typedef std::map<RTMAC, optmap_t> vmmap_t;
     38
     39    std::string m_strHome;   /* path of ~/.VirtualBox or equivalent */
    3640
    3741    std::string m_strNetwork;
     
    4953    RTNETADDRIPV4 m_IPv4PoolLast;
    5054
     55    optmap_t m_GlobalOptions;
     56    vmmap_t m_VMMap;
     57
    5158private:
    52     bool isSane();
     59    Config();
     60
     61    int init();
     62    int homeInit();
     63    int logInit();
     64    int complete();
    5365
    5466public: /* factory methods */
     
    5870
    5971public: /* accessors */
    60     void setHome(const std::string &strHome) { m_strHome = strHome; }
     72    const std::string &getHome() const { return m_strHome; }
    6173
    62     const std::string &getHome() const { return m_strHome; }
    6374    const std::string &getNetwork() const { return m_strNetwork; }
     75    void setNetwork(const std::string &aStrNetwork);
     76
    6477    const std::string &getBaseName() const { return m_strBaseName; }
    6578    const std::string &getTrunk() const { return m_strTrunk; }
     
    8093private:
    8194    static Config *read(const char *pszFileName);
     95    void parseConfig(const xml::ElementNode *root);
     96    void parseServer(const xml::ElementNode *server);
     97    void parseGlobalOptions(const xml::ElementNode *options);
     98    void parseVMConfig(const xml::ElementNode *config);
     99    void parseOption(const xml::ElementNode *option, optmap_t &optmap);
     100
     101    int parseMACAddress(RTMAC &aMac, const RTCString &aStr);
     102    int parseClientId(OptClientId &aId, const RTCString &aStr);
    82103
    83104    void sanitizeBaseName();
    84 
    85     void fillDefaultOptions(optmap_t &optmap,
    86                             const OptParameterRequest &reqOpts) const;
    87     void fillVendorOptions(optmap_t &optmap,
    88                            const OptParameterRequest &reqOpts,
    89                            const OptVendorClassId &vendor) const;
    90     void fillHostOptions(optmap_t &optmap,
    91                          const OptParameterRequest &reqOpts,
    92                          const ClientId &id) const;
    93105};
    94106
  • trunk/src/VBox/NetworkServices/Dhcpd/Db.cpp

    r71516 r71689  
    1818#include <iprt/err.h>
    1919#include <iprt/stream.h>
    20 
    21 #include <algorithm>
    22 #include <functional>
    2320
    2421#include "Db.h"
     
    340337    }
    341338}
    342 
    343 
    344 Binding *Db::bindingById(const ClientId &id) const
    345 {
    346     struct ClientMatch : public Binding::Match {
    347         const ClientId &m_id;
    348         ClientMatch(const ClientId &id) : m_id(id) {}
    349 
    350         bool operator()(const Binding *b)
    351         {
    352             return b->m_id == m_id;
    353         }
    354     };
    355 
    356     bindings_t::const_iterator found =
    357         std::find_if(m_bindings.begin(), m_bindings.end(),
    358                      ClientMatch(id));
    359 
    360     if (found == m_bindings.end())
    361         return NULL;
    362 
    363     Binding *b = *found;
    364     return b;
    365 }
    366 
    367 
    368 Binding *Db::bindingByAddr(RTNETADDRIPV4 addr) const
    369 {
    370     struct AddrMatch : public Binding::Match {
    371         const RTNETADDRIPV4 m_addr;
    372         AddrMatch(RTNETADDRIPV4 addr) : m_addr(addr) {}
    373 
    374         bool operator()(const Binding *b)
    375         {
    376             return b->m_addr.u == m_addr.u;
    377         }
    378     };
    379 
    380     bindings_t::const_iterator found =
    381         std::find_if(m_bindings.begin(), m_bindings.end(),
    382                      AddrMatch(addr));
    383 
    384     if (found == m_bindings.end())
    385         return NULL;
    386 
    387     Binding *b = *found;
    388     return b;
    389 }
    390 
    391339
    392340
  • trunk/src/VBox/NetworkServices/Dhcpd/Db.h

    r70836 r71689  
    3939public:
    4040    enum State { FREE, RELEASED, EXPIRED, OFFERED, ACKED };
    41 
    42     typedef std::unary_function<const Binding *, bool> Match;
    4341
    4442private:
     
    136134    bool addressBelongs(RTNETADDRIPV4 addr) const { return m_pool.contains(addr); }
    137135
    138     Binding *bindingById(const ClientId &id) const;
    139     Binding *bindingByAddr(RTNETADDRIPV4 addr) const;
    140 
    141136    Binding *allocateBinding(const DhcpClientMessage &req);
    142137    bool releaseBinding(const DhcpClientMessage &req);
  • trunk/src/VBox/NetworkServices/Dhcpd/DhcpOptions.cpp

    r70836 r71689  
    4848
    4949
     50int DhcpOption::encode(octets_t &dst) const
     51{
     52    if (!m_fPresent)
     53        return VERR_INVALID_STATE;
     54
     55    size_t cbOrig = dst.size();
     56
     57    append(dst, m_OptCode);
     58    appendLength(dst, 0);  /* placeholder */
     59
     60    ssize_t cbValue = encodeValue(dst);
     61    if (cbValue < 0 || UINT8_MAX <= cbValue)
     62    {
     63        dst.resize(cbOrig); /* undo */
     64        return VERR_INVALID_PARAMETER;
     65    }
     66
     67    dst[cbOrig+1] = cbValue;
     68    return VINF_SUCCESS;
     69}
     70
     71
     72/* static */
     73const octets_t *DhcpOption::findOption(const rawopts_t &aOptMap, uint8_t aOptCode)
     74{
     75    rawopts_t::const_iterator it(aOptMap.find(aOptCode));
     76    if (it == aOptMap.end())
     77        return NULL;
     78
     79    return &it->second;
     80}
     81
     82
    5083int DhcpOption::decode(const rawopts_t &map)
    5184{
     
    6699    return decode(req.rawopts());
    67100}
     101
     102
     103int DhcpOption::parse1(uint8_t &aValue, const char *pcszValue)
     104{
     105    int rc = RTStrToUInt8Full(RTStrStripL(pcszValue), 10, &aValue);
     106
     107    if (rc == VERR_TRAILING_SPACES)
     108        rc = VINF_SUCCESS;
     109    return rc;
     110}
     111
     112
     113int DhcpOption::parse1(uint16_t &aValue, const char *pcszValue)
     114{
     115    int rc = RTStrToUInt16Full(RTStrStripL(pcszValue), 10, &aValue);
     116
     117    if (rc == VERR_TRAILING_SPACES)
     118        rc = VINF_SUCCESS;
     119    return rc;
     120}
     121
     122
     123int DhcpOption::parse1(uint32_t &aValue, const char *pcszValue)
     124{
     125    int rc = RTStrToUInt32Full(RTStrStripL(pcszValue), 10, &aValue);
     126
     127    if (rc == VERR_TRAILING_SPACES)
     128        rc = VINF_SUCCESS;
     129    return rc;
     130}
     131
     132
     133int DhcpOption::parse1(RTNETADDRIPV4 &aValue, const char *pcszValue)
     134{
     135    return RTNetStrToIPv4Addr(pcszValue, &aValue);
     136}
     137
     138
     139int DhcpOption::parseList(std::vector<RTNETADDRIPV4> &aList, const char *pcszValue)
     140{
     141    std::vector<RTNETADDRIPV4> l;
     142    int rc;
     143
     144    pcszValue = RTStrStripL(pcszValue);
     145    do {
     146        RTNETADDRIPV4 Addr;
     147        char *pszNext;
     148
     149        rc = RTNetStrToIPv4AddrEx(pcszValue, &Addr, &pszNext);
     150        if (RT_FAILURE(rc))
     151            return VERR_INVALID_PARAMETER;
     152
     153        if (rc == VWRN_TRAILING_CHARS)
     154        {
     155            pcszValue = RTStrStripL(pszNext);
     156            if (pcszValue == pszNext) /* garbage after address */
     157                return VERR_INVALID_PARAMETER;
     158        }
     159
     160        l.push_back(Addr);
     161
     162        /*
     163         * If we got VINF_SUCCESS or VWRN_TRAILING_SPACES then this
     164         * was the last address and we are done.
     165         */
     166    } while (rc == VWRN_TRAILING_CHARS);
     167
     168    aList.swap(l);
     169    return VINF_SUCCESS;
     170}
     171
     172
     173/*
     174 * XXX: See DHCPServer::encodeOption()
     175 */
     176int DhcpOption::parseHex(octets_t &aRawValue, const char *pcszValue)
     177{
     178    octets_t data;
     179    char *pszNext;
     180    int rc;
     181
     182    if (pcszValue == NULL || *pcszValue == '\0')
     183        return VERR_INVALID_PARAMETER;
     184
     185    while (*pcszValue != '\0')
     186    {
     187        if (data.size() > UINT8_MAX)
     188            return VERR_INVALID_PARAMETER;
     189
     190        uint8_t u8Byte;
     191        rc = RTStrToUInt8Ex(pcszValue, &pszNext, 16, &u8Byte);
     192        if (!RT_SUCCESS(rc))
     193            return rc;
     194
     195        if (*pszNext == ':')
     196            ++pszNext;
     197        else if (*pszNext != '\0')
     198            return VERR_PARSE_ERROR;
     199
     200        data.push_back(u8Byte);
     201        pcszValue = pszNext;
     202    }
     203
     204    aRawValue.swap(data);
     205    return VINF_SUCCESS;
     206}
     207
     208
     209DhcpOption *DhcpOption::parse(uint8_t aOptCode, int aEnc, const char *pcszValue)
     210{
     211    switch (aEnc)
     212    {
     213    case 0: /* DhcpOptEncoding_Legacy */
     214        switch (aOptCode)
     215        {
     216#define HANDLE(_OptClass)                               \
     217            case _OptClass::optcode:                    \
     218                return _OptClass::parse(pcszValue);
     219
     220        HANDLE(OptSubnetMask);
     221        HANDLE(OptRouter);
     222        HANDLE(OptDNS);
     223        HANDLE(OptHostName);
     224        HANDLE(OptDomainName);
     225        HANDLE(OptRootPath);
     226        HANDLE(OptLeaseTime);
     227        HANDLE(OptRenewalTime);
     228        HANDLE(OptRebindingTime);
     229
     230#undef HANDLE
     231        default:
     232            return NULL;
     233        }
     234        break;
     235
     236    case 1:
     237        return RawOption::parse(aOptCode, pcszValue);
     238
     239    default:
     240        return NULL;
     241    }
     242}
  • trunk/src/VBox/NetworkServices/Dhcpd/DhcpOptions.h

    r70836 r71689  
    5151    virtual ~DhcpOption() {}
    5252
    53   protected:
    54     virtual ssize_t encodeValue(octets_t &data) const = 0;
    55     virtual int decodeValue(const octets_t &data, size_t cb) = 0;
     53  public:
     54    static DhcpOption *parse(uint8_t aOptCode, int aEnc, const char *pcszValue);
    5655
    5756  public:
    5857    uint8_t optcode() const { return m_OptCode; }
    59 
    6058    bool present() const { return m_fPresent; }
    6159
    62     int encode(octets_t &data) const
    63     {
    64         if (!m_fPresent)
    65             return VERR_INVALID_STATE;
    66 
    67         size_t cbOrig = data.size();
    68 
    69         append(data, m_OptCode);
    70         appendLength(data, 0);  /* placeholder */
    71 
    72         ssize_t cbValue = encodeValue(data);
    73         if (cbValue < 0 || UINT8_MAX <= cbValue)
    74         {
    75             data.resize(cbOrig); /* undo */
    76             return VERR_INVALID_PARAMETER;
    77         }
    78 
    79         data[cbOrig+1] = cbValue;
    80         return VINF_SUCCESS;
    81     }
    82 
    83     int testEncodeValue(octets_t &data) const /* XXX */
    84     {
    85         if (!m_fPresent)
    86             return VERR_INVALID_STATE;
    87 
    88         return encodeValue(data) >= 0 ? VINF_SUCCESS : VERR_INVALID_PARAMETER;
    89     }
    90 
    91   public:
     60  public:
     61    int encode(octets_t &dst) const;
     62
    9263    int decode(const rawopts_t &map);
    9364    int decode(const DhcpClientMessage &req);
    9465
    95 
    96   protected:
    97     static const octets_t *findOption(const rawopts_t &aOptMap, uint8_t aOptCode)
    98     {
    99         rawopts_t::const_iterator it(aOptMap.find(aOptCode));
    100         if (it == aOptMap.end())
    101             return NULL;
    102 
    103         return &it->second;
    104     }
     66  protected:
     67    virtual ssize_t encodeValue(octets_t &dst) const = 0;
     68    virtual int decodeValue(const octets_t &src, size_t cb) = 0;
     69
     70  protected:
     71    static const octets_t *findOption(const rawopts_t &aOptMap, uint8_t aOptCode);
    10572
    10673  protected:
     
    10875     * Serialization
    10976     */
    110     static void append(octets_t &aData, uint8_t aValue)
    111     {
    112         aData.push_back(aValue);
    113     }
    114 
    115     static void append(octets_t &aData, uint16_t aValue)
     77    static void append(octets_t &aDst, uint8_t aValue)
     78    {
     79        aDst.push_back(aValue);
     80    }
     81
     82    static void append(octets_t &aDst, uint16_t aValue)
    11683    {
    11784        RTUINT16U u16 = { RT_H2N_U16(aValue) };
    118         aData.insert(aData.end(), u16.au8, u16.au8 + sizeof(aValue));
    119     }
    120 
    121     static void append(octets_t &aData, uint32_t aValue)
     85        aDst.insert(aDst.end(), u16.au8, u16.au8 + sizeof(aValue));
     86    }
     87
     88    static void append(octets_t &aDst, uint32_t aValue)
    12289    {
    12390        RTUINT32U u32 = { RT_H2N_U32(aValue) };
    124         aData.insert(aData.end(), u32.au8, u32.au8 + sizeof(aValue));
    125     }
    126 
    127     static void append(octets_t &aData, RTNETADDRIPV4 aIPv4)
    128     {
    129         aData.insert(aData.end(), aIPv4.au8, aIPv4.au8 + sizeof(aIPv4));
    130     }
    131 
    132     static void append(octets_t &aData, const char *pszString, size_t cb)
    133     {
    134         aData.insert(aData.end(), pszString, pszString + cb);
    135     }
    136 
    137     static void append(octets_t &aData, const std::string &str)
    138     {
    139         append(aData, str.c_str(), str.size());
     91        aDst.insert(aDst.end(), u32.au8, u32.au8 + sizeof(aValue));
     92    }
     93
     94    static void append(octets_t &aDst, RTNETADDRIPV4 aIPv4)
     95    {
     96        aDst.insert(aDst.end(), aIPv4.au8, aIPv4.au8 + sizeof(aIPv4));
     97    }
     98
     99    static void append(octets_t &aDst, const char *pszString, size_t cb)
     100    {
     101        aDst.insert(aDst.end(), pszString, pszString + cb);
     102    }
     103
     104    static void append(octets_t &aDst, const std::string &str)
     105    {
     106        append(aDst, str.c_str(), str.size());
    140107    }
    141108
    142109    /* non-overloaded name to avoid ambiguity */
    143     static void appendLength(octets_t &aData, size_t cb)
    144     {
    145         append(aData, static_cast<uint8_t>(cb));
     110    static void appendLength(octets_t &aDst, size_t cb)
     111    {
     112        append(aDst, static_cast<uint8_t>(cb));
    146113    }
    147114
     
    183150        pos += cb;
    184151    }
    185 };
    186 
    187 
    188 inline octets_t &operator<<(octets_t &data, const DhcpOption &option)
    189 {
    190     option.encode(data);
    191     return data;
     152
     153
     154    /*
     155     * Parse textual representation (e.g. in config file)
     156     */
     157    static int parse1(uint8_t &aValue, const char *pcszValue);
     158    static int parse1(uint16_t &aValue, const char *pcszValue);
     159    static int parse1(uint32_t &aValue, const char *pcszValue);
     160    static int parse1(RTNETADDRIPV4 &aValue, const char *pcszValue);
     161
     162    static int parseList(std::vector<RTNETADDRIPV4> &aList, const char *pcszValue);
     163
     164    static int parseHex(octets_t &aRawValue, const char *pcszValue);
     165};
     166
     167
     168inline octets_t &operator<<(octets_t &dst, const DhcpOption &option)
     169{
     170    option.encode(dst);
     171    return dst;
    192172}
    193173
     
    202182 */
    203183struct OptEnd {};
    204 inline octets_t &operator<<(octets_t &data, const OptEnd &end)
     184inline octets_t &operator<<(octets_t &dst, const OptEnd &end)
    205185{
    206186    RT_NOREF(end);
    207187
    208     data.push_back(RTNET_DHCP_OPT_END);
    209     return data;
     188    dst.push_back(RTNET_DHCP_OPT_END);
     189    return dst;
    210190}
    211191
     
    225205      : DhcpOption(aOptCode, fPresent) {}
    226206
    227     explicit OptNoValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
     207    OptNoValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
    228208      : DhcpOption(aOptCode, false)
    229209    {
     
    237217
    238218  protected:
    239     virtual ssize_t encodeValue(octets_t &data) const
    240     {
    241         RT_NOREF(data);
     219    virtual ssize_t encodeValue(octets_t &dst) const
     220    {
     221        RT_NOREF(dst);
    242222        return 0;
    243223    }
     
    249229    }
    250230
    251     virtual int decodeValue(const octets_t &data, size_t cb)
    252     {
    253         RT_NOREF(data);
     231    virtual int decodeValue(const octets_t &src, size_t cb)
     232    {
     233        RT_NOREF(src);
    254234
    255235        if (!isLengthValid(cb))
     
    299279      : DhcpOption(aOptCode), m_Value(aOptValue) {}
    300280
    301     explicit OptValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
     281    OptValueBase(uint8_t aOptCode, const DhcpClientMessage &req)
    302282      : DhcpOption(aOptCode, false), m_Value()
    303283    {
     
    316296
    317297  protected:
    318     virtual ssize_t encodeValue(octets_t &data) const
    319     {
    320         append(data, m_Value);
     298    virtual ssize_t encodeValue(octets_t &dst) const
     299    {
     300        append(dst, m_Value);
    321301        return sizeof(T);
    322302    }
     
    328308    }
    329309
    330     virtual int decodeValue(const octets_t &data, size_t cb)
     310    virtual int decodeValue(const octets_t &src, size_t cb)
    331311    {
    332312        if (!isLengthValid(cb))
    333313            return VERR_INVALID_PARAMETER;
    334314
    335         octets_t::const_iterator pos(data.begin());
     315        octets_t::const_iterator pos(src.begin());
    336316        extract(m_Value, pos);
    337317
     
    346326{
    347327  public:
     328    using typename OptValueBase<T>::value_t;
     329
     330  public:
    348331    static const uint8_t optcode = _OptCode;
    349332
     
    356339    explicit OptValue(const DhcpClientMessage &req)
    357340      : OptValueBase<T>(optcode, req) {}
     341
     342    static OptValue *parse(const char *pcszValue)
     343    {
     344        value_t v;
     345        int rc = DhcpOption::parse1(v, pcszValue);
     346        if (RT_FAILURE(rc))
     347            return NULL;
     348        return new OptValue(v);
     349    }
    358350};
    359351
     
    372364    std::string m_String;
    373365
    374     OptStringBase(uint8_t aOptCode)
     366    explicit OptStringBase(uint8_t aOptCode)
    375367      : DhcpOption(aOptCode, false), m_String() {}
    376368
    377     explicit OptStringBase(uint8_t aOptCode, const std::string &aOptString)
     369    OptStringBase(uint8_t aOptCode, const std::string &aOptString)
    378370      : DhcpOption(aOptCode), m_String(aOptString) {}
    379371
    380     explicit OptStringBase(uint8_t aOptCode, const DhcpClientMessage &req)
     372    OptStringBase(uint8_t aOptCode, const DhcpClientMessage &req)
    381373      : DhcpOption(aOptCode, false), m_String()
    382374    {
     
    395387
    396388  protected:
    397     virtual ssize_t encodeValue(octets_t &data) const
     389    virtual ssize_t encodeValue(octets_t &dst) const
    398390    {
    399391        if (!isLengthValid(m_String.size()))
    400392            return -1;
    401393
    402         append(data, m_String);
     394        append(dst, m_String);
    403395        return m_String.size();
    404396    }
     
    410402    }
    411403
    412     virtual int decodeValue(const octets_t &data, size_t cb)
     404    virtual int decodeValue(const octets_t &src, size_t cb)
    413405    {
    414406        if (!isLengthValid(cb))
    415407            return VERR_INVALID_PARAMETER;
    416408
    417         octets_t::const_iterator pos(data.begin());
     409        octets_t::const_iterator pos(src.begin());
    418410        extract(m_String, pos, cb);
    419411        m_fPresent = true;
     
    437429    explicit OptString(const DhcpClientMessage &req)
    438430      : OptStringBase(optcode, req) {}
     431
     432    static OptString *parse(const char *pcszValue)
     433    {
     434        return new OptString(pcszValue);
     435    }
    439436};
    440437
     
    463460      : DhcpOption(aOptCode), m_List(aOptList) {}
    464461
    465     explicit OptListBase(uint8_t aOptCode, const DhcpClientMessage &req)
     462    OptListBase(uint8_t aOptCode, const DhcpClientMessage &req)
    466463      : DhcpOption(aOptCode, false), m_List()
    467464    {
     
    480477
    481478  protected:
    482     virtual ssize_t encodeValue(octets_t &data) const
     479    virtual ssize_t encodeValue(octets_t &dst) const
    483480    {
    484481        const size_t cbItem = sizeof(T);
     
    490487                break;
    491488
    492             append(data, m_List[i]);
     489            append(dst, m_List[i]);
    493490            cbValue += cbItem;
    494491        }
     
    503500    }
    504501
    505     virtual int decodeValue(const octets_t &data, size_t cb)
     502    virtual int decodeValue(const octets_t &src, size_t cb)
    506503    {
    507504        if (!isLengthValid(cb))
     
    510507        m_List.erase(m_List.begin(), m_List.end());
    511508
    512         octets_t::const_iterator pos(data.begin());
     509        octets_t::const_iterator pos(src.begin());
    513510        for (size_t i = 0; i < cb / sizeof(T); ++i)
    514511        {
     
    528525{
    529526  public:
     527    using typename OptListBase<T>::value_t;
     528
     529  public:
    530530    static const uint8_t optcode = _OptCode;
    531531
     
    536536      : OptListBase<T>(optcode, aOptSingle) {}
    537537
    538     OptList(const std::vector<T> &aOptList)
     538    explicit OptList(const std::vector<T> &aOptList)
    539539      : OptListBase<T>(optcode, aOptList) {}
    540540
    541541    explicit OptList(const DhcpClientMessage &req)
    542542      : OptListBase<T>(optcode, req) {}
     543
     544    static OptList *parse(const char *pcszValue)
     545    {
     546        value_t v;
     547        int rc = DhcpOption::parseList(v, pcszValue);
     548        if (RT_FAILURE(rc) || v.empty())
     549            return NULL;
     550        return new OptList(v);
     551    }
     552};
     553
     554
     555/*
     556 * Options specified by raw binary data that we don't know how to
     557 * interpret.
     558 */
     559class RawOption
     560  : public DhcpOption
     561{
     562  protected:
     563    octets_t m_Data;
     564
     565  public:
     566    explicit RawOption(uint8_t aOptCode)
     567      : DhcpOption(aOptCode, false), m_Data() {}
     568
     569    RawOption(uint8_t aOptCode, const octets_t &aSrc)
     570      : DhcpOption(aOptCode), m_Data(aSrc) {}
     571
     572  public:
     573    virtual RawOption *clone() const
     574    {
     575        return new RawOption(*this);
     576    }
     577
     578
     579  protected:
     580    virtual ssize_t encodeValue(octets_t &dst) const
     581    {
     582        dst.insert(dst.end(), m_Data.begin(), m_Data.end());
     583        return m_Data.size();
     584    }
     585
     586    virtual int decodeValue(const octets_t &src, size_t cb)
     587    {
     588        octets_t::const_iterator beg(src.begin());
     589        octets_t data(beg, beg + cb);
     590        m_Data.swap(data);
     591
     592        m_fPresent = true;
     593        return VINF_SUCCESS;
     594    }
     595
     596  public:
     597    static RawOption *parse(uint8_t aOptCode, const char *pcszValue)
     598    {
     599        octets_t data;
     600        int rc = DhcpOption::parseHex(data, pcszValue);
     601        if (RT_FAILURE(rc))
     602            return NULL;
     603        return new RawOption(aOptCode, data);
     604    }
    543605};
    544606
  • trunk/src/VBox/NetworkServices/Dhcpd/VBoxNetDhcpd.cpp

    r71353 r71689  
    3333#include <VBox/intnetinline.h>
    3434
    35 #include <VBox/com/com.h>
    36 
    3735#include "VBoxLwipCore.h"
    3836#include "Config.h"
     
    7371
    7472private:
     73    PRTLOGGER m_pStderrReleaseLogger;
     74
    7575    /* intnet plumbing */
    7676    PSUPDRVSESSION m_pSession;
     
    8181    struct netif m_LwipNetif;
    8282
    83     /* path of ~/.VirtualBox or equivalent */
    84     std::string m_strHome;
    85 
    8683    Config *m_Config;
    8784
     
    9895
    9996private:
    100     void homeInit();
    101     int logInit(const std::string &strBaseName);
     97    int logInitStderr();
    10298
    10399    /*
     
    149145
    150146VBoxNetDhcpd::VBoxNetDhcpd()
    151   : m_pSession(NIL_RTR0PTR),
     147  : m_pStderrReleaseLogger(NULL),
     148    m_pSession(NIL_RTR0PTR),
    152149    m_hIf(INTNET_HANDLE_INVALID),
    153150    m_pIfBuf(NULL),
     
    158155    int rc;
    159156
     157    logInitStderr();
     158
    160159    rc = r3Init();
    161160    if (RT_FAILURE(rc))
     
    170169    ifClose();
    171170    r3Fini();
     171}
     172
     173
     174/*
     175 * We don't know the name of the release log file until we parse our
     176 * configuration because we use network name as basename.  To get
     177 * early logging to work, start with stderr-only release logger.
     178 *
     179 * We disable "sup" for this logger to avoid spam from SUPR3Init().
     180 */
     181int VBoxNetDhcpd::logInitStderr()
     182{
     183    static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
     184
     185    PRTLOGGER pLogger;
     186    int rc;
     187
     188    uint32_t fFlags = 0;
     189#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     190    fFlags |= RTLOGFLAGS_USECRLF;
     191#endif
     192
     193    rc = RTLogCreate(&pLogger, fFlags,
     194                     "all -sup all.restrict -default.restrict",
     195                     NULL,      /* environment base */
     196                     RT_ELEMENTS(s_apszGroups), s_apszGroups,
     197                     RTLOGDEST_STDERR, NULL);
     198    if (RT_FAILURE(rc))
     199    {
     200        RTPrintf("Failed to init stderr logger: %Rrs\n", rc);
     201        return rc;
     202    }
     203
     204    m_pStderrReleaseLogger = pLogger;
     205    RTLogRelSetDefaultInstance(m_pStderrReleaseLogger);
     206
     207    return VINF_SUCCESS;
    172208}
    173209
     
    260296    OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0';
    261297
    262     OpenReq.enmTrunkType = enmTrunkType;
     298    if (enmTrunkType != kIntNetTrunkType_Invalid)
     299        OpenReq.enmTrunkType = enmTrunkType;
     300    else
     301        OpenReq.enmTrunkType = kIntNetTrunkType_WhateverNone;
    263302
    264303    OpenReq.fFlags = 0;
     
    588627        return VERR_GENERAL_FAILURE;
    589628
    590     homeInit();
    591     m_Config->setHome(m_strHome);
    592 
    593     logInit(m_Config->getBaseName());
    594 
    595629    rc = m_server.init(m_Config);
    596630
     
    609643    ifPump();
    610644    return VINF_SUCCESS;
    611 }
    612 
    613 
    614 void VBoxNetDhcpd::homeInit()
    615 {
    616     int rc;
    617 
    618     /* pathname of ~/.VirtualBox or equivalent */
    619     char szHome[RTPATH_MAX];
    620     rc = com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome), false);
    621     if (RT_FAILURE(rc))
    622         return;
    623 
    624     m_strHome.assign(szHome);
    625 }
    626 
    627 
    628 int VBoxNetDhcpd::logInit(const std::string &strBaseName)
    629 {
    630     int rc;
    631     size_t cch;
    632 
    633     /* default log file name */
    634     char szLogFile[RTPATH_MAX];
    635     cch = RTStrPrintf(szLogFile, sizeof(szLogFile),
    636                       "%s%c%s-Dhcpd.log",
    637                       m_strHome.c_str(), RTPATH_DELIMITER, strBaseName.c_str());
    638     if (cch >= sizeof(szLogFile))
    639         return VERR_BUFFER_OVERFLOW;
    640 
    641 
    642     /* get a writable copy of the base name */
    643     char szBaseName[RTPATH_MAX];
    644     rc = RTStrCopy(szBaseName, sizeof(szBaseName), strBaseName.c_str());
    645     if (RT_FAILURE(rc))
    646         return rc;
    647 
    648     /* sanitize base name some more to be usable in an environment variable name */
    649     for (char *p = szBaseName; *p != '\0'; ++p)
    650     {
    651         if (   *p != '_'
    652             && (*p < '0' || '9' < *p)
    653             && (*p < 'a' || 'z' < *p)
    654             && (*p < 'A' || 'Z' < *p))
    655         {
    656             *p = '_';
    657         }
    658     }
    659 
    660 
    661     /* name of the environment variable to control logging */
    662     char szEnvVarBase[128];
    663     cch = RTStrPrintf(szEnvVarBase, sizeof(szEnvVarBase),
    664                       "VBOXDHCP_%s_RELEASE_LOG", szBaseName);
    665     if (cch >= sizeof(szEnvVarBase))
    666         return VERR_BUFFER_OVERFLOW;
    667 
    668 
    669     rc = com::VBoxLogRelCreate("DHCP Server",
    670                                szLogFile,
    671                                RTLOGFLAGS_PREFIX_TIME_PROG,
    672                                "all all.restrict -default.restrict",
    673                                szEnvVarBase,
    674                                RTLOGDEST_FILE
    675 #ifdef DEBUG
    676                                | RTLOGDEST_STDERR
    677 #endif
    678                                ,
    679                                32768 /* cMaxEntriesPerGroup */,
    680                                0 /* cHistory */,
    681                                0 /* uHistoryFileTime */,
    682                                0 /* uHistoryFileSize */,
    683                                NULL /* pErrInfo */);
    684 
    685     return rc;
    686645}
    687646
Note: See TracChangeset for help on using the changeset viewer.

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