diff options
author | Ben Caimano <ben.caimano@10gen.com> | 2021-04-23 15:35:58 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-04-23 16:17:00 +0000 |
commit | 83f45db3ee406ae9218764170e90ac8714e05e97 (patch) | |
tree | 904da7b7cfde489cc3f7b0b7f4af7a03ebd77fe4 /src/mongo/util/net/sockaddr.cpp | |
parent | 5f55799008fdcf7bd418f3dec1a4448c0801f701 (diff) | |
download | mongo-83f45db3ee406ae9218764170e90ac8714e05e97.tar.gz |
SERVER-55787 Better expose getaddrinfo errors in SockAddr
Diffstat (limited to 'src/mongo/util/net/sockaddr.cpp')
-rw-r--r-- | src/mongo/util/net/sockaddr.cpp | 131 |
1 files changed, 71 insertions, 60 deletions
diff --git a/src/mongo/util/net/sockaddr.cpp b/src/mongo/util/net/sockaddr.cpp index 7a96087b896..1a2b058cbf3 100644 --- a/src/mongo/util/net/sockaddr.cpp +++ b/src/mongo/util/net/sockaddr.cpp @@ -53,6 +53,7 @@ #endif #endif +#include "mongo/base/status.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/util/builder.h" #include "mongo/logv2/log.h" @@ -69,24 +70,36 @@ struct AddrInfoDeleter { }; using AddrInfoPtr = std::unique_ptr<addrinfo, AddrInfoDeleter>; -struct AddrErr { - AddrInfoPtr addr; - int err; -}; +AddrInfoPtr resolveAddrInfo(StringData hostOrIp, int port, sa_family_t familyHint) { + struct AddrError { + AddrInfoPtr addr; + int err; + }; + + // Convert to std::string to ensure null-termination. + const auto hostString = std::string(hostOrIp); + const auto portString = ItoA(port).toString(); + + auto tryResolve = [&](bool allowDns) noexcept { + AddrError result; -AddrErr resolveAddrInfo(const std::string& hostOrIp, int port, sa_family_t familyHint) { - const std::string portStr{StringData{ItoA(port)}}; - auto tryResolve = [&](bool allowDns) noexcept->AddrErr { addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_socktype = SOCK_STREAM; if (!allowDns) hints.ai_flags |= AI_NUMERICHOST; hints.ai_family = familyHint; + addrinfo* addrs = nullptr; - int ret = getaddrinfo(hostOrIp.c_str(), portStr.c_str(), &hints, &addrs); - AddrInfoPtr rvPtr(addrs); - return {std::move(rvPtr), ret}; + result.err = getaddrinfo(hostString.c_str(), portString.c_str(), &hints, &addrs); + result.addr = AddrInfoPtr(addrs); + return result; + }; + + auto validateResolution = [](AddrError addrErr) -> AddrInfoPtr { + uassert(ErrorCodes::HostUnreachable, getAddrInfoStrError(addrErr.err), addrErr.err == 0); + + return std::move(addrErr.addr); }; switch (auto r = tryResolve(false); r.err) { @@ -96,9 +109,9 @@ AddrErr resolveAddrInfo(const std::string& hostOrIp, int port, sa_family_t famil case EAI_NODATA: // Old IPv6-capable hosts can return EAI_NODATA. #endif #endif - return tryResolve(true); // Not an IP address. Retry with DNS. + return validateResolution(tryResolve(true)); // Not an IP address. Retry with DNS. default: - return r; + return validateResolution(std::move(r)); } } @@ -129,90 +142,88 @@ SockAddr::SockAddr(int sourcePort) { _isValid = true; } -void SockAddr::initUnixDomainSocket(const std::string& path, int port) { +void SockAddr::initUnixDomainSocket(StringData path, int port) { #ifdef _WIN32 uassert(13080, "no unix socket support on windows", false); #endif uassert( 13079, "path to unix socket too long", path.size() < sizeof(as<sockaddr_un>().sun_path)); as<sockaddr_un>().sun_family = AF_UNIX; - strcpy(as<sockaddr_un>().sun_path, path.c_str()); + path.copyTo(as<sockaddr_un>().sun_path, /* includeEndingNull =*/true); addressSize = sizeof(sockaddr_un); _isValid = true; } -SockAddr::SockAddr(StringData target, int port, sa_family_t familyHint) - : _hostOrIp(target.toString()) { - if (_hostOrIp == "localhost") { - _hostOrIp = "127.0.0.1"; +SockAddr SockAddr::create(StringData target, int port, sa_family_t familyHint) { + if (target == "localhost") { + target = "127.0.0.1"_sd; } - if (str::contains(_hostOrIp, '/') || familyHint == AF_UNIX) { - initUnixDomainSocket(_hostOrIp, port); - return; + if (str::contains(target, '/') || familyHint == AF_UNIX) { + SockAddr ret; + ret.initUnixDomainSocket(target, port); + return ret; } - auto addrErr = resolveAddrInfo(_hostOrIp, port, familyHint); + try { + const auto ownedAddrs = resolveAddrInfo(target, port, familyHint); - if (addrErr.err) { + // This throws away all but the first address. + // Use SockAddr::createAll() to get all addresses. + const auto* addrs = ownedAddrs.get(); + fassert(16501, static_cast<size_t>(addrs->ai_addrlen) <= sizeof(struct sockaddr_storage)); + return SockAddr(addrs->ai_addr, addrs->ai_addrlen, target); + } catch (const DBException&) { // we were unsuccessful - if (_hostOrIp != "0.0.0.0") { // don't log if this as it is a - // CRT construction and log() may not work yet. - LOGV2(23175, - "getaddrinfo(\"{host}\") failed: {error}", - "Command getaddrinfo failed", - "host"_attr = _hostOrIp, - "error"_attr = getAddrInfoStrError(addrErr.err)); - _isValid = false; - return; + + if (target == "0.0.0.0") { + // don't log if this as it is a CRT construction and log() may not work yet. + return SockAddr(port); } - *this = SockAddr(port); - return; - } - // This throws away all but the first address. - // Use SockAddr::createAll() to get all addresses. - const auto* addrs = addrErr.addr.get(); - fassert(16501, static_cast<size_t>(addrs->ai_addrlen) <= sizeof(sa)); - memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen); - addressSize = addrs->ai_addrlen; - _isValid = true; + throw; + } } std::vector<SockAddr> SockAddr::createAll(StringData target, int port, sa_family_t familyHint) { - std::string hostOrIp = target.toString(); - if (str::contains(hostOrIp, '/')) { + if (str::contains(target, '/')) { std::vector<SockAddr> ret = {SockAddr()}; - ret[0].initUnixDomainSocket(hostOrIp, port); + ret[0].initUnixDomainSocket(target, port); // Currently, this is always valid since initUnixDomainSocket() // will uassert() on failure. Be defensive against future changes. return ret[0].isValid() ? ret : std::vector<SockAddr>(); } - auto addrErr = resolveAddrInfo(hostOrIp, port, familyHint); - if (addrErr.err) { + try { + const auto ownedAddrs = resolveAddrInfo(target, port, familyHint); + + std::set<SockAddr> ret; + for (const auto* addrs = ownedAddrs.get(); addrs; addrs = addrs->ai_next) { + fassert(40594, + static_cast<size_t>(addrs->ai_addrlen) <= sizeof(struct sockaddr_storage)); + ret.emplace(addrs->ai_addr, addrs->ai_addrlen, target); + } + return std::vector<SockAddr>(ret.begin(), ret.end()); + } catch (const DBException& ex) { LOGV2(23176, "getaddrinfo(\"{host}\") failed: {error}", "getaddrinfo invocation failed", - "host"_attr = hostOrIp, - "error"_attr = getAddrInfoStrError(addrErr.err)); + "host"_attr = target, + "error"_attr = ex.toStatus()); return {}; } - - std::set<SockAddr> ret; - struct sockaddr_storage storage; - memset(&storage, 0, sizeof(storage)); - for (const auto* addrs = addrErr.addr.get(); addrs; addrs = addrs->ai_next) { - fassert(40594, static_cast<size_t>(addrs->ai_addrlen) <= sizeof(struct sockaddr_storage)); - ret.emplace(addrs->ai_addr, addrs->ai_addrlen); - } - return std::vector<SockAddr>(ret.begin(), ret.end()); } -SockAddr::SockAddr(const sockaddr* other, socklen_t size) - : addressSize(size), _hostOrIp(), sa(), _isValid(true) { +SockAddr::SockAddr(const sockaddr* other, socklen_t size) : addressSize(size), _hostOrIp(), sa() { memcpy(&sa, other, size); _hostOrIp = toString(true); + _isValid = true; +} + +SockAddr::SockAddr(const sockaddr* other, socklen_t size, StringData hostOrIp) + : addressSize(size), _hostOrIp(hostOrIp.toString()), sa() { + memcpy(&sa, other, size); + _isValid = true; } bool SockAddr::isIP() const { |