VirtualBox

Changeset 17779 in vbox


Ignore:
Timestamp:
Mar 12, 2009 9:29:23 PM (16 years ago)
Author:
vboxsync
Message:

All but the reply...

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp

    r17770 r17779  
    174174            return 2;
    175175        }
     176
     177        if (RT_N2H_U32(m_UpperAddr.u) < RT_N2H_U32(m_LowerAddr.u))
     178        {
     179            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: The --upper-ip value is lower than the --lower-ip one!\n"
     180                                    "             %d.%d.%d.%d < %d.%d.%d.%d\n",
     181                         m_UpperAddr.au8[0], m_UpperAddr.au8[1], m_UpperAddr.au8[2], m_UpperAddr.au8[3],
     182                         m_LowerAddr.au8[0], m_LowerAddr.au8[1], m_LowerAddr.au8[2], m_LowerAddr.au8[3]);
     183            return 3;
     184        }
     185
     186        /* the code goes insane if we have too many atm. lazy bird */
     187        uint32_t cIPs = RT_N2H_U32(m_UpperAddr.u) - RT_N2H_U32(m_LowerAddr.u);
     188        if (cIPs > 1024)
     189        {
     190            RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: Too many IPs between --upper-ip and --lower-ip! %d (max 1024)\n"
     191                                    "             %d.%d.%d.%d < %d.%d.%d.%d\n",
     192                         cIPs,
     193                         m_UpperAddr.au8[0], m_UpperAddr.au8[1], m_UpperAddr.au8[2], m_UpperAddr.au8[3],
     194                         m_LowerAddr.au8[0], m_LowerAddr.au8[1], m_LowerAddr.au8[2], m_LowerAddr.au8[3]);
     195            return 3;
     196        }
    176197        return 0;
     198    }
     199
     200    /**
     201     * Is this config for one specific client?
     202     *
     203     * @return  true / false.
     204     */
     205    bool            isOneSpecificClient(void) const
     206    {
     207        return m_LowerAddr.u == m_UpperAddr.u
     208            && m_MacAddresses.size() > 0;
     209    }
     210
     211    /**
     212     * Checks if this config matches the specified MAC address.
     213     *
     214     * @returns true / false.
     215     *
     216     * @param   pMac    The MAC address to match.
     217     */
     218    bool            matchesMacAddress(PCRTMAC pMac) const
     219    {
     220        size_t i = m_MacAddresses.size();
     221        if (RT_LIKELY(i < 1))
     222            return true; /* no entries == ALL wildcard match */
     223
     224        while (i--)
     225        {
     226            PCRTMAC pCur = &m_MacAddresses[i];
     227            if (    pCur->au16[0] == pMac->au16[0]
     228                &&  pCur->au16[1] == pMac->au16[1]
     229                &&  pCur->au16[2] == pMac->au16[2])
     230                return true;
     231        }
     232        return false;
    177233    }
    178234
     
    187243    typedef enum State
    188244    {
     245        /** Invalid. */
     246        kState_Invalid = 0,
    189247        /** The lease is free / released. */
    190         kState_Free = 0,
     248        kState_Free,
    191249        /** An offer has been made.
    192250         * Expire time indicates when the offer expires. */
     
    196254        kState_Active
    197255    } State;
    198 
    199     void            offer(uint32_t xid);
    200     void            activate(void);
    201     void            release(void);
    202256
    203257    /** The client MAC address. */
     
    214268    /** The configuration for this lease. */
    215269    VBoxNetDhcpCfg *m_pCfg;
     270
     271public:
     272    /** Constructor taking an IPv4 address and a Config. */
     273    VBoxNetDhcpLease(RTNETADDRIPV4 IPv4Addr, VBoxNetDhcpCfg *pCfg)
     274    {
     275        m_pCfg          = pCfg;
     276        m_IPv4Address   = IPv4Addr;
     277
     278        m_MacAddress.au16[0] = m_MacAddress.au16[1] =  m_MacAddress.au16[2] = 0xff;
     279        m_enmState      = kState_Free;
     280        RTTimeSpecSetSeconds(&m_ExpireTime, 0);
     281        m_xid           = UINT32_MAX;
     282    }
     283
     284    /** Destructor.  */
     285    ~VBoxNetDhcpLease()
     286    {
     287        m_IPv4Address.u = UINT32_MAX;
     288        m_pCfg          = NULL;
     289        m_MacAddress.au16[0] = m_MacAddress.au16[1] =  m_MacAddress.au16[2] = 0xff;
     290        m_enmState      = kState_Free;
     291        m_xid           = UINT32_MAX;
     292    }
     293
     294    void            offer(uint32_t xid);
     295    void            activate(void);
     296    void            activate(uint32_t xid);
     297    void            release(void);
     298    bool            hasExpired(void) const;
     299
     300    /**
     301     * Checks if the lease is in use or not.
     302     *
     303     * @returns true if active, false if free or expired.
     304     *
     305     * @param   pNow        The current time to use. Optional.
     306     */
     307    bool            isInUse(PCRTTIMESPEC pNow = NULL) const
     308    {
     309        if  (   m_enmState == kState_Offer
     310             || m_enmState == kState_Active)
     311        {
     312            RTTIMESPEC Now;
     313            if (!pNow)
     314                pNow = RTTimeNow(&Now);
     315            return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(pNow);
     316        }
     317        return false;
     318    }
     319
     320    /**
     321     * Is this lease for one specific client?
     322     *
     323     * @return  true/false.
     324     */
     325    bool            isOneSpecificClient(void) const
     326    {
     327        return m_pCfg
     328            && m_pCfg->isOneSpecificClient();
     329    }
     330
     331    /**
     332     * Is this lease currently being offered to a client.
     333     *
     334     * @returns true / false.
     335     */
     336    bool            isBeingOffered(void) const
     337    {
     338        return m_enmState == kState_Offer
     339            && isInUse();
     340    }
     341
     342    /**
     343     * Is the lease in the current config or not.
     344     *
     345     * When updating the config we might leave active leases behind which aren't
     346     * included in the new config. These will have m_pCfg set to NULL and should be
     347     * freed up when they expired.
     348     *
     349     * @returns true / false.
     350     */
     351    bool            isInCurrentConfig(void) const
     352    {
     353        return m_pCfg != NULL;
     354    }
    216355};
    217356
     
    231370protected:
    232371    int                 addConfig(VBoxNetDhcpCfg *pCfg);
     372    void                explodeConfig(void);
     373
    233374    bool                handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb);
    234375    bool                handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb);
     
    238379    void                makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb);
    239380
    240     VBoxNetDhcpLease   *findLeaseByMacAddress(PCRTMAC pMacAddress, bool fEnsureUpToDateConfig);
     381    VBoxNetDhcpLease   *findLeaseByMacAddress(PCRTMAC pMacAddress);
    241382    VBoxNetDhcpLease   *findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress);
    242383    VBoxNetDhcpLease   *newLease(PCRTNETBOOTP pDhcpMsg, size_t cb);
    243     void                updateLeaseConfig(VBoxNetDhcpLease *pLease);
    244384
    245385    static uint8_t const *findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, size_t *pcbMaxOpt);
     
    260400
    261401    /** The current configs. */
    262     std::vector<VBoxNetDhcpCfg> m_Cfgs;
     402    std::vector<VBoxNetDhcpCfg *> m_Cfgs;
    263403
    264404    /** The current leases. */
     
    317457
    318458/**
     459 * Activate this lease with a new transaction ID.
     460 *
     461 * @param   xid     The transaction ID.
     462 * @todo    check if this is really necessary.
     463 */
     464void VBoxNetDhcpLease::activate(uint32_t xid)
     465{
     466    activate();
     467    m_xid = xid;
     468}
     469
     470
     471/**
    319472 * Release a lease either upon client request or because it didn't quite match a
    320473 * DHCP_REQUEST.
     
    326479    RTTimeSpecAddSeconds(&m_ExpireTime, 5);
    327480}
     481
     482
     483/**
     484 * Checks if the lease has expired or not.
     485 *
     486 * This just checks the expiration time not the state. This is so that this
     487 * method will work for reusing RELEASEd leases when the client comes back after
     488 * a reboot or ipconfig /renew. Callers not interested in info on released
     489 * leases should check the state first.
     490 *
     491 * @returns true if expired, false if not.
     492 */
     493bool VBoxNetDhcpLease::hasExpired() const
     494{
     495    RTTIMESPEC Now;
     496    return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(RTTimeNow(&Now));
     497}
     498
    328499
    329500
     
    357528
    358529#if 1 /* while hacking. */
    359     VBoxNetDhcpCfg DefCfg;
    360     DefCfg.m_LowerAddr.u    = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,100)));
    361     DefCfg.m_UpperAddr.u    = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,250)));
    362     DefCfg.m_SubnetMask.u   = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8(255,255,255,  0)));
     530    VBoxNetDhcpCfg *pDefCfg = new VBoxNetDhcpCfg();
     531    pDefCfg->m_LowerAddr.u    = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,100)));
     532    pDefCfg->m_UpperAddr.u    = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,250)));
     533    pDefCfg->m_SubnetMask.u   = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8(255,255,255,  0)));
    363534    RTNETADDRIPV4 Addr;
    364     Addr.u                  = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,  1)));
    365     DefCfg.m_Routers.push_back(Addr);
    366     Addr.u                  = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,  2)));
    367     DefCfg.m_DNSes.push_back(Addr);
    368     DefCfg.m_DomainName     = "vboxnetdhcp.org";
    369     DefCfg.m_cSecLease      = 60*60; /* 1 hour */
    370     DefCfg.m_TftpServer     = "10.0.2.3"; //??
     535    Addr.u                    = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,  1)));
     536    pDefCfg->m_Routers.push_back(Addr);
     537    Addr.u                    = RT_H2N_U32_C(RT_BSWAP_U32_C(RT_MAKE_U32_FROM_U8( 10,  0,  2,  2)));
     538    pDefCfg->m_DNSes.push_back(Addr);
     539    pDefCfg->m_DomainName     = "vboxnetdhcp.org";
     540    pDefCfg->m_cSecLease      = 60*60; /* 1 hour */
     541    pDefCfg->m_TftpServer     = "10.0.2.3"; //??
     542    this->addConfig(pDefCfg);
    371543#endif
    372544}
     
    415587        rc = pCfg->validate();
    416588        if (!rc)
    417             m_Cfgs.push_back(*pCfg);
    418         delete pCfg;
     589            m_Cfgs.push_back(pCfg);
     590        else
     591            delete pCfg;
    419592    }
    420593    return rc;
     594}
     595
     596
     597/**
     598 * Explodes the config into leases.
     599 *
     600 * @remarks     This code is brute force and not very fast nor memory efficient.
     601 *              We will have to revisit this later.
     602 *
     603 * @remarks     If an IP has been reconfigured for a fixed mac address and it's
     604 *              already leased to a client, we it won't be available until the
     605 *              client releases its lease or it expires.
     606 */
     607void VBoxNetDhcp::explodeConfig(void)
     608{
     609    RTTIMESPEC  Now;
     610    RTTimeNow(&Now);
     611
     612    /*
     613     * Remove all non-active leases from the vector and zapping the
     614     * config pointers of the once left behind.
     615     */
     616    std::vector<VBoxNetDhcpLease>::iterator Itr = m_Leases.begin();
     617    while (Itr != m_Leases.end())
     618    {
     619        if (!Itr->isInUse(&Now))
     620            Itr = m_Leases.erase(Itr);
     621        else
     622        {
     623            Itr->m_pCfg = NULL;
     624            Itr++;
     625        }
     626    }
     627
     628    /*
     629     * Loop thru the configurations in reverse order, giving the last
     630     * configs priority of the newer ones.
     631     */
     632    size_t iCfg = m_Cfgs.size();
     633    while (iCfg-- > 0)
     634    {
     635        VBoxNetDhcpCfg *pCfg = m_Cfgs[iCfg];
     636
     637        /* Expand the IP lease range. */
     638        uint32_t const uEnd = RT_N2H_U32(pCfg->m_UpperAddr.u);
     639        for (uint32_t i = RT_N2H_U32(pCfg->m_LowerAddr.u); i < uEnd; i++)
     640        {
     641            RTNETADDRIPV4 IPv4Addr;
     642            IPv4Addr.u = RT_H2N_U32(i);
     643
     644            /* Check if it exists and is configured. */
     645            VBoxNetDhcpLease *pLease = NULL;
     646            for (size_t i = 0; i < m_Leases.size(); i++)
     647                if (m_Leases[i].m_IPv4Address.u == IPv4Addr.u)
     648                {
     649                    pLease = &m_Leases[i];
     650                    break;
     651                }
     652            if (pLease)
     653            {
     654                if (!pLease->m_pCfg)
     655                    pLease->m_pCfg = pCfg;
     656            }
     657            else
     658            {
     659                /* add it. */
     660                VBoxNetDhcpLease NewLease(IPv4Addr, pCfg);
     661                m_Leases.push_back(NewLease);
     662                debugPrint(10, false, "exploseConfig: new lease %d.%d.%d.%d",
     663                           IPv4Addr.au8[0], IPv4Addr.au8[1], IPv4Addr.au8[2], IPv4Addr.au8[3]);
     664            }
     665        }
     666    }
    421667}
    422668
     
    499745                    {
    500746                        RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxDhcpCfg failed\n");
    501                         rc = 1;
    502                         break;
     747                        return 1;
    503748                    }
    504749                }
     
    525770                    default:
    526771                        AssertMsgFailed(("%d", rc));
    527                         rc = 1;
    528                         break;
     772                        return 1;
    529773                }
    530774                break;
     
    548792        }
    549793    }
     794
     795    /*
     796     * Do the reconfig. (move this later)
     797     */
     798    if (!rc)
     799        explodeConfig();
    550800
    551801    return rc;
     
    7791029     * If none was found, create a new lease for it and then construct a reply.
    7801030     */
    781     VBoxNetDhcpLease *pLease = findLeaseByMacAddress(&pDhcpMsg->bp_chaddr.Mac,
    782                                                      true /* fEnsureUpToDateConfig */);
    783     if (!pLease)
     1031    VBoxNetDhcpLease *pLease = findLeaseByMacAddress(&pDhcpMsg->bp_chaddr.Mac);
     1032    if (    !pLease
     1033        ||  !pLease->isInCurrentConfig())
    7841034        pLease = newLease(pDhcpMsg, cb);
    7851035    if (!pLease)
    7861036        return false;
     1037    debugPrint(1, true, "Offering %d.%d.%d.%d to %.6Rhxs xid=%#x",
     1038               pLease->m_IPv4Address.au8[0],
     1039               pLease->m_IPv4Address.au8[1],
     1040               pLease->m_IPv4Address.au8[2],
     1041               pLease->m_IPv4Address.au8[3],
     1042               &pDhcpMsg->bp_chaddr.Mac,
     1043               pDhcpMsg->bp_xid);
    7871044    pLease->offer(pDhcpMsg->bp_xid);
    7881045
     
    8041061    /** @todo Probably need to match the server IP here to work correctly with
    8051062     *        other servers. */
     1063    /** @todo check this against the RFC and real code. the code is kind of
     1064     *        fishy... */
    8061065
    8071066    /*
     
    8141073    {
    8151074        VBoxNetDhcpLease *pLease = findLeaseByIpv4AndMacAddresses(IPv4Addr, &pDhcpMsg->bp_chaddr.Mac);
    816         if (pLease)
    817         {
     1075        if (    pLease
     1076            &&  pLease->isInCurrentConfig())
     1077        {
     1078            if (pLease->isBeingOffered())
     1079                debugPrint(2, true, "REQUEST for offered lease.");
     1080            else
     1081                debugPrint(1, true, "REQUEST for lease not on offer.");
     1082
    8181083            /* Check if the xid matches, if it doesn't it's not our call. */
    8191084#if 0      /** @todo check how windows treats bp_xid here, it should match I think. If
     
    8321097             * Ack it.
    8331098             */
    834             pLease->activate();
     1099            pLease->activate(pDhcpMsg->bp_xid);
    8351100            makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb);
    8361101        }
     
    8471112            {
    8481113                /* ACK it. */
     1114                debugPrint(1, true, "REQUEST for lease not on offer, new lease matches.");
    8491115                pLease->activate();
    8501116                makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb);
     
    8531119            {
    8541120                /* NAK it */
     1121                debugPrint(1, true, "REQUEST for lease not on offer, NACnig it.");
    8551122                if (pLease)
    8561123                    pLease->release();
     
    12081475    bool optEnd(void)
    12091476    {
    1210         return hasOverflowed();
     1477        return !hasOverflowed();
    12111478    }
    12121479};
     
    12911558 * @returns Pointer to the lease if found, NULL if not found.
    12921559 * @param   pMacAddress             The mac address.
    1293  * @param   fEnsureUpToDateConfig   Whether to update the configuration.
    1294  */
    1295 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress, bool fEnsureUpToDateConfig)
     1560 */
     1561VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress)
    12961562{
    12971563    size_t iLease = m_Leases.size();
     
    13031569            &&  pLease->m_MacAddress.au16[1] == pMacAddress->au16[1]
    13041570            &&  pLease->m_MacAddress.au16[2] == pMacAddress->au16[2])
    1305         {
    1306             if (fEnsureUpToDateConfig)
    1307                 updateLeaseConfig(pLease);
    13081571            return pLease;
    1309         }
    13101572    }
    13111573
     
    13501612VBoxNetDhcpLease *VBoxNetDhcp::newLease(PCRTNETBOOTP pDhcpMsg, size_t cb)
    13511613{
    1352     debugPrint(0, true, "newLease is not implemented");
    1353     return NULL;
    1354 }
    1355 
    1356 
    1357 /**
    1358  * Updates the configuration of the lease in question.
    1359  *
    1360  * @todo it's possible that we'll simplify this stuff by expanding all the
    1361  *       possible leases when loading the config instead in newLease()...
    1362  *
    1363  * @param   pLease          The lease.
    1364  */
    1365 void VBoxNetDhcp::updateLeaseConfig(VBoxNetDhcpLease *pLease)
    1366 {
     1614    RTMAC const MacAddr = pDhcpMsg->bp_chaddr.Mac;
     1615    RTTIMESPEC  Now;
     1616    RTTimeNow(&Now);
     1617
     1618    /*
     1619     * Search the possible leases.
     1620     *
     1621     * We'll try do all the searches in one pass, that is to say, perfect
     1622     * match, old lease, and next free/expired lease.
     1623     */
     1624    VBoxNetDhcpLease *pBest = NULL;
     1625    VBoxNetDhcpLease *pOld  = NULL;
     1626    VBoxNetDhcpLease *pFree = NULL;
     1627
     1628    size_t cLeases = m_Leases.size();
     1629    for (size_t i = 0; i < cLeases; i++)
     1630    {
     1631        VBoxNetDhcpLease *pCur = &m_Leases[i];
     1632
     1633        /* Skip it if no configuration, that means its not in the current config. */
     1634        if (!pCur->m_pCfg)
     1635            continue;
     1636
     1637        /* best */
     1638        if (    pCur->isOneSpecificClient()
     1639            &&  pCur->m_pCfg->matchesMacAddress(&MacAddr))
     1640        {
     1641            if (    !pBest
     1642                ||  pBest->m_pCfg->m_MacAddresses.size() < pCur->m_pCfg->m_MacAddresses.size())
     1643                pBest = pCur;
     1644        }
     1645
     1646        /* old lease */
     1647        if (    pCur->m_MacAddress.au16[0] == MacAddr.au16[0]
     1648            &&  pCur->m_MacAddress.au16[1] == MacAddr.au16[1]
     1649            &&  pCur->m_MacAddress.au16[2] == MacAddr.au16[2])
     1650        {
     1651            if (    !pOld
     1652                ||  RTTimeSpecGetSeconds(&pCur->m_ExpireTime) > RTTimeSpecGetSeconds(&pFree->m_ExpireTime))
     1653                pOld = pCur;
     1654        }
     1655
     1656        /* expired lease */
     1657        if (!pCur->isInUse(&Now))
     1658        {
     1659            if (    !pFree
     1660                ||  RTTimeSpecGetSeconds(&pCur->m_ExpireTime) < RTTimeSpecGetSeconds(&pFree->m_ExpireTime))
     1661                pFree = pCur;
     1662        }
     1663    }
     1664
     1665    VBoxNetDhcpLease *pNew = pBest;
     1666    if (!pNew)
     1667        pNew = pOld;
     1668    if (!pNew)
     1669        pNew = pFree;
     1670    if (!pNew)
     1671    {
     1672        debugPrint(0, true, "No more leases.");
     1673        return NULL;
     1674    }
     1675
     1676    /*
     1677     * Init the lease.
     1678     */
     1679    pNew->m_MacAddress = MacAddr;
     1680    pNew->m_xid        = pDhcpMsg->bp_xid;
     1681    /** @todo extract the client id. */
     1682
     1683    return pNew;
    13671684}
    13681685
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