Changeset 46969 in vbox for trunk/src/VBox/NetworkServices
- Timestamp:
- Jul 4, 2013 6:35:01 AM (12 years ago)
- Location:
- trunk/src/VBox/NetworkServices
- Files:
-
- 2 deleted
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/DHCP/Makefile.kmk
r46968 r46969 33 33 # Hardened VBoxNetDHCP. 34 34 # 35 VBoxNetDHCPHardened_TEMPLATE = VBOX MAINCLIENTEXE35 VBoxNetDHCPHardened_TEMPLATE = VBOXR3HARDENEDEXE 36 36 VBoxNetDHCPHardened_SOURCES = VBoxNetDHCPHardened.cpp 37 37 VBoxNetDHCPHardened_NAME = VBoxNetDHCP … … 41 41 # VBoxNetDHCP 42 42 # 43 VBoxNetDHCP_TEMPLATE = VBOXMAINCLIENTEXE44 #VBoxNetDHCP_TEMPLATE := VBOXR3$(if-expr defined(VBOX_WITH_HARDENING),,EXE)43 VBoxNetDHCP_TEMPLATE = 44 VBoxNetDHCP_TEMPLATE := VBOXR3$(if-expr defined(VBOX_WITH_HARDENING),,EXE) 45 45 VBoxNetDHCP_SOURCES = \ 46 46 VBoxNetDHCP.cpp \ 47 Config.cpp \48 47 ../NetLib/VBoxNetIntIf.cpp \ 49 48 ../NetLib/VBoxNetUDP.cpp \ 50 ../NetLib/VBoxNetARP.cpp \ 51 ../NetLib/VBoxNetBaseService.cpp 49 ../NetLib/VBoxNetARP.cpp 52 50 VBoxNetDHCP_LIBS = \ 53 51 $(LIB_RUNTIME) 54 52 VBoxNetDHCP_LDFLAGS.win = /SUBSYSTEM:windows 55 53 56 ifeq ($(USERNAME),vvl)57 PROGRAMS += tstDhcpConfig58 59 #60 # VBOXMAINCLIENT here only to use DhcpOpt_T type.61 tstDhcpConfig_TEMPLATE = VBOXMAINCLIENTEXE62 #XXX: enable condtionally if user is vvl63 #tstDhcpConfig_INSTTYPE = none64 tstDhcpConfig_SOURCES = test/tstDhcpConfig.cpp65 endif66 67 54 68 55 include $(FILE_KBUILD_SUB_FOOTER) -
trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp
r46962 r46969 25 25 * Header Files * 26 26 *******************************************************************************/ 27 #include <VBox/com/com.h>28 #include <VBox/com/listeners.h>29 #include <VBox/com/string.h>30 #include <VBox/com/Guid.h>31 #include <VBox/com/array.h>32 #include <VBox/com/ErrorInfo.h>33 #include <VBox/com/errorprint.h>34 #include <VBox/com/EventQueue.h>35 #include <VBox/com/VirtualBox.h>36 37 27 #include <iprt/alloca.h> 38 28 #include <iprt/buildconfig.h> … … 54 44 #include <VBox/version.h> 55 45 56 57 46 #include "../NetLib/VBoxNetLib.h" 58 47 59 48 #include <vector> 60 #include <list>61 49 #include <string> 62 #include <map>63 64 #include "../NetLib/VBoxNetBaseService.h"65 50 66 51 #ifdef RT_OS_WINDOWS /* WinMain */ … … 69 54 #endif 70 55 71 #ifndef INET4_ADDRLEN 72 # define INET4_ADDRLEN 17 73 #endif 74 75 #include "Config.h" 56 76 57 /******************************************************************************* 77 58 * Structures and Typedefs * 78 59 *******************************************************************************/ 60 61 /** 62 * DHCP configuration item. 63 * 64 * This is all public data because I'm too lazy to do it properly right now. 65 */ 66 class VBoxNetDhcpCfg 67 { 68 public: 69 /** The etheret addresses this matches config applies to. 70 * An empty vector means 'ANY'. */ 71 std::vector<RTMAC> m_MacAddresses; 72 /** The upper address in the range. */ 73 RTNETADDRIPV4 m_UpperAddr; 74 /** The lower address in the range. */ 75 RTNETADDRIPV4 m_LowerAddr; 76 77 /** Option 1: The net mask. */ 78 RTNETADDRIPV4 m_SubnetMask; 79 /* * Option 2: The time offset. */ 80 /** Option 3: Routers for the subnet. */ 81 std::vector<RTNETADDRIPV4> m_Routers; 82 /* * Option 4: Time server. */ 83 /* * Option 5: Name server. */ 84 /** Option 6: Domain Name Server (DNS) */ 85 std::vector<RTNETADDRIPV4> m_DNSes; 86 /* * Option 7: Log server. */ 87 /* * Option 8: Cookie server. */ 88 /* * Option 9: LPR server. */ 89 /* * Option 10: Impress server. */ 90 /* * Option 11: Resource location server. */ 91 /* * Option 12: Host name. */ 92 std::string m_HostName; 93 /* * Option 13: Boot file size option. */ 94 /* * Option 14: Merit dump file. */ 95 /** Option 15: Domain name. */ 96 std::string m_DomainName; 97 /* * Option 16: Swap server. */ 98 /* * Option 17: Root path. */ 99 /* * Option 18: Extension path. */ 100 /* * Option 19: IP forwarding enable/disable. */ 101 /* * Option 20: Non-local routing enable/disable. */ 102 /* * Option 21: Policy filter. */ 103 /* * Option 22: Maximum datagram reassembly size (MRS). */ 104 /* * Option 23: Default IP time-to-live. */ 105 /* * Option 24: Path MTU aging timeout. */ 106 /* * Option 25: Path MTU plateau table. */ 107 /* * Option 26: Interface MTU. */ 108 /* * Option 27: All subnets are local. */ 109 /* * Option 28: Broadcast address. */ 110 /* * Option 29: Perform maximum discovery. */ 111 /* * Option 30: Mask supplier. */ 112 /* * Option 31: Perform route discovery. */ 113 /* * Option 32: Router solicitation address. */ 114 /* * Option 33: Static route. */ 115 /* * Option 34: Trailer encapsulation. */ 116 /* * Option 35: ARP cache timeout. */ 117 /* * Option 36: Ethernet encapsulation. */ 118 /* * Option 37: TCP Default TTL. */ 119 /* * Option 38: TCP Keepalive Interval. */ 120 /* * Option 39: TCP Keepalive Garbage. */ 121 /* * Option 40: Network Information Service (NIS) Domain. */ 122 /* * Option 41: Network Information Servers. */ 123 /* * Option 42: Network Time Protocol Servers. */ 124 /* * Option 43: Vendor Specific Information. */ 125 /* * Option 44: NetBIOS over TCP/IP Name Server (NBNS). */ 126 /* * Option 45: NetBIOS over TCP/IP Datagram distribution Server (NBDD). */ 127 /* * Option 46: NetBIOS over TCP/IP Node Type. */ 128 /* * Option 47: NetBIOS over TCP/IP Scope. */ 129 /* * Option 48: X Window System Font Server. */ 130 /* * Option 49: X Window System Display Manager. */ 131 132 /** Option 51: IP Address Lease Time. */ 133 uint32_t m_cSecLease; 134 135 /* * Option 64: Network Information Service+ Domain. */ 136 /* * Option 65: Network Information Service+ Servers. */ 137 /** Option 66: TFTP server name. */ 138 std::string m_TftpServer; 139 /** Address for the bp_siaddr field corresponding to m_TftpServer. */ 140 RTNETADDRIPV4 m_TftpServerAddr; 141 /** Option 67: Bootfile name. */ 142 std::string m_BootfileName; 143 144 /* * Option 68: Mobile IP Home Agent. */ 145 /* * Option 69: Simple Mail Transport Protocol (SMPT) Server. */ 146 /* * Option 70: Post Office Protocol (POP3) Server. */ 147 /* * Option 71: Network News Transport Protocol (NNTP) Server. */ 148 /* * Option 72: Default World Wide Web (WWW) Server. */ 149 /* * Option 73: Default Finger Server. */ 150 /* * Option 74: Default Internet Relay Chat (IRC) Server. */ 151 /* * Option 75: StreetTalk Server. */ 152 153 /* * Option 119: Domain Search. */ 154 155 156 VBoxNetDhcpCfg() 157 { 158 m_UpperAddr.u = UINT32_MAX; 159 m_LowerAddr.u = UINT32_MAX; 160 m_SubnetMask.u = UINT32_MAX; 161 m_cSecLease = 60*60; /* 1 hour */ 162 } 163 164 /** Validates the configuration. 165 * @returns 0 on success, exit code + error message to stderr on failure. */ 166 int validate(void) 167 { 168 if ( m_UpperAddr.u == UINT32_MAX 169 || m_LowerAddr.u == UINT32_MAX 170 || m_SubnetMask.u == UINT32_MAX) 171 { 172 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: Config is missing:"); 173 if (m_UpperAddr.u == UINT32_MAX) 174 RTStrmPrintf(g_pStdErr, " --upper-ip"); 175 if (m_LowerAddr.u == UINT32_MAX) 176 RTStrmPrintf(g_pStdErr, " --lower-ip"); 177 if (m_SubnetMask.u == UINT32_MAX) 178 RTStrmPrintf(g_pStdErr, " --netmask"); 179 return 2; 180 } 181 182 if (RT_N2H_U32(m_UpperAddr.u) < RT_N2H_U32(m_LowerAddr.u)) 183 { 184 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: The --upper-ip value is lower than the --lower-ip one!\n" 185 " %d.%d.%d.%d < %d.%d.%d.%d\n", 186 m_UpperAddr.au8[0], m_UpperAddr.au8[1], m_UpperAddr.au8[2], m_UpperAddr.au8[3], 187 m_LowerAddr.au8[0], m_LowerAddr.au8[1], m_LowerAddr.au8[2], m_LowerAddr.au8[3]); 188 return 3; 189 } 190 191 /* the code goes insane if we have too many atm. lazy bird */ 192 uint32_t cIPs = RT_N2H_U32(m_UpperAddr.u) - RT_N2H_U32(m_LowerAddr.u); 193 if (cIPs > 1024) 194 { 195 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: Too many IPs between --upper-ip and --lower-ip! %d (max 1024)\n" 196 " %d.%d.%d.%d < %d.%d.%d.%d\n", 197 cIPs, 198 m_UpperAddr.au8[0], m_UpperAddr.au8[1], m_UpperAddr.au8[2], m_UpperAddr.au8[3], 199 m_LowerAddr.au8[0], m_LowerAddr.au8[1], m_LowerAddr.au8[2], m_LowerAddr.au8[3]); 200 return 3; 201 } 202 return 0; 203 } 204 205 /** 206 * Is this config for one specific client? 207 * 208 * @return true / false. 209 */ 210 bool isOneSpecificClient(void) const 211 { 212 return m_LowerAddr.u == m_UpperAddr.u 213 && m_MacAddresses.size() > 0; 214 } 215 216 /** 217 * Checks if this config matches the specified MAC address. 218 * 219 * @returns true / false. 220 * 221 * @param pMac The MAC address to match. 222 */ 223 bool matchesMacAddress(PCRTMAC pMac) const 224 { 225 size_t i = m_MacAddresses.size(); 226 if (RT_LIKELY(i < 1)) 227 return true; /* no entries == ALL wildcard match */ 228 229 while (i--) 230 { 231 PCRTMAC pCur = &m_MacAddresses[i]; 232 if ( pCur->au16[0] == pMac->au16[0] 233 && pCur->au16[1] == pMac->au16[1] 234 && pCur->au16[2] == pMac->au16[2]) 235 return true; 236 } 237 return false; 238 } 239 240 }; 241 242 /** 243 * DHCP lease. 244 */ 245 class VBoxNetDhcpLease 246 { 247 public: 248 typedef enum State 249 { 250 /** Invalid. */ 251 kState_Invalid = 0, 252 /** The lease is free / released. */ 253 kState_Free, 254 /** An offer has been made. 255 * Expire time indicates when the offer expires. */ 256 kState_Offer, 257 /** The lease is active. 258 * Expire time indicates when the lease expires. */ 259 kState_Active 260 } State; 261 262 /** The client MAC address. */ 263 RTMAC m_MacAddress; 264 /** The IPv4 address. */ 265 RTNETADDRIPV4 m_IPv4Address; 266 267 /** The current lease state. */ 268 State m_enmState; 269 /** The lease expiration time. */ 270 RTTIMESPEC m_ExpireTime; 271 /** Transaction ID. */ 272 uint32_t m_xid; 273 /** The configuration for this lease. */ 274 VBoxNetDhcpCfg *m_pCfg; 275 276 public: 277 /** Constructor taking an IPv4 address and a Config. */ 278 VBoxNetDhcpLease(RTNETADDRIPV4 IPv4Addr, VBoxNetDhcpCfg *pCfg) 279 { 280 m_pCfg = pCfg; 281 m_IPv4Address = IPv4Addr; 282 283 m_MacAddress.au16[0] = m_MacAddress.au16[1] = m_MacAddress.au16[2] = 0xff; 284 m_enmState = kState_Free; 285 RTTimeSpecSetSeconds(&m_ExpireTime, 0); 286 m_xid = UINT32_MAX; 287 } 288 289 /** Destructor. */ 290 ~VBoxNetDhcpLease() 291 { 292 m_IPv4Address.u = UINT32_MAX; 293 m_pCfg = NULL; 294 m_MacAddress.au16[0] = m_MacAddress.au16[1] = m_MacAddress.au16[2] = 0xff; 295 m_enmState = kState_Free; 296 m_xid = UINT32_MAX; 297 } 298 299 void offer(uint32_t xid); 300 void activate(void); 301 void activate(uint32_t xid); 302 void release(void); 303 bool hasExpired(void) const; 304 305 /** 306 * Checks if the lease is in use or not. 307 * 308 * @returns true if active, false if free or expired. 309 * 310 * @param pNow The current time to use. Optional. 311 */ 312 bool isInUse(PCRTTIMESPEC pNow = NULL) const 313 { 314 if ( m_enmState == kState_Offer 315 || m_enmState == kState_Active) 316 { 317 RTTIMESPEC Now; 318 if (!pNow) 319 pNow = RTTimeNow(&Now); 320 return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(pNow); 321 } 322 return false; 323 } 324 325 /** 326 * Is this lease for one specific client? 327 * 328 * @return true/false. 329 */ 330 bool isOneSpecificClient(void) const 331 { 332 return m_pCfg 333 && m_pCfg->isOneSpecificClient(); 334 } 335 336 /** 337 * Is this lease currently being offered to a client. 338 * 339 * @returns true / false. 340 */ 341 bool isBeingOffered(void) const 342 { 343 return m_enmState == kState_Offer 344 && isInUse(); 345 } 346 347 /** 348 * Is the lease in the current config or not. 349 * 350 * When updating the config we might leave active leases behind which aren't 351 * included in the new config. These will have m_pCfg set to NULL and should be 352 * freed up when they expired. 353 * 354 * @returns true / false. 355 */ 356 bool isInCurrentConfig(void) const 357 { 358 return m_pCfg != NULL; 359 } 360 }; 361 79 362 /** 80 363 * DHCP server instance. 81 364 */ 82 class VBoxNetDhcp : public VBoxNetBaseService365 class VBoxNetDhcp 83 366 { 84 367 public: … … 86 369 virtual ~VBoxNetDhcp(); 87 370 88 int init(); 371 int parseArgs(int argc, char **argv); 372 int tryGoOnline(void); 89 373 int run(void); 90 void usage(void) { /* XXX: document options */ };91 int parseOpt(int rc, const RTGETOPTUNION& getOptVal);92 374 93 375 protected: 376 int addConfig(VBoxNetDhcpCfg *pCfg); 377 void explodeConfig(void); 378 94 379 bool handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb); 95 380 bool handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb); … … 97 382 bool handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb); 98 383 bool handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb); 99 384 void makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb); 385 386 VBoxNetDhcpLease *findLeaseByMacAddress(PCRTMAC pMacAddress, bool fAnyState); 387 VBoxNetDhcpLease *findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState); 388 VBoxNetDhcpLease *newLease(PCRTNETBOOTP pDhcpMsg, size_t cb); 389 390 static uint8_t const *findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, size_t *pcbMaxOpt); 391 static bool findOptionIPv4Addr(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, PRTNETADDRIPV4 pIPv4Addr); 392 393 inline void debugPrint( int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const; 100 394 void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const; 101 395 static const char *debugDhcpName(uint8_t uMsgType); 102 396 103 397 protected: 104 /** @name The DHCP server specificconfiguration data members.398 /** @name The server configuration data members. 105 399 * @{ */ 106 /* 107 * XXX: what was the plan? SQL3 or plain text file? 108 * How it will coexists with managment from VBoxManagement, who should manage db 109 * in that case (VBoxManage, VBoxSVC ???) 110 */ 400 std::string m_Name; 401 std::string m_Network; 402 std::string m_TrunkName; 403 INTNETTRUNKTYPE m_enmTrunkType; 404 RTMAC m_MacAddress; 405 RTNETADDRIPV4 m_Ipv4Address; 111 406 std::string m_LeaseDBName; 112 113 407 /** @} */ 114 408 115 /* corresponding dhcp server description in Main */ 116 ComPtr<IDHCPServer> m_DhcpServer; 117 118 ComPtr<INATNetwork> m_NATNetwork; 119 120 /* 121 * We will ignore cmd line parameters IFF there will be some DHCP specific arguments 122 * otherwise all paramters will come from Main. 123 */ 124 bool m_fIgnoreCmdLineParameters; 125 126 /* 127 * -b -n 10.0.1.2 -m 255.255.255.0 -> to the list processing in 128 */ 129 typedef struct 130 { 131 char Key; 132 std::string strValue; 133 } CMDLNPRM; 134 std::list<CMDLNPRM> CmdParameterll; 135 typedef std::list<CMDLNPRM>::iterator CmdParameterIterator; 409 /** The current configs. */ 410 std::vector<VBoxNetDhcpCfg *> m_Cfgs; 411 412 /** The current leases. */ 413 std::vector<VBoxNetDhcpLease> m_Leases; 414 415 /** @name The network interface 416 * @{ */ 417 PSUPDRVSESSION m_pSession; 418 uint32_t m_cbSendBuf; 419 uint32_t m_cbRecvBuf; 420 INTNETIFHANDLE m_hIf; /**< The handle to the network interface. */ 421 PINTNETBUF m_pIfBuf; /**< Interface buffer. */ 422 /** @} */ 136 423 137 424 /** @name Debug stuff … … 144 431 /** @} */ 145 432 }; 146 #if 0 147 /* XXX: clean up it. */ 148 typedef std::vector<VBoxNetDhcpLease> DhcpLeaseContainer; 149 typedef DhcpLeaseContainer::iterator DhcpLeaseIterator; 150 typedef DhcpLeaseContainer::reverse_iterator DhcpLeaseRIterator; 151 typedef DhcpLeaseContainer::const_iterator DhcpLeaseCIterator; 152 #endif 433 153 434 154 435 /******************************************************************************* … … 158 439 static VBoxNetDhcp *g_pDhcp; 159 440 160 /* DHCP server specific options */ 161 static const RTGETOPTDEF g_aOptionDefs[] = 162 { 163 { "--lease-db", 'D', RTGETOPT_REQ_STRING }, 164 { "--begin-config", 'b', RTGETOPT_REQ_NOTHING }, 165 { "--gateway", 'g', RTGETOPT_REQ_IPV4ADDR }, 166 { "--lower-ip", 'l', RTGETOPT_REQ_IPV4ADDR }, 167 { "--upper-ip", 'u', RTGETOPT_REQ_IPV4ADDR }, 168 }; 169 170 #if 0 171 /* XXX this will gone */ 441 172 442 /** 173 443 * Offer this lease to a client. … … 235 505 return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(RTTimeNow(&Now)); 236 506 } 237 #endif 507 508 509 238 510 239 511 /** … … 266 538 memset(&m_CurHdrs, '\0', sizeof(m_CurHdrs)); 267 539 268 m_fIgnoreCmdLineParameters = true;269 270 540 #if 0 /* enable to hack the code without a mile long argument list. */ 271 541 VBoxNetDhcpCfg *pDefCfg = new VBoxNetDhcpCfg(); … … 279 549 pDefCfg->m_DNSes.push_back(Addr); 280 550 pDefCfg->m_DomainName = "vboxnetdhcp.org"; 281 # 551 #if 0 282 552 pDefCfg->m_cSecLease = 60*60; /* 1 hour */ 283 # 553 #else 284 554 pDefCfg->m_cSecLease = 30; /* sec */ 285 # 555 #endif 286 556 pDefCfg->m_TftpServer = "10.0.2.3"; //?? 287 557 this->addConfig(pDefCfg); … … 295 565 VBoxNetDhcp::~VBoxNetDhcp() 296 566 { 297 } 298 299 300 301 302 /** 303 * Parse the DHCP specific arguments. 304 * 305 * This callback caled for each paramenter so 306 * .... 307 * we nee post analisys of the parameters, at least 308 * for -b, -g, -l, -u, -m 309 */ 310 int VBoxNetDhcp::parseOpt(int rc, const RTGETOPTUNION& Val) 311 { 312 CMDLNPRM prm; 313 314 /* Ok, we've entered here, thus we can't ignore cmd line parameters anymore */ 315 m_fIgnoreCmdLineParameters = false; 316 317 prm.Key = rc; 318 319 switch (rc) 320 { 567 /* 568 * Close the interface connection. 569 */ 570 if (m_hIf != INTNET_HANDLE_INVALID) 571 { 572 INTNETIFCLOSEREQ CloseReq; 573 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 574 CloseReq.Hdr.cbReq = sizeof(CloseReq); 575 CloseReq.pSession = m_pSession; 576 CloseReq.hIf = m_hIf; 577 m_hIf = INTNET_HANDLE_INVALID; 578 int rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_CLOSE, 0, &CloseReq.Hdr); 579 AssertRC(rc); 580 } 581 582 if (m_pSession) 583 { 584 SUPR3Term(false /*fForced*/); 585 m_pSession = NIL_RTR0PTR; 586 } 587 } 588 589 590 /** 591 * Adds a config to the tail. 592 * 593 * @returns See VBoxNetDHCP::validate(). 594 * @param pCfg The config too add. 595 * This object will be consumed by this call! 596 */ 597 int VBoxNetDhcp::addConfig(VBoxNetDhcpCfg *pCfg) 598 { 599 int rc = 0; 600 if (pCfg) 601 { 602 rc = pCfg->validate(); 603 if (!rc) 604 m_Cfgs.push_back(pCfg); 605 else 606 delete pCfg; 607 } 608 return rc; 609 } 610 611 612 /** 613 * Explodes the config into leases. 614 * 615 * @remarks This code is brute force and not very fast nor memory efficient. 616 * We will have to revisit this later. 617 * 618 * @remarks If an IP has been reconfigured for a fixed mac address and it's 619 * already leased to a client, we it won't be available until the 620 * client releases its lease or it expires. 621 */ 622 void VBoxNetDhcp::explodeConfig(void) 623 { 624 RTTIMESPEC Now; 625 RTTimeNow(&Now); 626 627 /* 628 * Remove all non-active leases from the vector and zapping the 629 * config pointers of the once left behind. 630 */ 631 std::vector<VBoxNetDhcpLease>::iterator Itr = m_Leases.begin(); 632 while (Itr != m_Leases.end()) 633 { 634 if (!Itr->isInUse(&Now)) 635 Itr = m_Leases.erase(Itr); 636 else 637 { 638 Itr->m_pCfg = NULL; 639 Itr++; 640 } 641 } 642 643 /* 644 * Loop thru the configurations in reverse order, giving the last 645 * configs priority of the newer ones. 646 */ 647 size_t iCfg = m_Cfgs.size(); 648 while (iCfg-- > 0) 649 { 650 VBoxNetDhcpCfg *pCfg = m_Cfgs[iCfg]; 651 652 /* Expand the IP lease range. */ 653 uint32_t const uLast = RT_N2H_U32(pCfg->m_UpperAddr.u); 654 for (uint32_t i = RT_N2H_U32(pCfg->m_LowerAddr.u); i <= uLast; i++) 655 { 656 RTNETADDRIPV4 IPv4Addr; 657 IPv4Addr.u = RT_H2N_U32(i); 658 659 /* Check if it exists and is configured. */ 660 VBoxNetDhcpLease *pLease = NULL; 661 for (size_t j = 0; j < m_Leases.size(); j++) 662 if (m_Leases[j].m_IPv4Address.u == IPv4Addr.u) 663 { 664 pLease = &m_Leases[j]; 665 break; 666 } 667 if (pLease) 668 { 669 if (!pLease->m_pCfg) 670 pLease->m_pCfg = pCfg; 671 } 672 else 673 { 674 /* add it. */ 675 VBoxNetDhcpLease NewLease(IPv4Addr, pCfg); 676 m_Leases.push_back(NewLease); 677 debugPrint(10, false, "exploseConfig: new lease %d.%d.%d.%d", 678 IPv4Addr.au8[0], IPv4Addr.au8[1], IPv4Addr.au8[2], IPv4Addr.au8[3]); 679 } 680 } 681 } 682 } 683 684 685 /** 686 * Parse the arguments. 687 * 688 * @returns 0 on success, fully bitched exit code on failure. 689 * 690 * @param argc Argument count. 691 * @param argv Argument vector. 692 */ 693 int VBoxNetDhcp::parseArgs(int argc, char **argv) 694 { 695 static const RTGETOPTDEF s_aOptionDefs[] = 696 { 697 { "--name", 'N', RTGETOPT_REQ_STRING }, 698 { "--network", 'n', RTGETOPT_REQ_STRING }, 699 { "--trunk-name", 't', RTGETOPT_REQ_STRING }, 700 { "--trunk-type", 'T', RTGETOPT_REQ_STRING }, 701 { "--mac-address", 'a', RTGETOPT_REQ_MACADDR }, 702 { "--ip-address", 'i', RTGETOPT_REQ_IPV4ADDR }, 703 { "--lease-db", 'D', RTGETOPT_REQ_STRING }, 704 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 705 706 { "--begin-config", 'b', RTGETOPT_REQ_NOTHING }, 707 { "--gateway", 'g', RTGETOPT_REQ_IPV4ADDR }, 708 { "--lower-ip", 'l', RTGETOPT_REQ_IPV4ADDR }, 709 { "--upper-ip", 'u', RTGETOPT_REQ_IPV4ADDR }, 710 { "--netmask", 'm', RTGETOPT_REQ_IPV4ADDR }, 711 }; 712 713 RTGETOPTSTATE State; 714 int rc = RTGetOptInit(&State, argc, argv, &s_aOptionDefs[0], RT_ELEMENTS(s_aOptionDefs), 0, 0 /*fFlags*/); 715 AssertRCReturn(rc, 49); 716 717 VBoxNetDhcpCfg *pCurCfg = NULL; 718 for (;;) 719 { 720 RTGETOPTUNION Val; 721 rc = RTGetOpt(&State, &Val); 722 if (!rc) 723 break; 724 switch (rc) 725 { 726 case 'N': 727 m_Name = Val.psz; 728 break; 729 case 'n': 730 m_Network = Val.psz; 731 break; 732 case 't': 733 m_TrunkName = Val.psz; 734 break; 735 case 'T': 736 if (!strcmp(Val.psz, "none")) 737 m_enmTrunkType = kIntNetTrunkType_None; 738 else if (!strcmp(Val.psz, "whatever")) 739 m_enmTrunkType = kIntNetTrunkType_WhateverNone; 740 else if (!strcmp(Val.psz, "netflt")) 741 m_enmTrunkType = kIntNetTrunkType_NetFlt; 742 else if (!strcmp(Val.psz, "netadp")) 743 m_enmTrunkType = kIntNetTrunkType_NetAdp; 744 else if (!strcmp(Val.psz, "srvnat")) 745 m_enmTrunkType = kIntNetTrunkType_SrvNat; 746 else 747 { 748 RTStrmPrintf(g_pStdErr, "Invalid trunk type '%s'\n", Val.psz); 749 return 1; 750 } 751 break; 752 case 'a': 753 m_MacAddress = Val.MacAddr; 754 break; 755 case 'i': 756 m_Ipv4Address = Val.IPv4Addr; 757 break; 758 case 'd': 759 m_LeaseDBName = Val.psz; 760 break; 761 762 case 'v': 763 m_cVerbosity++; 764 break; 765 321 766 /* Begin config. */ 322 case 'b': 323 CmdParameterll.push_back(prm); 324 break; 325 326 case 'l': 327 case 'u': 328 case 'm': 329 case 'g': 330 prm.strValue = std::string(Val.psz); 331 CmdParameterll.push_back(prm); 332 break; 333 334 case 'D': 335 break; 336 337 default: 338 rc = RTGetOptPrintError(rc, &Val); 339 RTPrintf("Use --help for more information.\n"); 340 return rc; 341 } 767 case 'b': 768 rc = addConfig(pCurCfg); 769 if (rc) 770 break; 771 pCurCfg = NULL; 772 /* fall thru */ 773 774 /* config specific ones. */ 775 case 'g': 776 case 'l': 777 case 'u': 778 case 'm': 779 if (!pCurCfg) 780 { 781 pCurCfg = new VBoxNetDhcpCfg(); 782 if (!pCurCfg) 783 { 784 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: new VBoxDhcpCfg failed\n"); 785 return 1; 786 } 787 } 788 789 switch (rc) 790 { 791 case 'g': 792 pCurCfg->m_Routers.push_back(Val.IPv4Addr); 793 break; 794 795 case 'l': 796 pCurCfg->m_LowerAddr = Val.IPv4Addr; 797 break; 798 799 case 'u': 800 pCurCfg->m_UpperAddr = Val.IPv4Addr; 801 break; 802 803 case 'm': 804 pCurCfg->m_SubnetMask = Val.IPv4Addr; 805 break; 806 807 case 0: /* ignore */ break; 808 default: 809 AssertMsgFailed(("%d", rc)); 810 return 1; 811 } 812 break; 813 814 case 'V': 815 RTPrintf("%sr%u\n", RTBldCfgVersion(), RTBldCfgRevision()); 816 return 1; 817 818 case 'h': 819 RTPrintf("VBoxNetDHCP Version %s\n" 820 "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n" 821 "All rights reserved.\n" 822 "\n" 823 "Usage: VBoxNetDHCP <options>\n" 824 "\n" 825 "Options:\n", 826 RTBldCfgVersion()); 827 for (size_t i = 0; i < RT_ELEMENTS(s_aOptionDefs); i++) 828 RTPrintf(" -%c, %s\n", s_aOptionDefs[i].iShort, s_aOptionDefs[i].pszLong); 829 return 1; 830 831 default: 832 rc = RTGetOptPrintError(rc, &Val); 833 RTPrintf("Use --help for more information.\n"); 834 return rc; 835 } 836 } 837 838 /* 839 * Do the reconfig. (move this later) 840 */ 841 if (!rc) 842 explodeConfig(); 342 843 343 844 return rc; 344 845 } 345 846 346 int VBoxNetDhcp::init() 347 { 348 HRESULT hrc = S_OK; 349 /* ok, here we should initiate instance of dhcp server 350 * and listener for Dhcp configuration events 351 */ 352 AssertRCReturn(virtualbox.isNull(), VERR_INTERNAL_ERROR); 353 354 hrc = virtualbox->FindDHCPServerByNetworkName(com::Bstr(m_Network.c_str()).raw(), 355 m_DhcpServer.asOutParam()); 356 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); 357 358 hrc = virtualbox->FindNATNetworkByName(com::Bstr(m_Network.c_str()).raw(), 359 m_NATNetwork.asOutParam()); 360 361 /* This isn't fatal in general case. 362 * AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); 363 */ 364 365 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager(); 366 AssertPtrReturn(confManager, VERR_INTERNAL_ERROR); 367 368 /** 369 * if we have nat netework of the same name 370 * this is good chance that we are assigned to this network. 371 */ 372 BOOL fNeedDhcpServer = false; 373 if ( !m_NATNetwork.isNull() 374 && SUCCEEDED(m_NATNetwork->COMGETTER(NeedDhcpServer)(&fNeedDhcpServer)) 375 && fNeedDhcpServer) 376 { 377 /* 90% we are servicing NAT network */ 378 RTNETADDRIPV4 gateway; 379 com::Bstr strGateway; 380 hrc = m_NATNetwork->GetGateway(strGateway.asOutParam()); 381 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); 382 RTNetStrToIPv4Addr(com::Utf8Str(strGateway).c_str(), &gateway); 383 384 confManager->addToAddressList(RTNET_DHCP_OPT_ROUTERS, gateway); 385 } 386 387 NetworkManager *netManager = NetworkManager::getNetworkManager(); 388 389 netManager->setOurAddress(m_Ipv4Address); 390 netManager->setOurNetmask(m_Ipv4Netmask); 391 netManager->setOurMac(m_MacAddress); 392 393 /* Configuration fetching */ 394 if (m_fIgnoreCmdLineParameters) 395 { 396 /* just fetch option array and add options to config */ 397 /* per VM-settings ??? 398 * 399 * - we have vms with attached adapters with known mac-addresses 400 * - mac-addresses might be changed as well as names, how keep our config cleaned ???? 847 848 /** 849 * Tries to connect to the internal network. 850 * 851 * @returns 0 on success, exit code + error message to stderr on failure. 852 */ 853 int VBoxNetDhcp::tryGoOnline(void) 854 { 855 /* 856 * Open the session, load ring-0 and issue the request. 857 */ 858 int rc = SUPR3Init(&m_pSession); 859 if (RT_FAILURE(rc)) 860 { 861 m_pSession = NIL_RTR0PTR; 862 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3Init -> %Rrc", rc); 863 return 1; 864 } 865 866 char szPath[RTPATH_MAX]; 867 rc = RTPathExecDir(szPath, sizeof(szPath) - sizeof("/VMMR0.r0")); 868 if (RT_FAILURE(rc)) 869 { 870 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: RTPathProgram -> %Rrc", rc); 871 return 1; 872 } 873 874 rc = SUPR3LoadVMM(strcat(szPath, "/VMMR0.r0")); 875 if (RT_FAILURE(rc)) 876 { 877 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3LoadVMM(\"%s\") -> %Rrc", szPath, rc); 878 return 1; 879 } 880 881 /* 882 * Create the open request. 883 */ 884 INTNETOPENREQ OpenReq; 885 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 886 OpenReq.Hdr.cbReq = sizeof(OpenReq); 887 OpenReq.pSession = m_pSession; 888 strncpy(OpenReq.szNetwork, m_Network.c_str(), sizeof(OpenReq.szNetwork)); 889 OpenReq.szNetwork[sizeof(OpenReq.szNetwork) - 1] = '\0'; 890 strncpy(OpenReq.szTrunk, m_TrunkName.c_str(), sizeof(OpenReq.szTrunk)); 891 OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0'; 892 OpenReq.enmTrunkType = m_enmTrunkType; 893 OpenReq.fFlags = 0; /** @todo check this */ 894 OpenReq.cbSend = m_cbSendBuf; 895 OpenReq.cbRecv = m_cbRecvBuf; 896 OpenReq.hIf = INTNET_HANDLE_INVALID; 897 898 /* 899 * Issue the request. 900 */ 901 debugPrint(2, false, "attempting to open/create network \"%s\"...", OpenReq.szNetwork); 902 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_OPEN, 0, &OpenReq.Hdr); 903 if (RT_SUCCESS(rc)) 904 { 905 m_hIf = OpenReq.hIf; 906 debugPrint(1, false, "successfully opened/created \"%s\" - hIf=%#x", OpenReq.szNetwork, m_hIf); 907 908 /* 909 * Get the ring-3 address of the shared interface buffer. 401 910 */ 402 com::SafeArray<BSTR> sf; 403 hrc = m_DhcpServer->GetGlobalOptions(ComSafeArrayAsOutParam(sf)); 404 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); 405 406 #if 0 407 for (int i = 0; i < sf.size(); ++i) 408 { 409 RTPrintf("%d: %s\n", i, com::Utf8Str(sf[i]).c_str()); 410 } 411 412 #endif 413 com::Bstr strUpperIp, strLowerIp; 414 415 RTNETADDRIPV4 LowerAddress; 416 RTNETADDRIPV4 UpperAddress; 417 418 hrc = m_DhcpServer->GetUpperIP(strUpperIp.asOutParam()); 419 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); 420 RTNetStrToIPv4Addr(com::Utf8Str(strUpperIp).c_str(), &UpperAddress); 421 422 423 hrc = m_DhcpServer->GetLowerIP(strLowerIp.asOutParam()); 424 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); 425 RTNetStrToIPv4Addr(com::Utf8Str(strLowerIp).c_str(), &LowerAddress); 426 427 RTNETADDRIPV4 networkId; 428 networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u; 429 std::string name = std::string("default"); 430 431 NetworkConfigEntity *pCfg = confManager->addNetwork(unconst(g_RootConfig), 432 networkId, 433 m_Ipv4Netmask, 434 LowerAddress, 435 UpperAddress); 436 437 } /* if(m_fIgnoreCmdLineParameters) */ 911 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq; 912 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 913 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq); 914 GetBufferPtrsReq.pSession = m_pSession; 915 GetBufferPtrsReq.hIf = m_hIf; 916 GetBufferPtrsReq.pRing3Buf = NULL; 917 GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR; 918 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0, &GetBufferPtrsReq.Hdr); 919 if (RT_SUCCESS(rc)) 920 { 921 PINTNETBUF pBuf = GetBufferPtrsReq.pRing3Buf; 922 debugPrint(1, false, "pBuf=%p cbBuf=%d cbSend=%d cbRecv=%d", 923 pBuf, pBuf->cbBuf, pBuf->cbSend, pBuf->cbRecv); 924 m_pIfBuf = pBuf; 925 926 /* 927 * Activate the interface. 928 */ 929 INTNETIFSETACTIVEREQ ActiveReq; 930 ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 931 ActiveReq.Hdr.cbReq = sizeof(ActiveReq); 932 ActiveReq.pSession = m_pSession; 933 ActiveReq.hIf = m_hIf; 934 ActiveReq.fActive = true; 935 rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_SET_ACTIVE, 0, &ActiveReq.Hdr); 936 if (RT_SUCCESS(rc)) 937 return 0; 938 939 /* bail out */ 940 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE,) failed, rc=%Rrc\n", rc); 941 } 942 else 943 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS,) failed, rc=%Rrc\n", rc); 944 } 438 945 else 439 { 440 CmdParameterIterator it; 441 442 RTNETADDRIPV4 networkId; 443 networkId.u = m_Ipv4Address.u & m_Ipv4Netmask.u; 444 RTNETADDRIPV4 netmask = m_Ipv4Netmask; 445 RTNETADDRIPV4 LowerAddress; 446 RTNETADDRIPV4 UpperAddress; 447 448 LowerAddress = networkId; 449 UpperAddress.u = RT_H2N_U32(RT_N2H_U32(LowerAddress.u) | RT_N2H_U32(netmask.u)); 450 451 int idx = 0; 452 char name[64]; 453 454 455 for (it = CmdParameterll.begin(); it != CmdParameterll.end(); ++it) 456 { 457 idx++; 458 RTStrPrintf(name, RT_ELEMENTS(name), "network-%d", idx); 459 std::string strname(name); 460 461 switch(it->Key) 462 { 463 case 'b': 464 /* config */ 465 NetworkConfigEntity(strname, 466 g_RootConfig, 467 g_AnyClient, 468 5, 469 networkId, 470 netmask, 471 LowerAddress, 472 UpperAddress); 473 case 'l': 474 case 'u': 475 case 'm': 476 case 'g': 477 /* XXX: TBD */ 478 break; 479 } 480 } 481 } 482 return VINF_SUCCESS; 483 } 946 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: SUPR3CallVMMR0Ex(,VMMR0_DO_INTNET_OPEN,) failed, rc=%Rrc\n", rc); 947 948 return RT_SUCCESS(rc) ? 0 : 1; 949 } 950 484 951 485 952 /** … … 491 958 int VBoxNetDhcp::run(void) 492 959 { 493 494 /* XXX: shortcut should be hidden from network manager */495 NetworkManager *netManager = NetworkManager::getNetworkManager();496 netManager->m_pSession = m_pSession;497 netManager->m_hIf = m_hIf;498 netManager->m_pIfBuf = m_pIfBuf;499 500 960 /* 501 961 * The loop. … … 614 1074 bool VBoxNetDhcp::handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb) 615 1075 { 616 617 /* let's main first */ 618 if (!m_DhcpServer.isNull()) 619 { 620 HRESULT hrc; 621 com::SafeArray<BSTR> sf; 622 hrc = m_DhcpServer->GetMacOptions(com::BstrFmt("%02X%02X%02X%02X%02X%02X", 623 pDhcpMsg->bp_chaddr.Mac.au8[0], 624 pDhcpMsg->bp_chaddr.Mac.au8[1], 625 pDhcpMsg->bp_chaddr.Mac.au8[2], 626 pDhcpMsg->bp_chaddr.Mac.au8[3], 627 pDhcpMsg->bp_chaddr.Mac.au8[4], 628 pDhcpMsg->bp_chaddr.Mac.au8[5], 629 pDhcpMsg->bp_chaddr.Mac.au8[6]).raw(), 630 ComSafeArrayAsOutParam(sf)); 631 if (SUCCEEDED(hrc)) 632 { 633 /* XXX: per-host configuration */ 634 } 635 636 SessionManager *sesionManager = SessionManager::getSessionManager(); 637 Session& session = sesionManager->getClientSessionByDhcpPacket(pDhcpMsg, cb); 638 /* XXX: switch -> private */ 639 session.switchTo(DHCPDISCOVERRECEIEVED); 640 641 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager(); 642 int rc = confManager->findConfiguration4Session(session); 643 AssertRCReturn(rc, rc); 644 645 rc = confManager->allocateConfiguration4Session(session); 646 AssertRCReturn(rc, rc); 647 648 NetworkManager *netManager = NetworkManager::getNetworkManager(); 649 rc = netManager->offer4Session(session); 650 AssertRCReturn(rc, rc); 651 652 653 } /* end of if(!m_DhcpServer.isNull()) */ 654 655 return VINF_SUCCESS; 1076 /* 1077 * The newLease() method contains logic for finding current leases 1078 * and reusing them in case the client is forgetful. 1079 */ 1080 VBoxNetDhcpLease *pLease = newLease(pDhcpMsg, cb); 1081 if (!pLease) 1082 return false; 1083 debugPrint(1, true, "Offering %d.%d.%d.%d to %.6Rhxs xid=%#x", 1084 pLease->m_IPv4Address.au8[0], 1085 pLease->m_IPv4Address.au8[1], 1086 pLease->m_IPv4Address.au8[2], 1087 pLease->m_IPv4Address.au8[3], 1088 &pDhcpMsg->bp_chaddr.Mac, 1089 pDhcpMsg->bp_xid); 1090 pLease->offer(pDhcpMsg->bp_xid); 1091 1092 makeDhcpReply(RTNET_DHCP_MT_OFFER, pLease, pDhcpMsg, cb); 1093 return true; 656 1094 } 657 1095 … … 667 1105 bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb) 668 1106 { 669 SessionManager *sesionManager = SessionManager::getSessionManager(); 670 Session& session = sesionManager->getClientSessionByDhcpPacket(pDhcpMsg, cb); 671 /* XXX: switch -> private */ 672 session.switchTo(DHCPREQUESTRECEIVED); 673 674 ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager(); 675 int rc = confManager->findConfiguration4Session(session); 676 AssertRCReturn(rc, false); 677 678 rc = confManager->commitConfiguration4ClientSession(session); 679 680 NetworkManager *netManager = NetworkManager::getNetworkManager(); 681 if (RT_SUCCESS(rc)) 682 rc = netManager->ack(session); 1107 /** @todo Probably need to match the server IP here to work correctly with 1108 * other servers. */ 1109 /** @todo This code isn't entirely correct and quite a bit of a hack, but it 1110 * will have to do for now as the right thing (tm) is very complex. 1111 * Part of the fun is verifying that the request is something we can 1112 * and should handle. */ 1113 1114 /* 1115 * Try find the lease by the requested address + client MAC address. 1116 */ 1117 VBoxNetDhcpLease *pLease = NULL; 1118 RTNETADDRIPV4 IPv4Addr; 1119 bool fReqAddr = findOptionIPv4Addr(RTNET_DHCP_OPT_REQ_ADDR, pDhcpMsg, cb, &IPv4Addr); 1120 if (fReqAddr) 1121 { 1122 fReqAddr = true; 1123 pLease = findLeaseByIpv4AndMacAddresses(IPv4Addr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */); 1124 } 1125 1126 /* 1127 * Try find the lease by the client IP address + client MAC address. 1128 */ 1129 if ( !pLease 1130 && pDhcpMsg->bp_ciaddr.u) 1131 pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */); 1132 1133 #if 0 /** @todo client id stuff - it doesn't make sense here imho, we need IP + MAC. What would make sense 1134 though is to compare the client id with what we've got in the lease and use it to root out 1135 bad requests. */ 1136 /* 1137 * Try find the lease by using the client id. 1138 */ 1139 if (!pLease) 1140 { 1141 size_t cbClientID = 0; 1142 uint8_t const *pbClientID = findOption(RTNET_DHCP_OPT_CLIENT_ID, pDhcpMsg, cb, &cbClientID); 1143 if ( pbClientID 1144 && cbClientID == sizeof(RTMAC) + 1 1145 && pbClientID[0] == RTNET_ARP_ETHER 1146 && 1147 ) 1148 { 1149 pLease = findLeaseByIpv4AndMacAddresses(pDhcpMsg->bp_ciaddr, &pDhcpMsg->bp_chaddr.Mac, true /* fAnyState */); 1150 } 1151 } 1152 #endif 1153 1154 /* 1155 * Validate the lease that's requested. 1156 * We've already check the MAC and IP addresses. 1157 */ 1158 bool fAckIt = false; 1159 if (pLease) 1160 { 1161 if (pLease->isBeingOffered()) 1162 { 1163 if (pLease->m_xid == pDhcpMsg->bp_xid) 1164 debugPrint(2, true, "REQUEST for offered lease."); 1165 else 1166 debugPrint(2, true, "REQUEST for offered lease, xid mismatch. Expected %#x, got %#x.", 1167 pLease->m_xid, pDhcpMsg->bp_xid); 1168 pLease->activate(pDhcpMsg->bp_xid); 1169 fAckIt = true; 1170 } 1171 else if (!pLease->isInCurrentConfig()) 1172 debugPrint(1, true, "REQUEST for obsolete lease -> NAK"); 1173 else if (fReqAddr != (pDhcpMsg->bp_ciaddr.u != 0)) // ??? 1174 { 1175 /** @todo this ain't safe. */ 1176 debugPrint(1, true, "REQUEST for lease not on offer, assuming renewal. lease_xid=%#x bp_xid=%#x", 1177 pLease->m_xid, pDhcpMsg->bp_xid); 1178 fAckIt = true; 1179 pLease->activate(pDhcpMsg->bp_xid); 1180 } 1181 else 1182 debugPrint(1, true, "REQUEST for lease not on offer, NAK it."); 1183 } 1184 1185 /* 1186 * NAK if if no lease was found. 1187 */ 1188 if (fAckIt) 1189 { 1190 debugPrint(1, false, "ACK'ing DHCP_REQUEST"); 1191 makeDhcpReply(RTNET_DHCP_MT_ACK, pLease, pDhcpMsg, cb); 1192 } 683 1193 else 684 rc = netManager->nak(session); 685 686 AssertRCReturn(rc, false); 1194 { 1195 debugPrint(1, false, "NAK'ing DHCP_REQUEST"); 1196 makeDhcpReply(RTNET_DHCP_MT_NAC, NULL, pDhcpMsg, cb); 1197 } 687 1198 688 1199 return true; … … 749 1260 debugPrint(1, true, "RELEASE is not implemented"); 750 1261 return true; 1262 } 1263 1264 1265 /** 1266 * Helper class for stuffing DHCP options into a reply packet. 1267 */ 1268 class VBoxNetDhcpWriteCursor 1269 { 1270 private: 1271 uint8_t *m_pbCur; /**< The current cursor position. */ 1272 uint8_t *m_pbEnd; /**< The end the current option space. */ 1273 uint8_t *m_pfOverload; /**< Pointer to the flags of the overload option. */ 1274 uint8_t m_fUsed; /**< Overload fields that have been used. */ 1275 PRTNETDHCPOPT m_pOpt; /**< The current option. */ 1276 PRTNETBOOTP m_pDhcp; /**< The DHCP packet. */ 1277 bool m_fOverflowed; /**< Set if we've overflowed, otherwise false. */ 1278 1279 public: 1280 /** Instantiate an option cursor for the specified DHCP message. */ 1281 VBoxNetDhcpWriteCursor(PRTNETBOOTP pDhcp, size_t cbDhcp) : 1282 m_pbCur(&pDhcp->bp_vend.Dhcp.dhcp_opts[0]), 1283 m_pbEnd((uint8_t *)pDhcp + cbDhcp), 1284 m_pfOverload(NULL), 1285 m_fUsed(0), 1286 m_pOpt(NULL), 1287 m_pDhcp(pDhcp), 1288 m_fOverflowed(false) 1289 { 1290 AssertPtr(pDhcp); 1291 Assert(cbDhcp > RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts[10])); 1292 } 1293 1294 /** Destructor. */ 1295 ~VBoxNetDhcpWriteCursor() 1296 { 1297 m_pbCur = m_pbEnd = m_pfOverload = NULL; 1298 m_pOpt = NULL; 1299 m_pDhcp = NULL; 1300 } 1301 1302 /** 1303 * Try use the bp_file field. 1304 * @returns true if not overloaded, false otherwise. 1305 */ 1306 bool useBpFile(void) 1307 { 1308 if ( m_pfOverload 1309 && (*m_pfOverload & 1)) 1310 return false; 1311 m_fUsed |= 1 /* bp_file flag*/; 1312 return true; 1313 } 1314 1315 1316 /** 1317 * Try overload more BOOTP fields 1318 */ 1319 bool overloadMore(void) 1320 { 1321 /* switch option area. */ 1322 uint8_t *pbNew; 1323 uint8_t *pbNewEnd; 1324 uint8_t fField; 1325 if (!(m_fUsed & 1)) 1326 { 1327 fField = 1; 1328 pbNew = &m_pDhcp->bp_file[0]; 1329 pbNewEnd = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)]; 1330 } 1331 else if (!(m_fUsed & 2)) 1332 { 1333 fField = 2; 1334 pbNew = &m_pDhcp->bp_sname[0]; 1335 pbNewEnd = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)]; 1336 } 1337 else 1338 return false; 1339 1340 if (!m_pfOverload) 1341 { 1342 /* Add an overload option. */ 1343 *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD; 1344 *m_pbCur++ = fField; 1345 m_pfOverload = m_pbCur; 1346 *m_pbCur++ = 1; /* bp_file flag */ 1347 } 1348 else 1349 *m_pfOverload |= fField; 1350 1351 /* pad current option field */ 1352 while (m_pbCur != m_pbEnd) 1353 *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */ 1354 1355 /* switch */ 1356 m_pbCur = pbNew; 1357 m_pbEnd = pbNewEnd; 1358 return true; 1359 } 1360 1361 /** 1362 * Begin an option. 1363 * 1364 * @returns true on success, false if we're out of space. 1365 * 1366 * @param uOption The option number. 1367 * @param cb The amount of data. 1368 */ 1369 bool begin(uint8_t uOption, size_t cb) 1370 { 1371 /* Check that the data of the previous option has all been written. */ 1372 Assert( !m_pOpt 1373 || (m_pbCur - m_pOpt->dhcp_len == (uint8_t *)(m_pOpt + 1))); 1374 AssertMsg(cb <= 255, ("%#x\n", cb)); 1375 1376 /* Check if we need to overload more stuff. */ 1377 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + (m_pfOverload ? 1 : 3)) 1378 { 1379 m_pOpt = NULL; 1380 if (!overloadMore()) 1381 { 1382 m_fOverflowed = true; 1383 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false); 1384 } 1385 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 1) 1386 { 1387 m_fOverflowed = true; 1388 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false); 1389 } 1390 } 1391 1392 /* Emit the option header. */ 1393 m_pOpt = (PRTNETDHCPOPT)m_pbCur; 1394 m_pOpt->dhcp_opt = uOption; 1395 m_pOpt->dhcp_len = (uint8_t)cb; 1396 m_pbCur += 2; 1397 return true; 1398 } 1399 1400 /** 1401 * Puts option data. 1402 * 1403 * @param pvData The data. 1404 * @param cb The amount to put. 1405 */ 1406 void put(void const *pvData, size_t cb) 1407 { 1408 Assert(m_pOpt || m_fOverflowed); 1409 if (RT_LIKELY(m_pOpt)) 1410 { 1411 Assert((uintptr_t)m_pbCur - (uintptr_t)(m_pOpt + 1) + cb <= (size_t)m_pOpt->dhcp_len); 1412 memcpy(m_pbCur, pvData, cb); 1413 m_pbCur += cb; 1414 } 1415 } 1416 1417 /** 1418 * Puts an IPv4 Address. 1419 * 1420 * @param IPv4Addr The address. 1421 */ 1422 void putIPv4Addr(RTNETADDRIPV4 IPv4Addr) 1423 { 1424 put(&IPv4Addr, 4); 1425 } 1426 1427 /** 1428 * Adds an IPv4 address option. 1429 * 1430 * @returns true/false just like begin(). 1431 * 1432 * @param uOption The option number. 1433 * @param IPv4Addr The address. 1434 */ 1435 bool optIPv4Addr(uint8_t uOption, RTNETADDRIPV4 IPv4Addr) 1436 { 1437 if (!begin(uOption, 4)) 1438 return false; 1439 putIPv4Addr(IPv4Addr); 1440 return true; 1441 } 1442 1443 /** 1444 * Adds an option taking 1 or more IPv4 address. 1445 * 1446 * If the vector contains no addresses, the option will not be added. 1447 * 1448 * @returns true/false just like begin(). 1449 * 1450 * @param uOption The option number. 1451 * @param rIPv4Addrs Reference to the address vector. 1452 */ 1453 bool optIPv4Addrs(uint8_t uOption, std::vector<RTNETADDRIPV4> const &rIPv4Addrs) 1454 { 1455 size_t const c = rIPv4Addrs.size(); 1456 if (!c) 1457 return true; 1458 1459 if (!begin(uOption, 4*c)) 1460 return false; 1461 for (size_t i = 0; i < c; i++) 1462 putIPv4Addr(rIPv4Addrs[i]); 1463 return true; 1464 } 1465 1466 /** 1467 * Puts an 8-bit integer. 1468 * 1469 * @param u8 The integer. 1470 */ 1471 void putU8(uint8_t u8) 1472 { 1473 put(&u8, 1); 1474 } 1475 1476 /** 1477 * Adds an 8-bit integer option. 1478 * 1479 * @returns true/false just like begin(). 1480 * 1481 * @param uOption The option number. 1482 * @param u8 The integer 1483 */ 1484 bool optU8(uint8_t uOption, uint8_t u8) 1485 { 1486 if (!begin(uOption, 1)) 1487 return false; 1488 putU8(u8); 1489 return true; 1490 } 1491 1492 /** 1493 * Puts an 32-bit integer (network endian). 1494 * 1495 * @param u32Network The integer. 1496 */ 1497 void putU32(uint32_t u32) 1498 { 1499 put(&u32, 4); 1500 } 1501 1502 /** 1503 * Adds an 32-bit integer (network endian) option. 1504 * 1505 * @returns true/false just like begin(). 1506 * 1507 * @param uOption The option number. 1508 * @param u32Network The integer. 1509 */ 1510 bool optU32(uint8_t uOption, uint32_t u32) 1511 { 1512 if (!begin(uOption, 4)) 1513 return false; 1514 putU32(u32); 1515 return true; 1516 } 1517 1518 /** 1519 * Puts a std::string. 1520 * 1521 * @param rStr Reference to the string. 1522 */ 1523 void putStr(std::string const &rStr) 1524 { 1525 put(rStr.c_str(), rStr.size()); 1526 } 1527 1528 /** 1529 * Adds an std::string option if the string isn't empty. 1530 * 1531 * @returns true/false just like begin(). 1532 * 1533 * @param uOption The option number. 1534 * @param rStr Reference to the string. 1535 */ 1536 bool optStr(uint8_t uOption, std::string const &rStr) 1537 { 1538 const size_t cch = rStr.size(); 1539 if (!cch) 1540 return true; 1541 1542 if (!begin(uOption, cch)) 1543 return false; 1544 put(rStr.c_str(), cch); 1545 return true; 1546 } 1547 1548 /** 1549 * Whether we've overflowed. 1550 * 1551 * @returns true on overflow, false otherwise. 1552 */ 1553 bool hasOverflowed(void) const 1554 { 1555 return m_fOverflowed; 1556 } 1557 1558 /** 1559 * Adds the terminating END option. 1560 * 1561 * The END will always be added as we're reserving room for it, however, we 1562 * might have dropped previous options due to overflows and that is what the 1563 * return status indicates. 1564 * 1565 * @returns true on success, false on a (previous) overflow. 1566 */ 1567 bool optEnd(void) 1568 { 1569 Assert((uintptr_t)(m_pbEnd - m_pbCur) < 4096); 1570 *m_pbCur++ = RTNET_DHCP_OPT_END; 1571 return !hasOverflowed(); 1572 } 1573 }; 1574 1575 1576 /** 1577 * Constructs and sends a reply to a client. 1578 * 1579 * @returns 1580 * @param uMsgType The DHCP message type. 1581 * @param pLease The lease. This can be NULL for some replies. 1582 * @param pDhcpMsg The client message. We will dig out the MAC address, 1583 * transaction ID, and requested options from this. 1584 * @param cb The size of the client message. 1585 */ 1586 void VBoxNetDhcp::makeDhcpReply(uint8_t uMsgType, VBoxNetDhcpLease *pLease, PCRTNETBOOTP pDhcpMsg, size_t cb) 1587 { 1588 size_t cbReply = RTNET_DHCP_NORMAL_SIZE; /** @todo respect the RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE option */ 1589 PRTNETBOOTP pReply = (PRTNETBOOTP)alloca(cbReply); 1590 1591 /* 1592 * The fixed bits stuff. 1593 */ 1594 pReply->bp_op = RTNETBOOTP_OP_REPLY; 1595 pReply->bp_htype = RTNET_ARP_ETHER; 1596 pReply->bp_hlen = sizeof(RTMAC); 1597 pReply->bp_hops = 0; 1598 pReply->bp_xid = pDhcpMsg->bp_xid; 1599 pReply->bp_secs = 0; 1600 pReply->bp_flags = 0; // (pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST); ?? 1601 pReply->bp_ciaddr.u = 0; 1602 pReply->bp_yiaddr.u = pLease ? pLease->m_IPv4Address.u : 0xffffffff; 1603 pReply->bp_siaddr.u = pLease && pLease->m_pCfg ? pLease->m_pCfg->m_TftpServerAddr.u : 0; /* (next server == TFTP)*/ 1604 pReply->bp_giaddr.u = 0; 1605 memset(&pReply->bp_chaddr, '\0', sizeof(pReply->bp_chaddr)); 1606 pReply->bp_chaddr.Mac = pDhcpMsg->bp_chaddr.Mac; 1607 memset(&pReply->bp_sname[0], '\0', sizeof(pReply->bp_sname)); 1608 memset(&pReply->bp_file[0], '\0', sizeof(pReply->bp_file)); 1609 pReply->bp_vend.Dhcp.dhcp_cookie = RT_H2N_U32_C(RTNET_DHCP_COOKIE); 1610 memset(&pReply->bp_vend.Dhcp.dhcp_opts[0], '\0', RTNET_DHCP_OPT_SIZE); 1611 1612 /* 1613 * The options - use a cursor class for dealing with the ugly stuff. 1614 */ 1615 VBoxNetDhcpWriteCursor Cursor(pReply, cbReply); 1616 1617 /* The basics */ 1618 Cursor.optU8(RTNET_DHCP_OPT_MSG_TYPE, uMsgType); 1619 Cursor.optIPv4Addr(RTNET_DHCP_OPT_SERVER_ID, m_Ipv4Address); 1620 1621 if (uMsgType != RTNET_DHCP_MT_NAC) 1622 { 1623 AssertReturnVoid(pLease && pLease->m_pCfg); 1624 const VBoxNetDhcpCfg *pCfg = pLease->m_pCfg; /* no need to retain it. */ 1625 1626 /* The IP config. */ 1627 Cursor.optU32(RTNET_DHCP_OPT_LEASE_TIME, RT_H2N_U32(pCfg->m_cSecLease)); 1628 Cursor.optIPv4Addr(RTNET_DHCP_OPT_SUBNET_MASK, pCfg->m_SubnetMask); 1629 Cursor.optIPv4Addrs(RTNET_DHCP_OPT_ROUTERS, pCfg->m_Routers); 1630 Cursor.optIPv4Addrs(RTNET_DHCP_OPT_ROUTERS, pCfg->m_DNSes); 1631 Cursor.optStr(RTNET_DHCP_OPT_HOST_NAME, pCfg->m_HostName); 1632 Cursor.optStr(RTNET_DHCP_OPT_DOMAIN_NAME, pCfg->m_DomainName); 1633 1634 /* The PXE config. */ 1635 if (pCfg->m_BootfileName.size()) 1636 { 1637 if (Cursor.useBpFile()) 1638 RTStrPrintf((char *)&pReply->bp_file[0], sizeof(pReply->bp_file), "%s", pCfg->m_BootfileName.c_str()); 1639 else 1640 Cursor.optStr(RTNET_DHCP_OPT_BOOTFILE_NAME, pCfg->m_BootfileName); 1641 } 1642 } 1643 1644 /* Terminate the options. */ 1645 if (!Cursor.optEnd()) 1646 debugPrint(0, true, "option overflow\n"); 1647 1648 /* 1649 * Send it. 1650 */ 1651 int rc; 1652 #if 0 1653 if (!(pDhcpMsg->bp_flags & RTNET_DHCP_FLAGS_NO_BROADCAST)) /** @todo need to see someone set this flag to check that it's correct. */ 1654 { 1655 RTNETADDRIPV4 IPv4AddrBrdCast; 1656 IPv4AddrBrdCast.u = UINT32_C(0xffffffff); /* broadcast IP */ 1657 rc = VBoxNetUDPUnicast(m_pSession, m_hIf, m_pIfBuf, 1658 m_Ipv4Address, &m_MacAddress, RTNETIPV4_PORT_BOOTPS, /* sender */ 1659 IPv4AddrBrdCast, &pDhcpMsg->bp_chaddr.Mac, RTNETIPV4_PORT_BOOTPC, /* receiver */ 1660 pReply, cbReply); 1661 } 1662 else 1663 #endif 1664 rc = VBoxNetUDPBroadcast(m_pSession, m_hIf, m_pIfBuf, 1665 m_Ipv4Address, &m_MacAddress, RTNETIPV4_PORT_BOOTPS, /* sender */ 1666 RTNETIPV4_PORT_BOOTPC, /* receiver port */ 1667 pReply, cbReply); 1668 if (RT_FAILURE(rc)) 1669 debugPrint(0, true, "error %Rrc when sending the reply", rc); 1670 } 1671 1672 1673 /** 1674 * Look up a lease by MAC address. 1675 * 1676 * @returns Pointer to the lease if found, NULL if not found. 1677 * @param pMacAddress The mac address. 1678 * @param fAnyState Any state. 1679 */ 1680 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByMacAddress(PCRTMAC pMacAddress, bool fAnyState) 1681 { 1682 size_t iLease = m_Leases.size(); 1683 while (iLease-- > 0) 1684 { 1685 VBoxNetDhcpLease *pLease = &m_Leases[iLease]; 1686 if ( pLease 1687 && pLease->m_MacAddress.au16[0] == pMacAddress->au16[0] 1688 && pLease->m_MacAddress.au16[1] == pMacAddress->au16[1] 1689 && pLease->m_MacAddress.au16[2] == pMacAddress->au16[2] 1690 && ( fAnyState 1691 || (pLease->m_enmState != VBoxNetDhcpLease::kState_Free)) ) 1692 return pLease; 1693 } 1694 1695 return NULL; 1696 } 1697 1698 1699 /** 1700 * Look up a lease by IPv4 and MAC addresses. 1701 * 1702 * @returns Pointer to the lease if found, NULL if not found. 1703 * @param IPv4Addr The IPv4 address. 1704 * @param pMacAddress The mac address. 1705 * @param fAnyState Any state. 1706 */ 1707 VBoxNetDhcpLease *VBoxNetDhcp::findLeaseByIpv4AndMacAddresses(RTNETADDRIPV4 IPv4Addr, PCRTMAC pMacAddress, bool fAnyState) 1708 { 1709 size_t iLease = m_Leases.size(); 1710 while (iLease-- > 0) 1711 { 1712 VBoxNetDhcpLease *pLease = &m_Leases[iLease]; 1713 if ( pLease 1714 && pLease->m_IPv4Address.u == IPv4Addr.u 1715 && pLease->m_MacAddress.au16[0] == pMacAddress->au16[0] 1716 && pLease->m_MacAddress.au16[1] == pMacAddress->au16[1] 1717 && pLease->m_MacAddress.au16[2] == pMacAddress->au16[2] 1718 && ( fAnyState 1719 || (pLease->m_enmState != VBoxNetDhcpLease::kState_Free)) ) 1720 return pLease; 1721 } 1722 1723 return NULL; 1724 } 1725 1726 1727 /** 1728 * Creates a new lease for the client specified in the DHCP message. 1729 * 1730 * The caller has already made sure it doesn't already have a lease. 1731 * 1732 * @returns Pointer to the lease if found, NULL+log if not found. 1733 * @param IPv4Addr The IPv4 address. 1734 * @param pMacAddress The MAC address. 1735 */ 1736 VBoxNetDhcpLease *VBoxNetDhcp::newLease(PCRTNETBOOTP pDhcpMsg, size_t cb) 1737 { 1738 RTMAC const MacAddr = pDhcpMsg->bp_chaddr.Mac; 1739 RTTIMESPEC Now; 1740 RTTimeNow(&Now); 1741 1742 /* 1743 * Search the possible leases. 1744 * 1745 * We'll try do all the searches in one pass, that is to say, perfect 1746 * match, old lease, and next free/expired lease. 1747 */ 1748 VBoxNetDhcpLease *pBest = NULL; 1749 VBoxNetDhcpLease *pOld = NULL; 1750 VBoxNetDhcpLease *pFree = NULL; 1751 1752 size_t cLeases = m_Leases.size(); 1753 for (size_t i = 0; i < cLeases; i++) 1754 { 1755 VBoxNetDhcpLease *pCur = &m_Leases[i]; 1756 1757 /* Skip it if no configuration, that means its not in the current config. */ 1758 if (!pCur->m_pCfg) 1759 continue; 1760 1761 /* best */ 1762 if ( pCur->isOneSpecificClient() 1763 && pCur->m_pCfg->matchesMacAddress(&MacAddr)) 1764 { 1765 if ( !pBest 1766 || pBest->m_pCfg->m_MacAddresses.size() < pCur->m_pCfg->m_MacAddresses.size()) 1767 pBest = pCur; 1768 } 1769 1770 /* old lease */ 1771 if ( pCur->m_MacAddress.au16[0] == MacAddr.au16[0] 1772 && pCur->m_MacAddress.au16[1] == MacAddr.au16[1] 1773 && pCur->m_MacAddress.au16[2] == MacAddr.au16[2]) 1774 { 1775 if ( !pOld 1776 || RTTimeSpecGetSeconds(&pCur->m_ExpireTime) > RTTimeSpecGetSeconds(&pFree->m_ExpireTime)) 1777 pOld = pCur; 1778 } 1779 1780 /* expired lease */ 1781 if (!pCur->isInUse(&Now)) 1782 { 1783 if ( !pFree 1784 || RTTimeSpecGetSeconds(&pCur->m_ExpireTime) < RTTimeSpecGetSeconds(&pFree->m_ExpireTime)) 1785 pFree = pCur; 1786 } 1787 } 1788 1789 VBoxNetDhcpLease *pNew = pBest; 1790 if (!pNew) 1791 pNew = pOld; 1792 if (!pNew) 1793 pNew = pFree; 1794 if (!pNew) 1795 { 1796 debugPrint(0, true, "No more leases."); 1797 return NULL; 1798 } 1799 1800 /* 1801 * Init the lease. 1802 */ 1803 pNew->m_MacAddress = MacAddr; 1804 pNew->m_xid = pDhcpMsg->bp_xid; 1805 /** @todo extract the client id. */ 1806 1807 return pNew; 1808 } 1809 1810 1811 /** 1812 * Finds an option. 1813 * 1814 * @returns On success, a pointer to the first byte in the option data (no none 1815 * then it'll be the byte following the 0 size field) and *pcbOpt set 1816 * to the option length. 1817 * On failure, NULL is returned and *pcbOpt unchanged. 1818 * 1819 * @param uOption The option to search for. 1820 * @param pDhcpMsg The DHCP message. 1821 * @param cb The size of the message. 1822 * @param pcbOpt Where to store the option size size. Optional. Note 1823 * that this is adjusted if the option length is larger 1824 * than the message buffer. 1825 */ 1826 /* static */ const uint8_t * 1827 VBoxNetDhcp::findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, size_t *pcbOpt) 1828 { 1829 Assert(uOption != RTNET_DHCP_OPT_PAD); 1830 1831 /* 1832 * Validate the DHCP bits and figure the max size of the options in the vendor field. 1833 */ 1834 if (cb <= RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts)) 1835 return NULL; 1836 if (pDhcpMsg->bp_vend.Dhcp.dhcp_cookie != RT_H2N_U32_C(RTNET_DHCP_COOKIE)) 1837 return NULL; 1838 size_t cbLeft = cb - RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts); 1839 if (cbLeft > RTNET_DHCP_OPT_SIZE) 1840 cbLeft = RTNET_DHCP_OPT_SIZE; 1841 1842 /* 1843 * Search the vendor field. 1844 */ 1845 bool fExtended = false; 1846 uint8_t const *pb = &pDhcpMsg->bp_vend.Dhcp.dhcp_opts[0]; 1847 while (pb && cbLeft > 0) 1848 { 1849 uint8_t uCur = *pb; 1850 if (uCur == RTNET_DHCP_OPT_PAD) 1851 { 1852 cbLeft--; 1853 pb++; 1854 } 1855 else if (cbLeft <= 1) 1856 break; 1857 else 1858 { 1859 size_t cbCur = pb[1]; 1860 if (cbCur > cbLeft - 2) 1861 cbCur = cbLeft - 2; 1862 if (uCur == uOption) 1863 { 1864 if (pcbOpt) 1865 *pcbOpt = cbCur; 1866 return pb+2; 1867 } 1868 pb += cbCur + 2; 1869 cbLeft -= cbCur - 2; 1870 } 1871 } 1872 1873 /** @todo search extended dhcp option field(s) when present */ 1874 1875 return NULL; 1876 } 1877 1878 1879 /** 1880 * Locates an option with an IPv4 address in the DHCP message. 1881 * 1882 * @returns true and *pIpv4Addr if found, false if not. 1883 * 1884 * @param uOption The option to find. 1885 * @param pDhcpMsg The DHCP message. 1886 * @param cb The size of the message. 1887 * @param pIPv4Addr Where to put the address. 1888 */ 1889 /* static */ bool 1890 VBoxNetDhcp::findOptionIPv4Addr(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cb, PRTNETADDRIPV4 pIPv4Addr) 1891 { 1892 size_t cbOpt; 1893 uint8_t const *pbOpt = findOption(uOption, pDhcpMsg, cb, &cbOpt); 1894 if (pbOpt) 1895 { 1896 if (cbOpt >= sizeof(RTNETADDRIPV4)) 1897 { 1898 *pIPv4Addr = *(PCRTNETADDRIPV4)pbOpt; 1899 return true; 1900 } 1901 } 1902 return false; 1903 } 1904 1905 1906 /** 1907 * Print debug message depending on the m_cVerbosity level. 1908 * 1909 * @param iMinLevel The minimum m_cVerbosity level for this message. 1910 * @param fMsg Whether to dump parts for the current DHCP message. 1911 * @param pszFmt The message format string. 1912 * @param ... Optional arguments. 1913 */ 1914 inline void VBoxNetDhcp::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const 1915 { 1916 if (iMinLevel <= m_cVerbosity) 1917 { 1918 va_list va; 1919 va_start(va, pszFmt); 1920 debugPrintV(iMinLevel, fMsg, pszFmt, va); 1921 va_end(va); 1922 } 751 1923 } 752 1924 … … 773 1945 && m_pCurMsg) 774 1946 { 775 /* XXX: export this to debugPrinfDhcpMsg or variant and other method export776 * to base class777 */778 1947 const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : ""; 779 1948 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: debug: %8s chaddr=%.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d siaddr=%d.%d.%d.%d xid=%#x\n", … … 834 2003 * Instantiate the DHCP server and hand it the options. 835 2004 */ 836 HRESULT hrc = com::Initialize();837 Assert(!FAILED(hrc));838 839 2005 VBoxNetDhcp *pDhcp = new VBoxNetDhcp(); 840 2006 if (!pDhcp) … … 846 2012 if (rc) 847 2013 return rc; 848 849 pDhcp->init();850 2014 851 2015 /* -
trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp
r46962 r46969 1 1 /* $Id$ */ 2 2 /** @file 3 * VBoxNetBaseService - Base Service class for connecting to IntNet. 4 */ 3 * VBoxNetDHCP - DHCP Service for connecting to IntNet. 4 */ 5 /** @todo r=bird: Cut&Past rules... Please fix DHCP refs! */ 5 6 6 7 /* … … 21 22 #define LOG_GROUP LOG_GROUP_NET_SERVICE 22 23 23 #include <VBox/com/com.h>24 #include <VBox/com/listeners.h>25 #include <VBox/com/string.h>26 #include <VBox/com/Guid.h>27 #include <VBox/com/array.h>28 #include <VBox/com/ErrorInfo.h>29 #include <VBox/com/errorprint.h>30 #include <VBox/com/EventQueue.h>31 #include <VBox/com/VirtualBox.h>32 33 24 #include <iprt/alloca.h> 34 25 #include <iprt/buildconfig.h> … … 39 30 #include <iprt/param.h> 40 31 #include <iprt/path.h> 41 #include <iprt/process.h>42 32 #include <iprt/stream.h> 43 33 #include <iprt/string.h> 44 34 #include <iprt/time.h> 45 35 #include <iprt/mem.h> 46 #include <iprt/message.h>47 36 48 37 #include <VBox/sup.h> … … 55 44 #include <string> 56 45 57 #include <VBox/err.h>58 46 #include <VBox/log.h> 59 47 … … 70 58 * Structures and Typedefs * 71 59 *******************************************************************************/ 72 73 /*******************************************************************************74 * Global Variables *75 *******************************************************************************/76 /* Commonly used options for network configuration */77 60 static RTGETOPTDEF g_aGetOptDef[] = 78 61 { … … 86 69 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 87 70 }; 88 89 90 71 VBoxNetBaseService::VBoxNetBaseService() 91 72 { 92 int rc = RTCritSectInit(&m_csThis); 93 AssertRC(rc); 94 /* numbers from DrvIntNet */ 95 m_cbSendBuf = 128 * _1K; 96 m_cbRecvBuf = 256 * _1K; 97 m_hIf = INTNET_HANDLE_INVALID; 98 m_pIfBuf = NULL; 99 100 m_cVerbosity = 0; 101 m_Name = "VBoxNetNAT"; 102 m_Network = "intnet"; 103 104 for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i) 105 m_vecOptionDefs.push_back(&g_aGetOptDef[i]); 106 107 HRESULT hrc = virtualbox.createLocalObject(CLSID_VirtualBox); 108 if (FAILED(hrc)) 109 RTMsgError("Failed to create the VirtualBox object!"); 110 } 111 112 73 int rc = RTCritSectInit(&m_csThis); 74 AssertRC(rc); 75 } 113 76 VBoxNetBaseService::~VBoxNetBaseService() 114 77 { … … 136 99 } 137 100 138 139 101 int VBoxNetBaseService::init() 140 102 { 103 /* numbers from DrvIntNet */ 104 m_cbSendBuf = 128 * _1K; 105 m_cbRecvBuf = 256 * _1K; 106 m_hIf = INTNET_HANDLE_INVALID; 107 m_pIfBuf = NULL; 108 109 m_cVerbosity = 0; 110 m_Name = "VBoxNetNAT"; 111 m_Network = "intnet"; 112 for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i) 113 m_vecOptionDefs.push_back(&g_aGetOptDef[i]); 141 114 return VINF_SUCCESS; 142 115 } 143 144 145 116 /** 146 117 * Parse the arguments. … … 217 188 218 189 case 'h': 219 RTPrintf(" %sVersion %s\n"190 RTPrintf("VBoxNetDHCP Version %s\n" 220 191 "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n" 221 192 "All rights reserved.\n" 222 193 "\n" 223 "Usage: %s<options>\n"194 "Usage: VBoxNetDHCP <options>\n" 224 195 "\n" 225 196 "Options:\n", 226 RTProcShortName(),227 RTProcShortName(),228 RTProcShortName(),229 197 RTBldCfgVersion()); 230 198 for (unsigned int i = 0; i < m_vecOptionDefs.size(); i++) … … 247 215 return rc; 248 216 } 249 250 217 251 218 int VBoxNetBaseService::tryGoOnline(void) … … 350 317 } 351 318 352 353 319 void VBoxNetBaseService::shutdown(void) 354 320 { 355 321 } 356 357 322 358 323 int VBoxNetBaseService::waitForIntNetEvent(int cMillis) … … 412 377 } 413 378 414 415 379 /** 416 380 * Print debug message depending on the m_cVerbosity level. 417 381 * 418 382 * @param iMinLevel The minimum m_cVerbosity level for this message. 419 * @param fMsg Whether to dump parts for the current service message. 383 * @param fMsg Whether to dump parts for the current DHCP message. 384 * @param pszFmt The message format string. 385 * @param ... Optional arguments. 386 */ 387 inline void VBoxNetBaseService::debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const 388 { 389 if (iMinLevel <= m_cVerbosity) 390 { 391 va_list va; 392 va_start(va, pszFmt); 393 debugPrintV(iMinLevel, fMsg, pszFmt, va); 394 va_end(va); 395 } 396 } 397 398 399 /** 400 * Print debug message depending on the m_cVerbosity level. 401 * 402 * @param iMinLevel The minimum m_cVerbosity level for this message. 403 * @param fMsg Whether to dump parts for the current DHCP message. 420 404 * @param pszFmt The message format string. 421 405 * @param va Optional arguments. … … 427 411 va_list vaCopy; /* This dude is *very* special, thus the copy. */ 428 412 va_copy(vaCopy, va); 429 RTStrmPrintf(g_pStdErr, "%s: %s: %N\n", 430 RTProcShortName(), 431 iMinLevel >= 2 ? "debug" : "info", 432 pszFmt, 433 &vaCopy); 413 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy); 434 414 va_end(vaCopy); 435 415 } 436 416 437 417 } 438 439 418 440 419 PRTGETOPTDEF VBoxNetBaseService::getOptionsPtr() -
trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h
r46962 r46969 18 18 #ifndef ___VBoxNetBaseService_h___ 19 19 #define ___VBoxNetBaseService_h___ 20 21 20 #include <iprt/critsect.h> 22 21 class VBoxNetBaseService … … 33 32 int sendBufferOnWire(PCINTNETSEG pSg, int cSg, size_t cbBuffer); 34 33 void flushWire(); 35 36 34 virtual void usage(void) = 0; 37 virtual int run(void) = 0; 35 virtual void run(void) = 0; 36 virtual int init(void); 38 37 virtual int parseOpt(int rc, const RTGETOPTUNION& getOptVal) = 0; 39 38 40 virtual int init(void); 41 42 /* VirtualBox instance */ 43 ComPtr<IVirtualBox> virtualbox; 44 45 protected: 46 /** 47 * Print debug message depending on the m_cVerbosity level. 48 * 49 * @param iMinLevel The minimum m_cVerbosity level for this message. 50 * @param fMsg Whether to dump parts for the current DHCP message. 51 * @param pszFmt The message format string. 52 * @param ... Optional arguments. 53 */ 54 void debugPrint(int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const 55 { 56 if (iMinLevel <= m_cVerbosity) 57 { 58 va_list va; 59 va_start(va, pszFmt); 60 debugPrintV(iMinLevel, fMsg, pszFmt, va); 61 va_end(va); 62 } 63 } 64 65 virtual void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const; 66 39 inline void debugPrint( int32_t iMinLevel, bool fMsg, const char *pszFmt, ...) const; 40 void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const; 41 public: 67 42 /** @name The server configuration data members. 68 43 * @{ */ … … 74 49 RTNETADDRIPV4 m_Ipv4Address; 75 50 RTNETADDRIPV4 m_Ipv4Netmask; 51 /* cs for syncing */ 52 RTCRITSECT m_csThis; 76 53 /** @} */ 77 54 /** @name The network interface … … 89 66 private: 90 67 PRTGETOPTDEF getOptionsPtr(); 91 92 /* cs for syncing */93 RTCRITSECT m_csThis;94 95 68 /** @} */ 96 69 };
Note:
See TracChangeset
for help on using the changeset viewer.