summaryrefslogtreecommitdiff
path: root/src/mongo/util/net/sockaddr.cpp
diff options
context:
space:
mode:
authorBen Caimano <ben.caimano@10gen.com>2021-04-23 15:35:58 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-23 16:17:00 +0000
commit83f45db3ee406ae9218764170e90ac8714e05e97 (patch)
tree904da7b7cfde489cc3f7b0b7f4af7a03ebd77fe4 /src/mongo/util/net/sockaddr.cpp
parent5f55799008fdcf7bd418f3dec1a4448c0801f701 (diff)
downloadmongo-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.cpp131
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 {