bool isSelf(const HostAndPort& hostAndPort, ServiceContext* const ctx) { // Fastpath: check if the host&port in question is bound to one // of the interfaces on this machine. // No need for ip match if the ports do not match if (hostAndPort.port() == serverGlobalParams.port) { std::vector<std::string> myAddrs = serverGlobalParams.bind_ips; // If any of the bound addresses is the default route (0.0.0.0 on IPv4) it means we are // listening on all network interfaces and need to check against any of them. if (myAddrs.empty() || std::any_of(myAddrs.cbegin(), myAddrs.cend(), [](std::string const& addrStr) { return HostAndPort(addrStr, serverGlobalParams.port).isDefaultRoute(); })) { myAddrs = getBoundAddrs(IPv6Enabled()); } const std::vector<std::string> hostAddrs = getAddrsForHost(hostAndPort.host(), hostAndPort.port(), IPv6Enabled()); for (std::vector<std::string>::const_iterator i = myAddrs.begin(); i != myAddrs.end(); ++i) { for (std::vector<std::string>::const_iterator j = hostAddrs.begin(); j != hostAddrs.end(); ++j) { if (*i == *j) { return true; } } } } ctx->waitForStartupComplete(); try { DBClientConnection conn; conn.setSoTimeout(30); // 30 second timeout // We need to avoid the isMaster call triggered by a normal connect, which would // cause a deadlock. 'isSelf' is called by the Replication Coordinator when validating // a replica set configuration document, but the 'isMaster' command requires a lock on the // replication coordinator to execute. As such we call we call 'connectSocketOnly', which // does not call 'isMaster'. if (!conn.connectSocketOnly(hostAndPort).isOK()) { return false; } if (auth::isInternalAuthSet() && !conn.authenticateInternalUser().isOK()) { return false; } BSONObj out; bool ok = conn.simpleCommand("admin", &out, "_isSelf"); bool me = ok && out["id"].type() == jstOID && instanceId == out["id"].OID(); return me; } catch (const std::exception& e) { warning() << "couldn't check isSelf (" << hostAndPort << ") " << e.what() << std::endl; } return false; }
bool isSelf(const HostAndPort& hostAndPort) { // Fastpath: check if the host&port in question is bound to one // of the interfaces on this machine. // No need for ip match if the ports do not match if (hostAndPort.port() == serverGlobalParams.port) { std::vector<std::string> myAddrs = serverGlobalParams.bind_ip.empty() ? getBoundAddrs(IPv6Enabled()) : std::vector<std::string>(); if (!serverGlobalParams.bind_ip.empty()) { boost::split(myAddrs, serverGlobalParams.bind_ip, boost::is_any_of(", ")); } const std::vector<std::string> hostAddrs = getAddrsForHost(hostAndPort.host(), hostAndPort.port(), IPv6Enabled()); for (std::vector<std::string>::const_iterator i = myAddrs.begin(); i != myAddrs.end(); ++i) { for (std::vector<std::string>::const_iterator j = hostAddrs.begin(); j != hostAddrs.end(); ++j) { if (*i == *j) { return true; } } } } if (!Listener::getTimeTracker()) { // this ensures we are actually running a server // this may return true later, so may want to retry return false; } try { DBClientConnection conn; std::string errmsg; if (!conn.connect(hostAndPort, errmsg)) { return false; } if (getGlobalAuthorizationManager()->isAuthEnabled() && isInternalAuthSet()) { if (!authenticateInternalUser(&conn)) { return false; } } BSONObj out; bool ok = conn.simpleCommand("admin" , &out, "_isSelf"); bool me = ok && out["id"].type() == jstOID && instanceId == out["id"].OID(); return me; } catch (const std::exception& e) { warning() << "could't check isSelf (" << hostAndPort << ") " << e.what() << std::endl; } return false; }
// If an ip address is passed in, just return that. If a hostname is passed // in, look up its ip and return that. Returns "" on failure. std::string hostbyname(const char* hostname) { SockAddr sockAddr(hostname, 0, IPv6Enabled() ? AF_UNSPEC : AF_INET); if (!sockAddr.isValid() || sockAddr.getAddr() == "0.0.0.0") return ""; else return sockAddr.getAddr(); }
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: " << gai_strerror(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); } } }
SockAddr::SockAddr(const char * iporhost , int port) { if (!strcmp(iporhost, "localhost")) iporhost = "127.0.0.1"; if (strchr(iporhost, '/')) { #ifdef _WIN32 uassert(13080, "no unix socket support on windows", false); #endif uassert(13079, "path to unix socket too long", strlen(iporhost) < sizeof(as<sockaddr_un>().sun_path)); as<sockaddr_un>().sun_family = AF_UNIX; strcpy(as<sockaddr_un>().sun_path, iporhost); 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); stringstream ss; ss << port; int ret = getaddrinfo(iporhost, 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(iporhost, ss.str().c_str(), &hints, &addrs); } if (ret) { log() << "getaddrinfo(\"" << iporhost << "\") failed: " << gai_strerror(ret) << endl; *this = SockAddr(port); } else { //TODO: handle other addresses in linked list; assert(addrs->ai_addrlen <= sizeof(sa)); memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen); addressSize = addrs->ai_addrlen; freeaddrinfo(addrs); } } }
vector<string> getAllIPs(const string& iporhost) { addrinfo* addrs = NULL; addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET); static string portNum = BSONObjBuilder::numStr(serverGlobalParams.port); vector<string> out; int ret = getaddrinfo(iporhost.c_str(), portNum.c_str(), &hints, &addrs); if ( ret ) { warning() << "getaddrinfo(\"" << iporhost << "\") failed: " << gai_strerror(ret) << endl; return out; } for (addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) { int family = addr->ai_family; char host[NI_MAXHOST]; if (family == AF_INET || family == AF_INET6) { int status = getnameinfo(addr->ai_addr, addr->ai_addrlen, host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); massert(13472, string("getnameinfo() failed: ") + gai_strerror(status), status == 0); out.push_back(host); } } freeaddrinfo(addrs); if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) { LogstreamBuilder builder(logger::globalLogDomain(), getThreadName(), logger::LogSeverity::Debug(1)); builder << "getallIPs(\"" << iporhost << "\"):"; for (vector<string>::const_iterator it=out.begin(), end=out.end(); it!=end; ++it) { builder << " [" << *it << ']'; } builder << endl; } return out; }
vector<string> getAllIPs(StringData iporhost) { addrinfo* addrs = NULL; addrinfo hints; memset(&hints, 0, sizeof(addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET); static string portNum = BSONObjBuilder::numStr(cmdLine.port); vector<string> out; int ret = getaddrinfo(iporhost.data(), portNum.c_str(), &hints, &addrs); if ( ret ) { warning() << "getaddrinfo(\"" << iporhost.data() << "\") failed: " << gai_strerror(ret) << endl; return out; } for (addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) { int family = addr->ai_family; char host[NI_MAXHOST]; if (family == AF_INET || family == AF_INET6) { int status = getnameinfo(addr->ai_addr, addr->ai_addrlen, host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); massert(13472, string("getnameinfo() failed: ") + gai_strerror(status), status == 0); out.push_back(host); } } freeaddrinfo(addrs); if (logLevel >= 1) { log(1) << "getallIPs(\"" << iporhost << "\"):"; for (vector<string>::const_iterator it=out.begin(), end=out.end(); it!=end; ++it) { log(1) << " [" << *it << ']'; } log(1) << endl; } return out; }
vector<SockAddr> ipToAddrs(const char* ips, int port, bool useUnixSockets) { vector<SockAddr> out; if (*ips == '\0') { out.push_back(SockAddr("0.0.0.0", port)); // IPv4 all if (IPv6Enabled()) out.push_back(SockAddr("::", port)); // IPv6 all #ifndef _WIN32 if (useUnixSockets) out.push_back(SockAddr(makeUnixSockPath(port).c_str(), port)); // Unix socket #endif return out; } while(*ips) { string ip; const char * comma = strchr(ips, ','); if (comma) { ip = string(ips, comma - ips); ips = comma + 1; } else { ip = string(ips); ips = ""; } SockAddr sa(ip.c_str(), port); out.push_back(sa); #ifndef _WIN32 if (useUnixSockets && (sa.getAddr() == "127.0.0.1" || sa.getAddr() == "0.0.0.0")) // only IPv4 out.push_back(SockAddr(makeUnixSockPath(port).c_str(), port)); #endif } return out; }
bool isSelf(const HostAndPort& hostAndPort) { // Fastpath: check if the host&port in question is bound to one // of the interfaces on this machine. // No need for ip match if the ports do not match if (hostAndPort.port() == serverGlobalParams.port) { std::vector<std::string> myAddrs = serverGlobalParams.bind_ip.empty() ? getBoundAddrs(IPv6Enabled()) : std::vector<std::string>(); if (!serverGlobalParams.bind_ip.empty()) { boost::split(myAddrs, serverGlobalParams.bind_ip, boost::is_any_of(", ")); } const std::vector<std::string> hostAddrs = getAddrsForHost(hostAndPort.host(), hostAndPort.port(), IPv6Enabled()); for (std::vector<std::string>::const_iterator i = myAddrs.begin(); i != myAddrs.end(); ++i) { for (std::vector<std::string>::const_iterator j = hostAddrs.begin(); j != hostAddrs.end(); ++j) { if (*i == *j) { return true; } } } } // Ensure that the server is up and ready to accept incoming network requests. const Listener* listener = Listener::getTimeTracker(); if (!listener) { return false; } listener->waitUntilListening(); try { DBClientConnection conn; conn.setSoTimeout(30); // 30 second timeout // We need to avoid the isMaster call triggered by a normal connect, which would // cause a deadlock. 'isSelf' is called by the Replication Coordinator when validating // a replica set configuration document, but the 'isMaster' command requires a lock on the // replication coordinator to execute. As such we call we call 'connectSocketOnly', which // does not call 'isMaster'. if (!conn.connectSocketOnly(hostAndPort).isOK()) { return false; } if (getGlobalAuthorizationManager()->isAuthEnabled() && isInternalAuthSet()) { if (!conn.authenticateInternalUser()) { return false; } } BSONObj out; bool ok = conn.simpleCommand("admin", &out, "_isSelf"); bool me = ok && out["id"].type() == jstOID && instanceId == out["id"].OID(); return me; } catch (const std::exception& e) { warning() << "couldn't check isSelf (" << hostAndPort << ") " << e.what() << std::endl; } return false; }