SockAddr::SockAddr(const char * _iporhost , int port) { string target = _iporhost; if( target == "localhost" ) { target = "127.0.0.1"; } if( mongoutils::str::contains(target, '/') ) { #ifdef _WIN32 uassert(13080, "no unix socket support on windows", false); #endif uassert(13079, "path to unix socket too long", target.size() < sizeof(as<sockaddr_un>().sun_path)); as<sockaddr_un>().sun_family = AF_UNIX; strcpy(as<sockaddr_un>().sun_path, target.c_str()); addressSize = sizeof(sockaddr_un); } else { addrinfo* addrs = NULL; addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_socktype = SOCK_STREAM; //hints.ai_flags = AI_ADDRCONFIG; // This is often recommended but don't do it. // SERVER-1579 hints.ai_flags |= AI_NUMERICHOST; // first pass tries w/o DNS lookup hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET); StringBuilder ss; ss << port; int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs); // old C compilers on IPv6-capable hosts return EAI_NODATA error #ifdef EAI_NODATA int nodata = (ret == EAI_NODATA); #else int nodata = false; #endif if ( (ret == EAI_NONAME || nodata) ) { // iporhost isn't an IP address, allow DNS lookup hints.ai_flags &= ~AI_NUMERICHOST; ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs); } if (ret) { // we were unsuccessful if( target != "0.0.0.0" ) { // don't log if this as it is a // CRT construction and log() may not work yet. log() << "getaddrinfo(\"" << target << "\") failed: " << getAddrInfoStrError(ret) << endl; } *this = SockAddr(port); } else { //TODO: handle other addresses in linked list; fassert(16501, addrs->ai_addrlen <= sizeof(sa)); memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen); addressSize = addrs->ai_addrlen; freeaddrinfo(addrs); } } }
static SockAddr getLocalAddrForBoundSocketFd(int fd) { SockAddr result; int rc = getsockname(fd, result.raw(), &result.addressSize); if (rc != 0) { warning() << "Could not resolve local address for socket with fd " << fd << ": " << getAddrInfoStrError(socketGetLastError()); result = SockAddr(); } return result; }
std::string SockAddr::getAddr() const { switch (getType()) { case AF_INET: case AF_INET6: { const int buflen=128; char buffer[buflen]; int ret = getnameinfo(raw(), addressSize, buffer, buflen, NULL, 0, NI_NUMERICHOST); massert(13082, mongoutils::str::stream() << "getnameinfo error " << getAddrInfoStrError(ret), ret == 0); return buffer; } case AF_UNIX: return (addressSize > 2 ? as<sockaddr_un>().sun_path : "anonymous unix socket"); case AF_UNSPEC: return "(NONE)"; default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return ""; } }
std::vector<std::string> getHostFQDNs(std::string hostName, HostnameCanonicalizationMode mode) { #ifndef _WIN32 using shim_char = char; using shim_addrinfo = struct addrinfo; const auto& shim_getaddrinfo = getaddrinfo; const auto& shim_freeaddrinfo = freeaddrinfo; const auto& shim_getnameinfo = getnameinfo; const auto& shim_toNativeString = [](const char* str) { return std::string(str); }; const auto& shim_fromNativeString = [](const std::string& str) { return str; }; #else using shim_char = wchar_t; using shim_addrinfo = struct addrinfoW; const auto& shim_getaddrinfo = GetAddrInfoW; const auto& shim_freeaddrinfo = FreeAddrInfoW; const auto& shim_getnameinfo = GetNameInfoW; const auto& shim_toNativeString = toWideString; const auto& shim_fromNativeString = toUtf8String; #endif std::vector<std::string> results; if (hostName.empty()) return results; if (mode == HostnameCanonicalizationMode::kNone) { results.emplace_back(std::move(hostName)); return results; } shim_addrinfo hints = {}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = 0; hints.ai_protocol = 0; if (mode == HostnameCanonicalizationMode::kForward) { hints.ai_flags = AI_CANONNAME; } int err; shim_addrinfo* info; auto nativeHostName = shim_toNativeString(hostName.c_str()); if ((err = shim_getaddrinfo(nativeHostName.c_str(), nullptr, &hints, &info)) != 0) { ONCE { warning() << "Failed to obtain address information for hostname " << hostName << ": " << getAddrInfoStrError(err); } return results; }
std::vector<std::string> getHostFQDNs(std::string hostName, HostnameCanonicalizationMode mode) { #ifndef _WIN32 using shim_char = char; using shim_addrinfo = struct addrinfo; const auto& shim_getaddrinfo = getaddrinfo; const auto& shim_freeaddrinfo = freeaddrinfo; const auto& shim_getnameinfo = getnameinfo; const auto& shim_toNativeString = [](const char* str) { return std::string(str); }; const auto& shim_fromNativeString = [](const std::string& str) { return str; }; #else using shim_char = wchar_t; using shim_addrinfo = struct addrinfoW; const auto& shim_getaddrinfo = GetAddrInfoW; const auto& shim_freeaddrinfo = FreeAddrInfoW; const auto& shim_getnameinfo = GetNameInfoW; const auto& shim_toNativeString = toWideString; const auto& shim_fromNativeString = toUtf8String; #endif std::vector<std::string> results; if (hostName.empty()) return results; if (mode == HostnameCanonicalizationMode::kNone) { results.emplace_back(std::move(hostName)); return results; } shim_addrinfo hints = {}; hints.ai_family = AF_UNSPEC; hints.ai_socktype = 0; hints.ai_protocol = 0; if (mode == HostnameCanonicalizationMode::kForward) { hints.ai_flags = AI_CANONNAME; } int err; shim_addrinfo* info; auto nativeHostName = shim_toNativeString(hostName.c_str()); if ((err = shim_getaddrinfo(nativeHostName.c_str(), nullptr, &hints, &info)) != 0) { LOG(3) << "Failed to obtain address information for hostname " << hostName << ": " << getAddrInfoStrError(err); return results; } const auto guard = MakeGuard([&shim_freeaddrinfo, &info] { shim_freeaddrinfo(info); }); if (mode == HostnameCanonicalizationMode::kForward) { results.emplace_back(shim_fromNativeString(info->ai_canonname)); return results; } bool encounteredErrors = false; std::stringstream getNameInfoErrors; getNameInfoErrors << "Failed to obtain name info for: [ "; for (shim_addrinfo* p = info; p; p = p->ai_next) { shim_char host[NI_MAXHOST] = {}; if ((err = shim_getnameinfo( p->ai_addr, p->ai_addrlen, host, sizeof(host), nullptr, 0, NI_NAMEREQD)) == 0) { results.emplace_back(shim_fromNativeString(host)); } else { if (encounteredErrors) { getNameInfoErrors << ", "; } encounteredErrors = true; // Format the addrinfo structure we have into a string for reporting char ip_str[INET6_ADDRSTRLEN]; struct sockaddr* addr = p->ai_addr; void* sin_addr = nullptr; if (p->ai_family == AF_INET) { struct sockaddr_in* addr_in = reinterpret_cast<struct sockaddr_in*>(addr); sin_addr = reinterpret_cast<void*>(&addr_in->sin_addr); } else if (p->ai_family == AF_INET6) { struct sockaddr_in6* addr_in6 = reinterpret_cast<struct sockaddr_in6*>(addr); sin_addr = reinterpret_cast<void*>(&addr_in6->sin6_addr); } getNameInfoErrors << "("; if (sin_addr) { invariant(inet_ntop(p->ai_family, sin_addr, ip_str, sizeof(ip_str)) != nullptr); getNameInfoErrors << ip_str; } else { getNameInfoErrors << "Unknown address family: " << p->ai_family; } getNameInfoErrors << ", \"" << getAddrInfoStrError(err) << "\")"; } } if (encounteredErrors) { LOG(3) << getNameInfoErrors.str() << " ]"; } // Deduplicate the results list std::sort(results.begin(), results.end()); results.erase(std::unique(results.begin(), results.end()), results.end()); // Remove any name that doesn't have a '.', since A records are illegal in TLDs results.erase( std::remove_if(results.begin(), results.end(), [](const std::string& str) { return str.find('.') == std::string::npos; }), results.end()); return results; }