Changeset 17779 in vbox
- Timestamp:
- Mar 12, 2009 9:29:23 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp
r17770 r17779 174 174 return 2; 175 175 } 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 } 176 197 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; 177 233 } 178 234 … … 187 243 typedef enum State 188 244 { 245 /** Invalid. */ 246 kState_Invalid = 0, 189 247 /** The lease is free / released. */ 190 kState_Free = 0,248 kState_Free, 191 249 /** An offer has been made. 192 250 * Expire time indicates when the offer expires. */ … … 196 254 kState_Active 197 255 } State; 198 199 void offer(uint32_t xid);200 void activate(void);201 void release(void);202 256 203 257 /** The client MAC address. */ … … 214 268 /** The configuration for this lease. */ 215 269 VBoxNetDhcpCfg *m_pCfg; 270 271 public: 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 } 216 355 }; 217 356 … … 231 370 protected: 232 371 int addConfig(VBoxNetDhcpCfg *pCfg); 372 void explodeConfig(void); 373 233 374 bool handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb); 234 375 bool handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb); … … 238 379 void makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb); 239 380 240 VBoxNetDhcpLease *findLeaseByMacAddress(PCRTMAC pMacAddress , bool fEnsureUpToDateConfig);381 VBoxNetDhcpLease *findLeaseByMacAddress(PCRTMAC pMacAddress); 241 382 VBoxNetDhcpLease *findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress); 242 383 VBoxNetDhcpLease *newLease(PCRTNETBOOTP pDhcpMsg, size_t cb); 243 void updateLeaseConfig(VBoxNetDhcpLease *pLease);244 384 245 385 static uint8_t const *findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, size_t *pcbMaxOpt); … … 260 400 261 401 /** The current configs. */ 262 std::vector<VBoxNetDhcpCfg > m_Cfgs;402 std::vector<VBoxNetDhcpCfg *> m_Cfgs; 263 403 264 404 /** The current leases. */ … … 317 457 318 458 /** 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 */ 464 void VBoxNetDhcpLease::activate(uint32_t xid) 465 { 466 activate(); 467 m_xid = xid; 468 } 469 470 471 /** 319 472 * Release a lease either upon client request or because it didn't quite match a 320 473 * DHCP_REQUEST. … … 326 479 RTTimeSpecAddSeconds(&m_ExpireTime, 5); 327 480 } 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 */ 493 bool VBoxNetDhcpLease::hasExpired() const 494 { 495 RTTIMESPEC Now; 496 return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(RTTimeNow(&Now)); 497 } 498 328 499 329 500 … … 357 528 358 529 #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))); 363 534 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); 371 543 #endif 372 544 } … … 415 587 rc = pCfg->validate(); 416 588 if (!rc) 417 m_Cfgs.push_back(*pCfg); 418 delete pCfg; 589 m_Cfgs.push_back(pCfg); 590 else 591 delete pCfg; 419 592 } 420 593 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 */ 607 void 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 } 421 667 } 422 668 … … 499 745 { 500 746 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxDhcpCfg failed\n"); 501 rc = 1; 502 break; 747 return 1; 503 748 } 504 749 } … … 525 770 default: 526 771 AssertMsgFailed(("%d", rc)); 527 rc = 1; 528 break; 772 return 1; 529 773 } 530 774 break; … … 548 792 } 549 793 } 794 795 /* 796 * Do the reconfig. (move this later) 797 */ 798 if (!rc) 799 explodeConfig(); 550 800 551 801 return rc; … … 779 1029 * If none was found, create a new lease for it and then construct a reply. 780 1030 */ 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()) 784 1034 pLease = newLease(pDhcpMsg, cb); 785 1035 if (!pLease) 786 1036 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); 787 1044 pLease->offer(pDhcpMsg->bp_xid); 788 1045 … … 804 1061 /** @todo Probably need to match the server IP here to work correctly with 805 1062 * other servers. */ 1063 /** @todo check this against the RFC and real code. the code is kind of 1064 * fishy... */ 806 1065 807 1066 /* … … 814 1073 { 815 1074 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 818 1083 /* Check if the xid matches, if it doesn't it's not our call. */ 819 1084 #if 0 /** @todo check how windows treats bp_xid here, it should match I think. If … … 832 1097 * Ack it. 833 1098 */ 834 pLease->activate( );1099 pLease->activate(pDhcpMsg->bp_xid); 835 1100 makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb); 836 1101 } … … 847 1112 { 848 1113 /* ACK it. */ 1114 debugPrint(1, true, "REQUEST for lease not on offer, new lease matches."); 849 1115 pLease->activate(); 850 1116 makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb); … … 853 1119 { 854 1120 /* NAK it */ 1121 debugPrint(1, true, "REQUEST for lease not on offer, NACnig it."); 855 1122 if (pLease) 856 1123 pLease->release(); … … 1208 1475 bool optEnd(void) 1209 1476 { 1210 return hasOverflowed();1477 return !hasOverflowed(); 1211 1478 } 1212 1479 }; … … 1291 1558 * @returns Pointer to the lease if found, NULL if not found. 1292 1559 * @param pMacAddress The mac address. 1293 * @param fEnsureUpToDateConfig Whether to update the configuration. 1294 */ 1295 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress, bool fEnsureUpToDateConfig) 1560 */ 1561 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress) 1296 1562 { 1297 1563 size_t iLease = m_Leases.size(); … … 1303 1569 && pLease->m_MacAddress.au16[1] == pMacAddress->au16[1] 1304 1570 && pLease->m_MacAddress.au16[2] == pMacAddress->au16[2]) 1305 {1306 if (fEnsureUpToDateConfig)1307 updateLeaseConfig(pLease);1308 1571 return pLease; 1309 }1310 1572 } 1311 1573 … … 1350 1612 VBoxNetDhcpLease *VBoxNetDhcp::newLease(PCRTNETBOOTP pDhcpMsg, size_t cb) 1351 1613 { 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; 1367 1684 } 1368 1685
Note:
See TracChangeset
for help on using the changeset viewer.