int VBoxNetDhcp::hostDnsServers(const ComHostPtr& host, const RTNETADDRIPV4& networkid, const AddressToOffsetMapping& mapping, AddressList& servers) { ComBstrArray strs; HRESULT hrc = host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs)); if (FAILED(hrc)) return VERR_NOT_FOUND; /* * Recent fashion is to run dnsmasq on 127.0.1.1 which we * currently can't map. If that's the only nameserver we've got, * we need to use DNS proxy for VMs to reach it. */ bool fUnmappedLoopback = false; for (size_t i = 0; i < strs.size(); ++i) { RTNETADDRIPV4 addr; int rc; rc = RTNetStrToIPv4Addr(com::Utf8Str(strs[i]).c_str(), &addr); if (RT_FAILURE(rc)) continue; if (addr.au8[0] == 127) { AddressToOffsetMapping::const_iterator remap(mapping.find(addr)); if (remap != mapping.end()) { int offset = remap->second; addr.u = RT_H2N_U32(RT_N2H_U32(networkid.u) + offset); } else { fUnmappedLoopback = true; continue; } } servers.push_back(addr); } if (servers.empty() && fUnmappedLoopback) { RTNETADDRIPV4 proxy; proxy.u = networkid.u | RT_H2N_U32_C(1U); servers.push_back(proxy); } return VINF_SUCCESS; }
int VBoxNetDhcp::initNoMain() { CmdParameterIterator it; RTNETADDRIPV4 address = getIpv4Address(); RTNETADDRIPV4 netmask = getIpv4Netmask(); RTNETADDRIPV4 networkId; networkId.u = address.u & netmask.u; RTNETADDRIPV4 UpperAddress; RTNETADDRIPV4 LowerAddress = networkId; UpperAddress.u = RT_H2N_U32(RT_N2H_U32(LowerAddress.u) | RT_N2H_U32(netmask.u)); for (it = CmdParameterll.begin(); it != CmdParameterll.end(); ++it) { switch(it->Key) { case 'l': RTNetStrToIPv4Addr(it->strValue.c_str(), &LowerAddress); break; case 'u': RTNetStrToIPv4Addr(it->strValue.c_str(), &UpperAddress); break; case 'b': break; } } ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager(); AssertPtrReturn(confManager, VERR_INTERNAL_ERROR); confManager->addNetwork(unconst(g_RootConfig), networkId, netmask, LowerAddress, UpperAddress); return VINF_SUCCESS; }
bool Lease::fromXML(const xml::ElementNode *node) { com::Utf8Str mac; bool valueExists = node->getAttributeValue(tagXMLLeaseAttributeMac.c_str(), mac); if (!valueExists) return false; int rc = RTNetStrToMacAddr(mac.c_str(), &m->m_mac); if (RT_FAILURE(rc)) return false; com::Utf8Str network; valueExists = node->getAttributeValue(tagXMLLeaseAttributeNetwork.c_str(), network); if (!valueExists) return false; rc = RTNetStrToIPv4Addr(network.c_str(), &m->m_network); if (RT_FAILURE(rc)) return false; /* Address */ const xml::ElementNode *address = node->findChildElement(tagXMLLeaseAddress.c_str()); if (!address) return false; com::Utf8Str addressValue; valueExists = address->getAttributeValue(tagXMLAddressAttributeValue.c_str(), addressValue); if (!valueExists) return false; rc = RTNetStrToIPv4Addr(addressValue.c_str(), &m->m_address); /* Time */ const xml::ElementNode *time = node->findChildElement(tagXMLLeaseTime.c_str()); if (!time) return false; valueExists = time->getAttributeValue(tagXMLTimeAttributeIssued.c_str(), &m->u64TimestampLeasingStarted); if (!valueExists) return false; m->fBinding = false; valueExists = time->getAttributeValue(tagXMLTimeAttributeExpiration.c_str(), &m->u32LeaseExpirationPeriod); if (!valueExists) return false; m->fHasLease = true; return true; }
static inline int configGetBoundryAddress(const ComDhcpServerPtr& dhcp, bool fUpperBoundry, RTNETADDRIPV4& boundryAddress) { boundryAddress.u = INADDR_ANY; HRESULT hrc; com::Bstr strAddress; if (fUpperBoundry) hrc = dhcp->COMGETTER(UpperIP)(strAddress.asOutParam()); else hrc = dhcp->COMGETTER(LowerIP)(strAddress.asOutParam()); AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); return RTNetStrToIPv4Addr(com::Utf8Str(strAddress).c_str(), &boundryAddress); }
int localMappings(const ComNatPtr& nat, AddressToOffsetMapping& mapping) { mapping.clear(); ComBstrArray strs; size_t cStrs; HRESULT hrc = nat->COMGETTER(LocalMappings)(ComSafeArrayAsOutParam(strs)); if ( SUCCEEDED(hrc) && (cStrs = strs.size())) { for (size_t i = 0; i < cStrs; ++i) { char szAddr[17]; RTNETADDRIPV4 ip4addr; char *pszTerm; uint32_t u32Off; com::Utf8Str strLo2Off(strs[i]); const char *pszLo2Off = strLo2Off.c_str(); RT_ZERO(szAddr); pszTerm = RTStrStr(pszLo2Off, "="); if ( pszTerm && (pszTerm - pszLo2Off) <= INET_ADDRSTRLEN) { memcpy(szAddr, pszLo2Off, (pszTerm - pszLo2Off)); int rc = RTNetStrToIPv4Addr(szAddr, &ip4addr); if (RT_SUCCESS(rc)) { u32Off = RTStrToUInt32(pszTerm + 1); if (u32Off != 0) mapping.insert( AddressToOffsetMapping::value_type(ip4addr, u32Off)); } } } } else return VERR_NOT_FOUND; return VINF_SUCCESS; }
/** * @note: const dropped here, because of map<K,V>::operator[] which isn't const, map<K,V>::at() has const * variant but it's C++11. */ int hostDnsServers(const ComHostPtr& host, const RTNETADDRIPV4& networkid, /*const*/ AddressToOffsetMapping& mapping, AddressList& servers) { servers.clear(); ComBstrArray strs; if (SUCCEEDED(host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(strs)))) { RTNETADDRIPV4 addr; int rc; for (unsigned int i = 0; i < strs.size(); ++i) { rc = RTNetStrToIPv4Addr(com::Utf8Str(strs[i]).c_str(), &addr); if (RT_SUCCESS(rc)) { if (addr.au8[0] == 127) { /* XXX: here we want map<K,V>::at(const K& k) const */ if (mapping[addr] != 0) { addr.u = RT_H2N_U32(RT_N2H_U32(networkid.u) + mapping[addr]); } else continue; /* XXX: Warning here (local mapping wasn't registered) */ } servers.push_back(addr); } } } else return VERR_NOT_FOUND; return VINF_SUCCESS; }
/** * Main thread. Starts also the LWIP thread. */ int VBoxNetLwipNAT::init() { LogFlowFuncEnter(); /* virtualbox initialized in super class */ int rc = ::VBoxNetBaseService::init(); AssertRCReturn(rc, rc); std::string networkName = getNetworkName(); rc = findNatNetwork(virtualbox, networkName, m_net); AssertRCReturn(rc, rc); ComEventTypeArray aNetEvents; aNetEvents.push_back(VBoxEventType_OnNATNetworkPortForward); aNetEvents.push_back(VBoxEventType_OnNATNetworkSetting); rc = createNatListener(m_listener, virtualbox, this, aNetEvents); AssertRCReturn(rc, rc); // resolver changes are reported on vbox but are retrieved from // host so stash a pointer for future lookups HRESULT hrc = virtualbox->COMGETTER(Host)(m_host.asOutParam()); AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); ComEventTypeArray aVBoxEvents; aVBoxEvents.push_back(VBoxEventType_OnHostNameResolutionConfigurationChange); aVBoxEvents.push_back(VBoxEventType_OnNATNetworkStartStop); rc = createNatListener(m_vboxListener, virtualbox, this, aVBoxEvents); AssertRCReturn(rc, rc); BOOL fIPv6Enabled = FALSE; hrc = m_net->COMGETTER(IPv6Enabled)(&fIPv6Enabled); AssertComRCReturn(hrc, VERR_NOT_FOUND); BOOL fIPv6DefaultRoute = FALSE; if (fIPv6Enabled) { hrc = m_net->COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(&fIPv6DefaultRoute); AssertComRCReturn(hrc, VERR_NOT_FOUND); } m_ProxyOptions.ipv6_enabled = fIPv6Enabled; m_ProxyOptions.ipv6_defroute = fIPv6DefaultRoute; com::Bstr bstrSourceIp4Key = com::BstrFmt("NAT/%s/SourceIp4", networkName.c_str()); com::Bstr bstrSourceIpX; hrc = virtualbox->GetExtraData(bstrSourceIp4Key.raw(), bstrSourceIpX.asOutParam()); if (SUCCEEDED(hrc)) { RTNETADDRIPV4 addr; rc = RTNetStrToIPv4Addr(com::Utf8Str(bstrSourceIpX).c_str(), &addr); if (RT_SUCCESS(rc)) { RT_ZERO(m_src4); m_src4.sin_addr.s_addr = addr.u; m_ProxyOptions.src4 = &m_src4; bstrSourceIpX.setNull(); } } if (!fDontLoadRulesOnStartup) { fetchNatPortForwardRules(m_net, false, m_vecPortForwardRule4); fetchNatPortForwardRules(m_net, true, m_vecPortForwardRule6); } /* if (!fDontLoadRulesOnStartup) */ AddressToOffsetMapping tmp; rc = localMappings(m_net, tmp); if (RT_SUCCESS(rc) && tmp.size() != 0) { unsigned long i = 0; for (AddressToOffsetMapping::iterator it = tmp.begin(); it != tmp.end() && i < RT_ELEMENTS(m_lo2off); ++it, ++i) { ip4_addr_set_u32(&m_lo2off[i].loaddr, it->first.u); m_lo2off[i].off = it->second; } m_loOptDescriptor.lomap = m_lo2off; m_loOptDescriptor.num_lomap = i; m_ProxyOptions.lomap_desc = &m_loOptDescriptor; } com::Bstr bstr; hrc = virtualbox->COMGETTER(HomeFolder)(bstr.asOutParam()); AssertComRCReturn(hrc, VERR_NOT_FOUND); if (!bstr.isEmpty()) { com::Utf8Str strTftpRoot(com::Utf8StrFmt("%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP")); char *pszStrTemp; // avoid const char ** vs char ** rc = RTStrUtf8ToCurrentCP(&pszStrTemp, strTftpRoot.c_str()); AssertRC(rc); m_ProxyOptions.tftp_root = pszStrTemp; } m_ProxyOptions.nameservers = getHostNameservers(); /* end of COM initialization */ rc = g_pLwipNat->tryGoOnline(); if (RT_FAILURE(rc)) return rc; /* this starts LWIP thread */ vboxLwipCoreInitialize(VBoxNetLwipNAT::onLwipTcpIpInit, this); LogFlowFuncLeaveRC(rc); return rc; }
/* XXX: Having fIPv6 we might emprove adress verification comparing address length * with INET[6]_ADDRLEN */ int netPfStrToPf(const char *pcszStrPortForward, int fIPv6, PPORTFORWARDRULE pPfr) { char *pszName; int proto; char *pszHostAddr; char *pszGuestAddr; uint16_t u16HostPort; uint16_t u16GuestPort; bool fTcpProto = false; char *pszRawBegin = NULL; char *pszRaw = NULL; int idxRaw = 0; int cbToken = 0; int cbRaw = 0; int rc = VINF_SUCCESS; AssertPtrReturn(pcszStrPortForward, VERR_INVALID_PARAMETER); AssertPtrReturn(pPfr, VERR_INVALID_PARAMETER); memset(pPfr, 0, sizeof(PORTFORWARDRULE)); pszHostAddr = &pPfr->aszPfrHostAddr[0]; pszGuestAddr = &pPfr->aszPfrGuestAddr[0]; pszName = &pPfr->aszPfrName[0]; cbRaw = strlen(pcszStrPortForward); /* Minimal rule ":tcp:[]:0:[]:0" has got lenght 14 */ AssertReturn(cbRaw > 14, VERR_INVALID_PARAMETER); pszRaw = RTStrDup(pcszStrPortForward); AssertPtrReturn(pszRaw, VERR_NO_MEMORY); pszRawBegin = pszRaw; /* name */ if (pszRaw[idxRaw] == PF_FIELD_SEPARATOR) idxRaw = 1; /* begin of the next segment */ else { char *pszEndOfName = RTStrStr(pszRaw + 1, PF_STR_FIELD_SEPARATOR); if (!pszEndOfName) goto invalid_parameter; cbToken = (pszEndOfName) - pszRaw; /* don't take : into account */ /* XXX it's unacceptable to have only name entry in PF */ AssertReturn(cbToken < cbRaw, VERR_INVALID_PARAMETER); if ( cbToken < 0 || (size_t)cbToken >= PF_NAMELEN) goto invalid_parameter; RTStrCopy(pszName, RT_MIN((size_t)cbToken + 1, PF_NAMELEN), pszRaw); pszRaw += cbToken; /* move to separator */ } AssertReturn(pszRaw[0] == PF_FIELD_SEPARATOR, VERR_INVALID_PARAMETER); /* protocol */ pszRaw++; /* skip separator */ idxRaw = 0; cbRaw--; if ( (( fTcpProto = (RTStrNICmp(pszRaw, "tcp", 3) == 0) || (RTStrNICmp(pszRaw, "udp", 3) == 0)) && (pszRaw[3] == PF_FIELD_SEPARATOR))) { proto = (fTcpProto ? IPPROTO_TCP : IPPROTO_UDP); idxRaw = 3; } else goto invalid_parameter; pszRaw += idxRaw; cbRaw -= idxRaw; idxRaw = 0; idxRaw = netPfStrAddressPortPairParse(pszRaw, cbRaw, pszHostAddr, INET6_ADDRSTRLEN, true, &u16HostPort); if (idxRaw < 0) return VERR_INVALID_PARAMETER; pszRaw += idxRaw; cbRaw -= idxRaw; Assert(pszRaw[0] == PF_FIELD_SEPARATOR); idxRaw = 0; idxRaw = netPfStrAddressPortPairParse(pszRaw, cbRaw, pszGuestAddr, INET6_ADDRSTRLEN, false, &u16GuestPort); if (idxRaw < 0) goto invalid_parameter; /* XXX: fill the rule */ pPfr->fPfrIPv6 = fIPv6; pPfr->iPfrProto = proto; if (strlen(pszHostAddr)) { if (!fIPv6) rc = RTNetStrToIPv4Addr(pszHostAddr, &pPfr->uPfrHostAddr.IPv4); #if 0 /* No IPv6 yet */ else rc = RTNetStrToIPv6Addr(pszHostAddr, &pPfr->uPfrHostAddr.IPv6); #endif if (RT_FAILURE(rc)) goto invalid_parameter; } pPfr->u16PfrHostPort = u16HostPort; if (strlen(pszGuestAddr)) { if (!fIPv6) rc = RTNetStrToIPv4Addr(pszGuestAddr, &pPfr->uPfrGuestAddr.IPv4); #if 0 else rc = RTNetStrToIPv6Addr(pszGuestAddr, &pPfr->uPfrGuestAddr.IPv6); #endif if (RT_FAILURE(rc)) goto invalid_parameter; } else goto invalid_parameter; /* guest address should be defined */ pPfr->u16PfrGuestPort = u16GuestPort; Log(("name: %s\n" "proto: %d\n" "host address: %s\n" "host port: %d\n" "guest address: %s\n" "guest port:%d\n", pszName, proto, pszHostAddr, u16HostPort, pszGuestAddr, u16GuestPort)); RTStrFree(pszRawBegin); return VINF_SUCCESS; invalid_parameter: RTStrFree(pszRawBegin); if (pPfr) memset(pPfr, 0, sizeof(PORTFORWARDRULE)); return VERR_INVALID_PARAMETER; }
/** * Converts an stringified IPv4 address into the RTNETADDRIPV4 representation. * * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on * failure. * * @param pszValue The value to convert. * @param pAddr Where to store the result. */ static int rtgetoptConvertIPv4Addr(const char *pszValue, PRTNETADDRIPV4 pAddr) { if (RT_FAILURE(RTNetStrToIPv4Addr(pszValue, pAddr))) return VERR_GETOPT_INVALID_ARGUMENT_FORMAT; return VINF_SUCCESS; }
int VBoxNetDhcp::initWithMain() { /* ok, here we should initiate instance of dhcp server * and listener for Dhcp configuration events */ AssertRCReturn(virtualbox.isNull(), VERR_INTERNAL_ERROR); std::string networkName = getNetwork(); int rc = findDhcpServer(virtualbox, networkName, m_DhcpServer); AssertRCReturn(rc, rc); rc = findNatNetwork(virtualbox, networkName, m_NATNetwork); AssertRCReturn(rc, rc); BOOL fNeedDhcpServer = isDhcpRequired(m_NATNetwork); if (!fNeedDhcpServer) return VERR_CANCELLED; RTNETADDRIPV4 gateway; com::Bstr strGateway; HRESULT hrc = m_NATNetwork->COMGETTER(Gateway)(strGateway.asOutParam()); AssertComRCReturn(hrc, VERR_INTERNAL_ERROR); RTNetStrToIPv4Addr(com::Utf8Str(strGateway).c_str(), &gateway); ConfigurationManager *confManager = ConfigurationManager::getConfigurationManager(); AssertPtrReturn(confManager, VERR_INTERNAL_ERROR); confManager->addToAddressList(RTNET_DHCP_OPT_ROUTERS, gateway); rc = fetchAndUpdateDnsInfo(); AssertMsgRCReturn(rc, ("Wasn't able to fetch Dns info"), rc); ComEventTypeArray aVBoxEvents; aVBoxEvents.push_back(VBoxEventType_OnHostNameResolutionConfigurationChange); rc = createNatListener(m_vboxListener, virtualbox, this, aVBoxEvents); AssertRCReturn(rc, rc); RTNETADDRIPV4 LowerAddress; rc = configGetBoundryAddress(m_DhcpServer, false, LowerAddress); AssertMsgRCReturn(rc, ("can't get lower boundrary adderss'"),rc); RTNETADDRIPV4 UpperAddress; rc = configGetBoundryAddress(m_DhcpServer, true, UpperAddress); AssertMsgRCReturn(rc, ("can't get upper boundrary adderss'"),rc); RTNETADDRIPV4 address = getIpv4Address(); RTNETADDRIPV4 netmask = getIpv4Netmask(); RTNETADDRIPV4 networkId = networkid(address, netmask); std::string name = std::string("default"); confManager->addNetwork(unconst(g_RootConfig), networkId, netmask, LowerAddress, UpperAddress); com::Bstr bstr; hrc = virtualbox->COMGETTER(HomeFolder)(bstr.asOutParam()); com::Utf8StrFmt strXmlLeaseFile("%ls%c%s.leases", bstr.raw(), RTPATH_DELIMITER, networkName.c_str()); confManager->loadFromFile(strXmlLeaseFile); return VINF_SUCCESS; }
/** * nameserverexpr ::= 'nameserver' ip+ * @note: resolver(5) ip ::= (ipv4|ipv6)(.number)? */ static enum RCP_TOKEN rcp_parse_nameserver(struct rcp_parser *parser) { enum RCP_TOKEN tok = rcp_get_token(parser); /* eats 'nameserver' */ if ( ( tok != tok_ipv4 && tok != tok_ipv4_port && tok != tok_ipv6 && tok != tok_ipv6_port) || tok == EOF) return tok_error; while ( tok == tok_ipv4 || tok == tok_ipv4_port || tok == tok_ipv6 || tok == tok_ipv6_port) { struct rcp_state *st; RTNETADDR *address; char *str_address; Assert(parser->rcpp_state); st = parser->rcpp_state; /* It's still valid resolv.conf file, just rest of the nameservers should be ignored */ if (st->rcps_num_nameserver >= RCPS_MAX_NAMESERVERS) return rcp_get_token(parser); address = &st->rcps_nameserver[st->rcps_num_nameserver]; str_address = &st->rcps_nameserver_str_buffer[st->rcps_num_nameserver * RCPS_IPVX_SIZE]; #ifdef RT_OS_DARWIN if ( tok == tok_ipv4_port || ( tok == tok_ipv6_port && (st->rcps_flags & RCPSF_IGNORE_IPV6) == 0)) { char *ptr = &parser->rcpp_str_buffer[strlen(parser->rcpp_str_buffer)]; while (*(--ptr) != '.'); *ptr = '\0'; address->uPort = RTStrToUInt16(ptr + 1); if (address->uPort == 0) return tok_error; } #endif /** * if we on Darwin upper code will cut off port if it's. */ if ((st->rcps_flags & RCPSF_NO_STR2IPCONV) != 0) { if (strlen(parser->rcpp_str_buffer) > RCPS_IPVX_SIZE) return tok_error; strcpy(str_address, parser->rcpp_str_buffer); st->rcps_str_nameserver[st->rcps_num_nameserver] = str_address; goto loop_prolog; } switch (tok) { case tok_ipv4: case tok_ipv4_port: { int rc = RTNetStrToIPv4Addr(parser->rcpp_str_buffer, &address->uAddr.IPv4); if (RT_FAILURE(rc)) return tok_error; address->enmType = RTNETADDRTYPE_IPV4; } break; case tok_ipv6: case tok_ipv6_port: { int rc; if ((st->rcps_flags & RCPSF_IGNORE_IPV6) != 0) return rcp_get_token(parser); rc = inet_pton(AF_INET6, parser->rcpp_str_buffer, &address->uAddr.IPv6); if (rc == -1) return tok_error; address->enmType = RTNETADDRTYPE_IPV6; } break; default: /* loop condition doesn't let enter enything */ AssertMsgFailed(("shouldn't ever happen tok:%d, %s", tok, isprint(tok) ? parser->rcpp_str_buffer : "#")); break; } loop_prolog: st->rcps_num_nameserver++; tok = rcp_get_token(parser); } return tok; }