Esempio n. 1
0
EIO_Status CConnTest::DispatcherOkay(string* reason)
{
    SConnNetInfo* net_info = ConnNetInfo_Create(0, m_DebugPrintout);
    ConnNetInfo_SetupStandardArgs(net_info, kTest);

    PreCheck(eDispatcher, 0/*main*/,
             "Checking whether NCBI dispatcher is okay");

    int okay = 0;
    SAuxData* auxdata = new SAuxData(m_Canceled, &okay);
    CConn_HttpStream http(net_info, kEmptyStr/*user_header*/, s_SvcHeader,
                          auxdata, s_Adjust, s_Cleanup, 0/*flags*/, m_Timeout);
    http.SetCanceledCallback(m_Canceled);
    char buf[1024];
    http.read(buf, sizeof(buf));
    CTempString str(buf, (size_t) http.gcount());
    EIO_Status status = ConnStatus
        (okay != 1  ||
         NStr::FindNoCase(str, "NCBI Dispatcher Test Page") == NPOS  ||
         NStr::FindNoCase(str, "Welcome") == NPOS, &http);

    string temp;
    if (status == eIO_Interrupt)
        temp = kCanceled;
    else if (status == eIO_Success)
        temp = "OK";
    else {
        if (status != eIO_Timeout) {
            if (okay) {
                temp = "Make sure there are no stray [CONN]{HOST|PORT|PATH}"
                    " settings in the way in your configuration\n";
            }
            if (okay == 1) {
                temp += "Service response was not recognized; please contact "
                    + HELP_EMAIL + '\n';
            }
        } else
            temp += x_TimeoutMsg();
        if (!(okay & 1)) {
            temp += "Check with your network administrator that your network"
                " neither filters out nor blocks non-standard HTTP headers\n";
        }
    }

    PostCheck(eDispatcher, 0/*main*/, status, temp);

    ConnNetInfo_Destroy(net_info);
    if (reason)
        reason->swap(temp);
    return status;
}
Esempio n. 2
0
EIO_Status CConnTest::GetFWConnections(string* reason)
{
    SConnNetInfo* net_info = ConnNetInfo_Create(0, m_DebugPrintout);
    if (net_info) {
        const char* user_header;
        net_info->req_method = eReqMethod_Post;
        if (net_info->firewall) {
            user_header = "NCBI-RELAY: FALSE";
            m_Firewall = true;
        } else
            user_header = "NCBI-RELAY: TRUE";
        if (net_info->stateless)
            m_Stateless = true;
        ConnNetInfo_OverrideUserHeader(net_info, user_header);
        ConnNetInfo_SetupStandardArgs(net_info, 0/*w/o service*/);
    }

    string temp(m_Firewall ? "FIREWALL" : "RELAY (legacy)");
    temp += " connection mode has been detected for stateful services\n";
    if (m_Firewall) {
        temp += "This mode requires your firewall to be configured in such a"
            " way that it allows outbound connections to the port range ["
            STRINGIFY(CONN_FWD_PORT_MIN) ".." STRINGIFY(CONN_FWD_PORT_MAX)
            "] (inclusive) at the two fixed NCBI addresses, "
            NCBI_FWD_BEMD " and " NCBI_FWD_STVA ".\n"
            "To set that up correctly, please have your network administrator"
            " read the following (if they have not already done so):"
            " " NCBI_FWDOC_URL "\n";
    } else {
        temp += "This is an obsolescent mode that requires keeping a wide port"
            " range [4444..4544] (inclusive) open to let through connections"
            " to the entire NCBI site (130.14.xxx.xxx/165.112.xxx.xxx) -- this"
            " mode was designed for unrestricted networks when firewall port"
            " blocking had not been an issue\n";
    }
    if (m_Firewall) {
        _ASSERT(net_info);
        switch (net_info->firewall) {
        case eFWMode_Adaptive:
            temp += "Also, there are usually a few additional ports such as "
                STRINGIFY(CONN_PORT_SSH) " and " STRINGIFY(CONN_PORT_HTTPS)
                " at " NCBI_FWD_BEMD ", which can be used if connections to"
                " the ports in the range described above, have failed\n";
            break;
        case eFWMode_Firewall:
            temp += "Furthermore, your configuration explicitly forbids to use"
                " any fallback firewall ports that may exist to improve"
                " reliability of connection experience\n";
            break;
        case eFWMode_Fallback:
            temp += "There are usually a few backup connection ports such as "
                STRINGIFY(CONN_PORT_SSH) " and " STRINGIFY(CONN_PORT_HTTPS)
                " at " NCBI_FWD_BEMD ", which can be used as a failover if"
                " connections to the port range above fail.  However, your "
                " configuration explicitly requests that only those fallback"
                " firewall ports (if any exist) are to be used for"
                " connections:  this also implies that no conventional ports"
                " from the default range will be used\n";
            break;
        default:
            temp += "Internal program error, please report!\n";
            _ASSERT(0);
            break;
        }
    } else {
        temp += "This mode may not be reliable if your site has a restraining"
            " firewall imposing a fine-grained control over which hosts and"
            " ports the outbound connections are allowed to use\n";
    }
    if (m_HttpProxy) {
        temp += "Connections to the aforementioned ports will be made via an"
            " HTTP proxy at '";
        temp += net_info->http_proxy_host;
        temp += ':';
        temp += NStr::UIntToString(net_info->http_proxy_port);
        temp += "'";
        if (net_info->http_proxy_leak) {	 
            temp += ".  If that is unsuccessful, a link bypassing the proxy"
                " will then be attempted";
        }
    }
    temp += '\n';

    PreCheck(eFirewallConnPoints, 0/*main*/, temp);

    PreCheck(eFirewallConnPoints, 1/*sub*/,
             "Obtaining current NCBI " +
             string(m_Firewall ? "firewall settings" : "service entries"));

    EIO_Status status = x_GetFirewallConfiguration(net_info);

    if (status == eIO_Interrupt)
        temp = kCanceled;
    else if (status == eIO_Success) {
        if (!m_Fwd.empty()
            ||  (!m_FwdFB.empty()
                 &&  m_Firewall  &&  net_info->firewall == eFWMode_Fallback)) {
            temp = "OK: ";
            if (!m_Fwd.empty()) {
                stable_sort(m_Fwd.begin(),   m_Fwd.end());
                temp += NStr::UInt8ToString(m_Fwd.size());
            }
            size_t down = 0;
            if (!m_FwdFB.empty()) {
                stable_sort(m_FwdFB.begin(), m_FwdFB.end());
                if (!m_Fwd.empty())
                    temp += " + ";
                temp += NStr::UInt8ToString(m_FwdFB.size());
                ITERATE(vector<CConnTest::CFWConnPoint>, cp, m_FwdFB) {
                    if (cp->status != eIO_Success)
                        ++down;
                }
                if (down)
                    temp += " - " + NStr::UInt8ToString(down);
            }
            temp +=
                m_Fwd.size() + m_FwdFB.size() - down == 1 ? " port" : " ports";
        } else {
Esempio n. 3
0
EIO_Status CConnTest::ServiceOkay(string* reason)
{
    static const char kService[] = "bounce";

    SConnNetInfo* net_info = ConnNetInfo_Create(kService, m_DebugPrintout);
    if (net_info)
        net_info->lb_disable = 1/*no local LB to use even if available*/;

    PreCheck(eStatelessService, 0/*main*/,
             "Checking whether NCBI services operational");

    CConn_ServiceStream svc(kService, fSERV_Stateless, net_info,
                            0/*extra*/, m_Timeout);
    svc.SetCanceledCallback(m_Canceled);

    svc << kTest << NcbiEndl;
    string temp;
    svc >> temp;
    bool responded = temp.size() > 0 ? true : false;
    EIO_Status status = ConnStatus(NStr::Compare(temp, kTest) != 0, &svc);

    if (status == eIO_Interrupt)
        temp = kCanceled;
    else if (status == eIO_Success)
        temp = "OK";
    else {
        char* str = net_info ? SERV_ServiceName(kService) : 0;
        if (str  &&  NStr::CompareNocase(str, kService) == 0) {
            free(str);
            str = 0;
        }
        SERV_ITER iter = SERV_OpenSimple(kService);
        if (!iter  ||  !SERV_GetNextInfo(iter)) {
            // Service not found
            SERV_Close(iter);
            iter = SERV_OpenSimple(kTest);
            if (!iter  ||  !SERV_GetNextInfo(iter)
                ||  NStr::CompareNocase(SERV_MapperName(iter), "DISPD") != 0) {
                // Make sure there will be a mapper error printed
                SERV_Close(iter);
                temp.clear();
                iter = 0;
            } else {
                // kTest service can be located but not kService
                temp = str ? "Substituted service" : "Service";
                temp += " cannot be located";
            }
        } else {
            temp = responded ? "Unrecognized" : "No";
            temp += " response from ";
            temp += str ? "substituted service" : "service";
        }
        if (!temp.empty()) {
            if (str) {
                temp += "; please remove [";
                string upper(kService);
                temp += NStr::ToUpper(upper);
                temp += "]CONN_SERVICE_NAME=\"";
                temp += str;
                temp += "\" from your configuration\n";
            } else if (status != eIO_Timeout  ||  m_Timeout > kTimeout)
                temp += "; please contact " + HELP_EMAIL + '\n';
        }
        if (status != eIO_Timeout) {
            const char* mapper = SERV_MapperName(iter);
            if (!mapper  ||  NStr::CompareNocase(mapper, "DISPD") != 0) {
                temp += "Network dispatcher is not enabled as a service"
                    " locator;  please review your configuration to purge any"
                    " occurrences of [CONN]DISPD_DISABLE off your settings\n";
            }
        } else
            temp += x_TimeoutMsg();
        SERV_Close(iter);
        if (str)
            free(str);
    }

    PostCheck(eStatelessService, 0/*main*/, status, temp);

    ConnNetInfo_Destroy(net_info);
    if (reason)
        reason->swap(temp);
    return status;
}
Esempio n. 4
0
EIO_Status CConnTest::HttpOkay(string* reason)
{
    SConnNetInfo* net_info = ConnNetInfo_Create(0, m_DebugPrintout);
    if (net_info) {
        if (net_info->http_proxy_host[0]  &&  net_info->http_proxy_port)
            m_HttpProxy = true;
        // Make sure there are no extras
        ConnNetInfo_SetUserHeader(net_info, 0);
        net_info->args[0] = '\0';
    }

    PreCheck(eHttp, 0/*main*/,
             "Checking whether NCBI is HTTP accessible");

    string host(net_info ? net_info->host : DEF_CONN_HOST);
    string port(net_info  &&  net_info->port
                ? ':' + NStr::UIntToString(net_info->port)
                : kEmptyStr);
    SAuxData* auxdata = new SAuxData(m_Canceled, 0);
    CConn_HttpStream http("/Service/index.html",
                          net_info, kEmptyStr/*user_header*/, s_GoodHeader,
                          auxdata, s_Adjust, s_Cleanup, 0/*flags*/, m_Timeout);
    http.SetCanceledCallback(m_Canceled);
    string temp;
    http >> temp;
    EIO_Status status = ConnStatus(temp.empty(), &http);

    if (status == eIO_Interrupt)
        temp = kCanceled;
    else if (status == eIO_Success)
        temp = "OK";
    else {
        if (status == eIO_Timeout)
            temp = x_TimeoutMsg();
        else
            temp.clear();
        if (NStr::CompareNocase(host, DEF_CONN_HOST) != 0  ||  !port.empty()) {
            int n = 0;
            temp += "Make sure that ";
            if (host != DEF_CONN_HOST) {
                n++;
                temp += "[CONN]HOST=\"";
                temp += host;
                temp += port.empty() ? "\"" : "\" and ";
            }
            if (!port.empty()) {
                n++;
                temp += "[CONN]PORT=\"";
                temp += port.c_str() + 1;
                temp += '"';
            }
            _ASSERT(n);
            temp += n > 1 ? " are" : " is";
            temp += " redefined correctly\n";
        }
        if (m_HttpProxy) {
            temp += "Make sure that the HTTP proxy server \'";
            temp += net_info->http_proxy_host;
            temp += ':';
            temp += NStr::UIntToString(net_info->http_proxy_port);
            temp += "' specified with [CONN]HTTP_PROXY_{HOST|PORT} is correct";
        } else {
            if (net_info->http_proxy_host[0]  ||  net_info->http_proxy_port) {
                temp += "Note that your HTTP proxy seems to have been"
                    " specified only partially, and thus cannot be used: the ";
                if (net_info->http_proxy_port) {
                    temp += "host part is missing (for port :"
                        + NStr::UIntToString(net_info->http_proxy_port);
                } else {
                    temp += "port part is missing (for host \'"
                        + string(net_info->http_proxy_host) + '\'';
                }
                temp += ")\n";
            }
            temp += "If your network access requires the use of an HTTP proxy"
                " server, please contact your network administrator and set"
                " [CONN]HTTP_PROXY_{HOST|PORT} (both must be set) in your"
                " configuration accordingly";
        }
        temp += "; and if your proxy server requires authorization, please"
            " check that appropriate [CONN]HTTP_PROXY_{USER|PASS} have been"
            " set\n";
        if (net_info  &&  (*net_info->user  ||  *net_info->pass)) {
            temp += "Make sure there are no stray [CONN]{USER|PASS} that"
                " appear in your configuration -- NCBI services neither"
                " require nor use them\n";
        }
    }

    PostCheck(eHttp, 0/*main*/, status, temp);

    ConnNetInfo_Destroy(net_info);
    if (reason)
        reason->swap(temp);
    return status;
}
Esempio n. 5
0
EIO_Status CConnTest::ExtraCheckOnFailure(void)
{
    static const STimeout kTimeout   = { 5,      0 };
    static const STimeout kTimeSlice = { 0, 100000 };
    static const struct {
        const char*  host;
        const char* vhost;
    } kTests[] = {
        // 0. NCBI default
        { "",                           0                      }, // NCBI
        // 1. External server(s)
        { "www.google.com",             0                      },
        //    NB: Google's public DNS (also @8.8.8.8), responds at :80 as well
        { "8.8.4.4",                    "www.google.com"       },
        // 2. NCBI servers, explicitly
        { "www.be-md.ncbi.nlm.nih.gov", "www.ncbi.nlm.nih.gov" }, // NCBI main
        { "www.st-va.ncbi.nlm.nih.gov", "www.ncbi.nlm.nih.gov" }, // NCBI colo
        { "130.14.29.110",              "www.ncbi.nlm.nih.gov" }, // NCBI main
        { "165.112.7.20",               "www.ncbi.nlm.nih.gov" }  // NCBI colo
    };

    m_CheckPoint.clear();
    PreCheck(eNone, 0/*main*/, "Failback HTTP access check");

    SConnNetInfo* net_info = ConnNetInfo_Create(0, eDebugPrintout_Data);
    if (!net_info) {
        PostCheck(eNone, 0/*main*/,
                  eIO_Unknown, "Cannot create network info structure");
        return eIO_Unknown;
    }

    net_info->req_method = eReqMethod_Head;
    net_info->timeout    = &kTimeout;
    net_info->max_try    = 0;
    m_Timeout = 0;

    CDeadline deadline(kTimeout.sec, kTimeout.usec * 1000);
    time_t           sec;
    unsigned int nanosec;
    deadline.GetExpirationTime(&sec, &nanosec);
    ::sprintf(net_info->path, "/NcbiTest%08lX%08lX",
              (unsigned long) sec, (unsigned long) nanosec);

    vector< AutoPtr<CConn_HttpStream> > http;
    for (size_t n = 0;  n < sizeof(kTests) / sizeof(kTests[0]);  ++n) {
        char user_header[80];
        _ASSERT(::strlen(kTests[n].host) < sizeof(net_info->host) - 1);
        if (kTests[n].host[0])
            ::strcpy(net_info->host, kTests[n].host);
        if (kTests[n].vhost) {
            _ASSERT(::strlen(kTests[n].vhost) + 6 < sizeof(user_header) - 1);
            ::sprintf(user_header, "Host: %s", kTests[n].vhost);
        } else
            *user_header = '\0';
        SAuxData* auxdata = new SAuxData(m_Canceled, 0);
        http.push_back(new CConn_HttpStream(net_info, user_header, s_AnyHeader,
                                            auxdata, s_Adjust, s_Cleanup));
        http.back()->SetCanceledCallback(m_Canceled);
    }

    EIO_Status status = eIO_Success;
    do {
        if (!http.size())
            break;
        ERASE_ITERATE(vector< AutoPtr<CConn_HttpStream> >, h, http) {
            CONN conn = (*h)->GetCONN();
            if (!conn) {
                VECTOR_ERASE(h, http);
                if (status == eIO_Success)
                    status  = eIO_Unknown;
                continue;
            }
            EIO_Status readst = CONN_Wait(conn, eIO_Read, &kTimeSlice);
            if (readst > eIO_Timeout) {
                if (readst == eIO_Interrupt) {
                    status  = eIO_Interrupt;
                    break;
                }
                if (status < readst  &&  (*h)->GetStatusCode() != 404)
                    status = readst;
                VECTOR_ERASE(h, http);
                continue;
            }
        }
    } while (status != eIO_Interrupt  &&  !deadline.IsExpired());

    if (status == eIO_Success  &&  http.size())
        status  = eIO_Timeout;

    PostCheck(eNone, 0/*main*/, status, kEmptyStr);

    return status;
}
Esempio n. 6
0
EIO_Status CConnTest::GetFWConnections(string* reason)
{
    SConnNetInfo* net_info = ConnNetInfo_Create(0);
    if (net_info) {
        const char* user_header;
        net_info->req_method = eReqMethod_Post;
        if (net_info->firewall) {
            user_header = "NCBI-RELAY: FALSE";
            m_Firewall = true;
        } else
            user_header = "NCBI-RELAY: TRUE";
        if (net_info->stateless)
            m_Stateless = true;
        ConnNetInfo_OverrideUserHeader(net_info, user_header);
        ConnNetInfo_SetupStandardArgs(net_info, 0/*w/o service*/);
    }

    string temp(m_Firewall ? "FIREWALL" : "RELAY (legacy)");
    temp += " connection mode has been detected for stateful services\n";
    if (m_Firewall) {
        temp += "This mode requires your firewall to be configured in such a"
            " way that it allows outbound connections to the port range ["
            STRINGIFY(CONN_FWD_PORT_MIN) ".." STRINGIFY(CONN_FWD_PORT_MAX)
            "] (inclusive) at the two fixed NCBI hosts, 130.14.29.112"
            " and 165.112.7.12\n"
            "To set that up correctly, please have your network administrator"
            " read the following (if they have not already done so):"
            " " NCBI_FW_URL "\n";
    } else {
        temp += "This is an obsolescent mode that requires keeping a wide port"
            " range [4444..4544] (inclusive) open to let through connections"
            " to any NCBI host (130.14.2x.xxx/165.112.xx.xxx) -- this mode was"
            " designed for unrestricted networks when firewall port blocking"
            " was not an issue\n";
    }
    if (m_Firewall) {
        _ASSERT(net_info);
        switch (net_info->firewall) {
        case eFWMode_Adaptive:
            temp += "There are also fallback connection ports such as 22 and"
                " 443 at 130.14.29.112.  They will be used if connections to"
                " the ports in the range described above have failed\n";
            break;
        case eFWMode_Firewall:
            temp += "Also, your configuration explicitly forbids to use any"
                " fallback firewall ports that may exist to improve network"
                " connectivity\n";
            break;
        case eFWMode_Fallback:
            temp += "However, your configuration explicitly requests that only"
                " fallback firewall ports (if any exist) are to be used for"
                " connections: this also implies that no conventional ports"
                " from the range above will be used\n";
            break;
        default:
            temp += "Internal program error, please report!\n";
            _ASSERT(0);
            break;
        }
    } else {
        temp += "This mode may not be reliable if your site has a restrictive"
            " firewall imposing fine-grained control over which hosts and"
            " ports the outbound connections are allowed to use\n";
    }
    if (m_HttpProxy) {
        temp += "Connections to the aforementioned ports will be made via an"
            " HTTP proxy at '";
        temp += net_info->http_proxy_host;
        temp += ':';
        temp += NStr::UIntToString(net_info->http_proxy_port);
        temp += "'";
        if (net_info  &&  net_info->http_proxy_leak) {
            temp += ".  If that is unsuccessful, a link bypassing the proxy"
                " will then be attempted";
        }
        if (m_Firewall  &&  *net_info->proxy_host)
            temp += ". In addition, your";
    }
    if (m_Firewall  &&  *net_info->proxy_host) {
        if (!m_HttpProxy)
            temp += "Your";
        temp += " configuration specifies that instead of connecting directly"
            " to NCBI addresses, a forwarding non-transparent proxy host '";
        temp += net_info->proxy_host;
        temp += "' should be used for all links";
        if (m_HttpProxy)
            temp += " (including those originating from the HTTP proxy)";
    }
    temp += '\n';

    PreCheck(eFirewallConnPoints, 0/*main*/, temp);

    PreCheck(eFirewallConnPoints, 1/*sub*/,
             "Obtaining current NCBI " +
             string(m_Firewall ? "firewall settings" : "service entries"));

    EIO_Status status = x_GetFirewallConfiguration(net_info);

    if (status == eIO_Interrupt)
        temp = kCanceled;
    else if (status == eIO_Success) {
        if (!m_Fwd.empty()
            ||  (!m_FwdFB.empty()
                 &&  m_Firewall  &&  net_info->firewall == eFWMode_Fallback)) {
            temp = "OK: ";
            if (!m_Fwd.empty()) {
                stable_sort(m_Fwd.begin(),   m_Fwd.end());
                temp += NStr::UInt8ToString(m_Fwd.size());
            }
            if (!m_FwdFB.empty()) {
                stable_sort(m_FwdFB.begin(), m_FwdFB.end());
                if (!m_Fwd.empty())
                    temp += " + ";
                temp += NStr::UInt8ToString(m_FwdFB.size());
            }
            temp += m_Fwd.size() + m_FwdFB.size() == 1 ? " port" : " ports";
        } else {
            status = eIO_Unknown;
            temp = "No connection ports found, please contact " + HELP_EMAIL;
        }
    } else if (status == eIO_Timeout) {
        temp = x_TimeoutMsg();
        if (m_Timeout > kTimeout)
            temp += "You may want to contact " + HELP_EMAIL;
    } else
        temp = "Please contact " + HELP_EMAIL;

    PostCheck(eFirewallConnPoints, 1/*sub*/, status, temp);

    ConnNetInfo_Destroy(net_info);

    if (status == eIO_Success) {
        PreCheck(eFirewallConnPoints, 2/*sub*/,
                 "Verifying configuration for consistency");

        bool firewall = true;
        // Check primary ports only
        ITERATE(vector<CConnTest::CFWConnPoint>, cp, m_Fwd) {
            if (cp->port < CONN_FWD_PORT_MIN  ||  CONN_FWD_PORT_MAX < cp->port)
                firewall = false;
            if (cp->status != eIO_Success) {
                status = cp->status;
                temp  = CSocketAPI::HostPortToString(cp->host, cp->port);
                temp += " is not operational, please contact " + HELP_EMAIL;
                break;
            }
        }
        if (status == eIO_Success) {
            if (!m_Firewall  &&  !m_FwdFB.empty()) {
                status = eIO_Unknown;
                temp = "Fallback ports found in non-firewall mode, please"
                    " contact " + HELP_EMAIL;
            } else if (m_Firewall != firewall) {
                status = eIO_Unknown;
                temp  = "Firewall ";
                temp += firewall ? "wrongly" : "not";
                temp += " acknowledged, please contact " + HELP_EMAIL;
            } else
                temp.resize(2);
        }

        PostCheck(eFirewallConnPoints, 2/*sub*/, status, temp);
    }