Changeset 46962 in vbox for trunk/src/VBox/NetworkServices
- Timestamp:
- Jul 4, 2013 5:44:31 AM (11 years ago)
- Location:
- trunk/src/VBox/NetworkServices
- Files:
-
- 1 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/DHCP/Makefile.kmk
r41477 r46962 33 33 # Hardened VBoxNetDHCP. 34 34 # 35 VBoxNetDHCPHardened_TEMPLATE = VBOX R3HARDENEDEXE35 VBoxNetDHCPHardened_TEMPLATE = VBOXMAINCLIENTEXE 36 36 VBoxNetDHCPHardened_SOURCES = VBoxNetDHCPHardened.cpp 37 37 VBoxNetDHCPHardened_NAME = VBoxNetDHCP … … 41 41 # VBoxNetDHCP 42 42 # 43 VBoxNetDHCP_TEMPLATE = 44 VBoxNetDHCP_TEMPLATE := VBOXR3$(if-expr defined(VBOX_WITH_HARDENING),,EXE)43 VBoxNetDHCP_TEMPLATE = VBOXMAINCLIENTEXE 44 #VBoxNetDHCP_TEMPLATE := VBOXR3$(if-expr defined(VBOX_WITH_HARDENING),,EXE) 45 45 VBoxNetDHCP_SOURCES = \ 46 46 VBoxNetDHCP.cpp \ 47 Config.cpp \ 47 48 ../NetLib/VBoxNetIntIf.cpp \ 48 49 ../NetLib/VBoxNetUDP.cpp \ 49 ../NetLib/VBoxNetARP.cpp 50 ../NetLib/VBoxNetARP.cpp \ 51 ../NetLib/VBoxNetBaseService.cpp 50 52 VBoxNetDHCP_LIBS = \ 51 53 $(LIB_RUNTIME) 52 54 VBoxNetDHCP_LDFLAGS.win = /SUBSYSTEM:windows 53 55 56 ifdef VBOX_WITH_TESTCASES 57 PROGRAMS += tstDhcpConfig 58 59 # 60 # VBOXMAINCLIENT here only to use DhcpOpt_T type. 61 tstDhcpConfig_TEMPLATE = VBOXMAINCLIENTEXE 62 #XXX: enable condtionally if user is vvl 63 #tstDhcpConfig_INSTTYPE = none 64 tstDhcpConfig_SOURCES = test/tstDhcpConfig.cpp 65 endif 66 54 67 55 68 include $(FILE_KBUILD_SUB_FOOTER) -
trunk/src/VBox/NetworkServices/DHCP/VBoxNetDHCP.cpp
r44529 r46962 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 27 37 #include <iprt/alloca.h> 28 38 #include <iprt/buildconfig.h> … … 44 54 #include <VBox/version.h> 45 55 56 46 57 #include "../NetLib/VBoxNetLib.h" 47 58 48 59 #include <vector> 60 #include <list> 49 61 #include <string> 62 #include <map> 63 64 #include "../NetLib/VBoxNetBaseService.h" 50 65 51 66 #ifdef RT_OS_WINDOWS /* WinMain */ … … 54 69 #endif 55 70 56 71 #ifndef INET4_ADDRLEN 72 # define INET4_ADDRLEN 17 73 #endif 74 75 #include "Config.h" 57 76 /******************************************************************************* 58 77 * Structures and Typedefs * 59 78 *******************************************************************************/ 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 VBoxNetDhcpCfg67 {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_MAX169 || m_LowerAddr.u == UINT32_MAX170 || 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) const211 {212 return m_LowerAddr.u == m_UpperAddr.u213 && 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) const224 {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 VBoxNetDhcpLease246 {247 public:248 typedef enum State249 {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_Active260 } 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) const313 {314 if ( m_enmState == kState_Offer315 || 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) const331 {332 return m_pCfg333 && 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) const342 {343 return m_enmState == kState_Offer344 && 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't351 * included in the new config. These will have m_pCfg set to NULL and should be352 * freed up when they expired.353 *354 * @returns true / false.355 */356 bool isInCurrentConfig(void) const357 {358 return m_pCfg != NULL;359 }360 };361 362 79 /** 363 80 * DHCP server instance. 364 81 */ 365 class VBoxNetDhcp 82 class VBoxNetDhcp: public VBoxNetBaseService 366 83 { 367 84 public: … … 369 86 virtual ~VBoxNetDhcp(); 370 87 371 int parseArgs(int argc, char **argv); 372 int tryGoOnline(void); 88 int init(); 373 89 int run(void); 90 void usage(void) { /* XXX: document options */ }; 91 int parseOpt(int rc, const RTGETOPTUNION& getOptVal); 374 92 375 93 protected: 376 int addConfig(VBoxNetDhcpCfg *pCfg);377 void explodeConfig(void);378 379 94 bool handleDhcpMsg(uint8_t uMsgType, PCRTNETBOOTP pDhcpMsg, size_t cb); 380 95 bool handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb); … … 382 97 bool handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb); 383 98 bool handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb); 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; 99 394 100 void debugPrintV(int32_t iMinLevel, bool fMsg, const char *pszFmt, va_list va) const; 395 101 static const char *debugDhcpName(uint8_t uMsgType); 396 102 397 103 protected: 398 /** @name The serverconfiguration data members.104 /** @name The DHCP server specific configuration data members. 399 105 * @{ */ 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; 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 */ 406 111 std::string m_LeaseDBName; 112 407 113 /** @} */ 408 114 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 /** @} */ 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; 423 136 424 137 /** @name Debug stuff … … 431 144 /** @} */ 432 145 }; 433 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 434 153 435 154 /******************************************************************************* … … 439 158 static VBoxNetDhcp *g_pDhcp; 440 159 441 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 */ 442 172 /** 443 173 * Offer this lease to a client. … … 505 235 return RTTimeSpecGetSeconds(&m_ExpireTime) > RTTimeSpecGetSeconds(RTTimeNow(&Now)); 506 236 } 507 508 509 237 #endif 510 238 511 239 /** … … 538 266 memset(&m_CurHdrs, '\0', sizeof(m_CurHdrs)); 539 267 268 m_fIgnoreCmdLineParameters = true; 269 540 270 #if 0 /* enable to hack the code without a mile long argument list. */ 541 271 VBoxNetDhcpCfg *pDefCfg = new VBoxNetDhcpCfg(); … … 549 279 pDefCfg->m_DNSes.push_back(Addr); 550 280 pDefCfg->m_DomainName = "vboxnetdhcp.org"; 551 # if 0281 # if 0 552 282 pDefCfg->m_cSecLease = 60*60; /* 1 hour */ 553 # else283 # else 554 284 pDefCfg->m_cSecLease = 30; /* sec */ 555 # endif285 # endif 556 286 pDefCfg->m_TftpServer = "10.0.2.3"; //?? 557 287 this->addConfig(pDefCfg); … … 565 295 VBoxNetDhcp::~VBoxNetDhcp() 566 296 { 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); 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 { 321 /* 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; 580 341 } 581 342 582 if (m_pSession) 583 { 584 SUPR3Term(false /*fForced*/); 585 m_pSession = NIL_RTR0PTR; 343 return rc; 344 } 345 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); 586 385 } 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 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 ???? 401 */ 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) 637 408 { 638 Itr->m_pCfg = NULL; 639 Itr++; 409 RTPrintf("%d: %s\n", i, com::Utf8Str(sf[i]).c_str()); 640 410 } 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++) 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) */ 438 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) 655 456 { 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]; 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 */ 665 478 break; 666 }667 if (pLease)668 {669 if (!pLease->m_pCfg)670 pLease->m_pCfg = pCfg;671 }672 else673 {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 479 } 680 480 } 681 481 } 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 766 /* Begin config. */ 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(); 843 844 return rc; 845 } 846 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. 910 */ 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 } 945 else 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 482 return VINF_SUCCESS; 483 } 951 484 952 485 /** … … 958 491 int VBoxNetDhcp::run(void) 959 492 { 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 960 500 /* 961 501 * The loop. … … 1074 614 bool VBoxNetDhcp::handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb) 1075 615 { 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; 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; 1094 656 } 1095 657 … … 1105 667 bool VBoxNetDhcp::handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb) 1106 668 { 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 } 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); 1193 683 else 1194 { 1195 debugPrint(1, false, "NAK'ing DHCP_REQUEST"); 1196 makeDhcpReply(RTNET_DHCP_MT_NAC, NULL, pDhcpMsg, cb); 1197 } 684 rc = netManager->nak(session); 685 686 AssertRCReturn(rc, false); 1198 687 1199 688 return true; … … 1264 753 1265 754 /** 1266 * Helper class for stuffing DHCP options into a reply packet.1267 */1268 class VBoxNetDhcpWriteCursor1269 {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_pfOverload1309 && (*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 fields1318 */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 else1338 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 else1349 *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_pOpt1373 || (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 integer1483 */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) const1554 {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, we1562 * might have dropped previous options due to overflows and that is what the1563 * 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 * @returns1580 * @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 else1640 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 01653 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 else1663 #endif1664 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 ( pLease1687 && 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 && ( fAnyState1691 || (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 ( pLease1714 && pLease->m_IPv4Address.u == IPv4Addr.u1715 && 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 && ( fAnyState1719 || (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, perfect1746 * 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 ( !pBest1766 || 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 ( !pOld1776 || RTTimeSpecGetSeconds(&pCur->m_ExpireTime) > RTTimeSpecGetSeconds(&pFree->m_ExpireTime))1777 pOld = pCur;1778 }1779 1780 /* expired lease */1781 if (!pCur->isInUse(&Now))1782 {1783 if ( !pFree1784 || 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 none1815 * then it'll be the byte following the 0 size field) and *pcbOpt set1816 * 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. Note1823 * that this is adjusted if the option length is larger1824 * 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 else1858 {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 */ bool1890 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, ...) const1915 {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 }1923 }1924 1925 1926 /**1927 755 * Print debug message depending on the m_cVerbosity level. 1928 756 * … … 1945 773 && m_pCurMsg) 1946 774 { 775 /* XXX: export this to debugPrinfDhcpMsg or variant and other method export 776 * to base class 777 */ 1947 778 const char *pszMsg = m_uCurMsgType != UINT8_MAX ? debugDhcpName(m_uCurMsgType) : ""; 1948 779 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", … … 2003 834 * Instantiate the DHCP server and hand it the options. 2004 835 */ 836 HRESULT hrc = com::Initialize(); 837 Assert(!FAILED(hrc)); 838 2005 839 VBoxNetDhcp *pDhcp = new VBoxNetDhcp(); 2006 840 if (!pDhcp) … … 2012 846 if (rc) 2013 847 return rc; 848 849 pDhcp->init(); 2014 850 2015 851 /* -
trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.cpp
r45114 r46962 1 1 /* $Id$ */ 2 2 /** @file 3 * VBoxNet DHCP - DHCP Servicefor connecting to IntNet.3 * VBoxNetBaseService - Base Service class for connecting to IntNet. 4 4 */ 5 /** @todo r=bird: Cut&Past rules... Please fix DHCP refs! */6 5 7 6 /* … … 22 21 #define LOG_GROUP LOG_GROUP_NET_SERVICE 23 22 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 24 33 #include <iprt/alloca.h> 25 34 #include <iprt/buildconfig.h> … … 30 39 #include <iprt/param.h> 31 40 #include <iprt/path.h> 41 #include <iprt/process.h> 32 42 #include <iprt/stream.h> 33 43 #include <iprt/string.h> 34 44 #include <iprt/time.h> 35 45 #include <iprt/mem.h> 46 #include <iprt/message.h> 36 47 37 48 #include <VBox/sup.h> … … 44 55 #include <string> 45 56 57 #include <VBox/err.h> 46 58 #include <VBox/log.h> 47 59 … … 58 70 * Structures and Typedefs * 59 71 *******************************************************************************/ 72 73 /******************************************************************************* 74 * Global Variables * 75 *******************************************************************************/ 76 /* Commonly used options for network configuration */ 60 77 static RTGETOPTDEF g_aGetOptDef[] = 61 78 { … … 69 86 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 70 87 }; 88 89 71 90 VBoxNetBaseService::VBoxNetBaseService() 72 91 { 73 int rc = RTCritSectInit(&m_csThis); 74 AssertRC(rc); 75 } 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 76 113 VBoxNetBaseService::~VBoxNetBaseService() 77 114 { … … 99 136 } 100 137 138 101 139 int VBoxNetBaseService::init() 102 140 { 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]);114 141 return VINF_SUCCESS; 115 142 } 143 144 116 145 /** 117 146 * Parse the arguments. … … 188 217 189 218 case 'h': 190 RTPrintf(" VBoxNetDHCPVersion %s\n"219 RTPrintf("%s Version %s\n" 191 220 "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n" 192 221 "All rights reserved.\n" 193 222 "\n" 194 "Usage: VBoxNetDHCP<options>\n"223 "Usage: %s <options>\n" 195 224 "\n" 196 225 "Options:\n", 226 RTProcShortName(), 227 RTProcShortName(), 228 RTProcShortName(), 197 229 RTBldCfgVersion()); 198 230 for (unsigned int i = 0; i < m_vecOptionDefs.size(); i++) … … 215 247 return rc; 216 248 } 249 217 250 218 251 int VBoxNetBaseService::tryGoOnline(void) … … 317 350 } 318 351 352 319 353 void VBoxNetBaseService::shutdown(void) 320 354 { 321 355 } 356 322 357 323 358 int VBoxNetBaseService::waitForIntNetEvent(int cMillis) … … 377 412 } 378 413 414 379 415 /** 380 416 * Print debug message depending on the m_cVerbosity level. 381 417 * 382 418 * @param iMinLevel The minimum m_cVerbosity level for this 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. 419 * @param fMsg Whether to dump parts for the current service message. 404 420 * @param pszFmt The message format string. 405 421 * @param va Optional arguments. … … 411 427 va_list vaCopy; /* This dude is *very* special, thus the copy. */ 412 428 va_copy(vaCopy, va); 413 RTStrmPrintf(g_pStdErr, "VBoxNetDHCP: %s: %N\n", iMinLevel >= 2 ? "debug" : "info", pszFmt, &vaCopy); 429 RTStrmPrintf(g_pStdErr, "%s: %s: %N\n", 430 RTProcShortName(), 431 iMinLevel >= 2 ? "debug" : "info", 432 pszFmt, 433 &vaCopy); 414 434 va_end(vaCopy); 415 435 } 416 436 417 437 } 438 418 439 419 440 PRTGETOPTDEF VBoxNetBaseService::getOptionsPtr() -
trunk/src/VBox/NetworkServices/NetLib/VBoxNetBaseService.h
r45114 r46962 18 18 #ifndef ___VBoxNetBaseService_h___ 19 19 #define ___VBoxNetBaseService_h___ 20 20 21 #include <iprt/critsect.h> 21 22 class VBoxNetBaseService … … 32 33 int sendBufferOnWire(PCINTNETSEG pSg, int cSg, size_t cbBuffer); 33 34 void flushWire(); 35 34 36 virtual void usage(void) = 0; 35 virtual void run(void) = 0; 36 virtual int init(void); 37 virtual int run(void) = 0; 37 38 virtual int parseOpt(int rc, const RTGETOPTUNION& getOptVal) = 0; 38 39 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: 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 42 67 /** @name The server configuration data members. 43 68 * @{ */ … … 49 74 RTNETADDRIPV4 m_Ipv4Address; 50 75 RTNETADDRIPV4 m_Ipv4Netmask; 51 /* cs for syncing */52 RTCRITSECT m_csThis;53 76 /** @} */ 54 77 /** @name The network interface … … 66 89 private: 67 90 PRTGETOPTDEF getOptionsPtr(); 91 92 /* cs for syncing */ 93 RTCRITSECT m_csThis; 94 68 95 /** @} */ 69 96 };
Note:
See TracChangeset
for help on using the changeset viewer.