2010-06-05 148 views
1

我在我的應用程序中的特殊應用程序端口上調用:: connect(),但它在一般情況下工作正常,但是,在兩臺特定機器之間,它們從EHOSTUNREACH失敗,這意味着「沒有路由到主機。 「爲什麼當ssh工作正常時,connect()返回EHOSTUNREACH?

如果我可以在沒有問題的端口22上ssh,那麼在這裏可能會發生:: connect()對於這個特定的機器對總是失敗?

在詳細模式下單產運行SSH:

[localMachine ~] ssh -v -p 22 remoteMachine 
OpenSSH_3.9p1, OpenSSL 0.9.7a Feb 19 2003 
debug1: Reading configuration data /etc/ssh/ssh_config 
debug1: Applying options for * 
debug1: Connecting to remoteMachine [10.34.49.107] port 22. 
debug1: Connection established. 
debug1: identity file /home/WilliamKF/.ssh/identity type -1 
debug1: identity file /home/WilliamKF/.ssh/id_rsa type 1 
debug1: identity file /home/WilliamKF/.ssh/id_dsa type -1 
debug1: Remote protocol version 2.0, remote software version OpenSSH_4.3 
debug1: match: OpenSSH_4.3 pat OpenSSH* 
debug1: Enabling compatibility mode for protocol 2.0 
debug1: Local version string SSH-2.0-OpenSSH_3.9p1 
debug1: SSH2_MSG_KEXINIT sent 
debug1: SSH2_MSG_KEXINIT received 
debug1: kex: server->client aes128-cbc hmac-md5 none 
debug1: kex: client->server aes128-cbc hmac-md5 none 
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent 
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP 
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent 
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY 
debug1: Host 'remoteMachine' is known and matches the RSA host key. 
debug1: Found key in /home/WilliamKF/.ssh/known_hosts:47 
debug1: ssh_rsa_verify: signature correct 
debug1: SSH2_MSG_NEWKEYS sent 
debug1: expecting SSH2_MSG_NEWKEYS 
debug1: SSH2_MSG_NEWKEYS received 
debug1: SSH2_MSG_SERVICE_REQUEST sent 
debug1: SSH2_MSG_SERVICE_ACCEPT received 
debug1: Authentications that can continue: publickey,gssapi-with-mic,password 
debug1: Next authentication method: gssapi-with-mic 
debug1: Authentications that can continue: publickey,gssapi-with-mic,password 
debug1: Authentications that can continue: publickey,gssapi-with-mic,password 
debug1: Next authentication method: publickey 
debug1: Trying private key: /home/WilliamKF/.ssh/identity 
debug1: Offering public key: /home/WilliamKF/.ssh/id_rsa 
debug1: Server accepts key: pkalg ssh-rsa blen 149 
debug1: read PEM private key done: type RSA 
debug1: Authentication succeeded (publickey). 
debug1: channel 0: new [client-session] 
debug1: Entering interactive session. 

這裏是在客戶端的功能:

void // virtual 
Sender::connectTCP() 
{ 
    // First build the feedback channel's socket & make it reuseable 
    // so we don't get the nasty message. 
    if (0 > (setFbSocket(socket(AF_INET, SOCK_STREAM, 0)))) { 
    THROW_ERR("failed to create the command socket: "); 
    } 

    setSocketOptions(); 

    // Build the localIp address and bind it to the feedback socket. 
    // Although it's not traditional for a client to bind the sending socket 
    // to a the local address, we do it to prevent connect() from using an 
    // ephemeral port which (our site's firewall may block). Also build the 
    // remoteIp address. 
    buildAddr(getTCPcommandLocalAddr(), getLocalHost().c_str(), 
      getLocFbPort()); 
    deepBind(getFbSocket(), getTCPcommandLocalAddr()); 
    buildAddr(getTCPcommandRemoteAddr(), getRemoteHost().c_str(), 
      getRemFbPort()); 

    // Connect to the receiver at the remote addr. Make multiple attempts 
    // when we get a connection refused errno (ECONNREFUSED). ECONNREFUSED 
    // means no one is listening at the other end ... which my be the result 
    // of a race condition (i.e., we're calling connect before the server has 
    // gotten to listen.) 
    const int timeoutMinutes = 5; 
    const int timeoutSeconds = timeoutMinutes * 60; 
    int conCount = timeoutSeconds; 

    while ((conCount > 0) && 
     (0 > ::connect(getFbSocket(), 
         (sockaddr*)&getTCPcommandRemoteAddr(), 
         sizeof(sockaddr)))) { 
    switch (errno) { 
     case ECONNREFUSED: { 
     ::sleep(1); 
     --conCount; 
     // Warn every 15 seconds, but don't warn at 5 minutes exactly. 
     if ((conCount % 15) == 0 && conCount) { 
      clog << "Warning: The server connection" 
       << " has been refused for " 
       << timeFromSeconds(timeoutSeconds - conCount) 
       << ", will continue to retry for up to " 
       << timeoutMinutes << " minutes.\n" 
       << "Perhaps ports " << getRemFbPort() << " and " 
       << getRemDataPort() 
       << 
      " are not being routed properly to the server or alternatively " 
      "perhaps nothing on the server is listening to those ports?\n"; 
     } 
     continue; 
     } 
     case EHOSTUNREACH: { 
     clog << "Error: Command connect failed: No route to host '" 
      << getRemoteHost() << "'." << endl; 
     throw; 
     } 
     default: { 
     clog << "Error: Command connect failed: " 
      << strerror(errno) << endl; 
     throw; 
     } 
    } 
    } 
    if (conCount == 0) { 
    clog << "Error: Command connect" 
     << " continually refused after retrying for " << timeoutMinutes 
     << " minutes: " 
     << strerror(errno) << endl; 

    throw; 
    } 

    setCmdBlocking(); 
    setDataBlocking(); 
    setFbIsConn(true); 

    clog << "Application has connected to " 
     << getRemoteHost() << ":" << getRemFbPort() << endl; 
} 
+0

它是否適用於其他機器?有任何代碼發佈? – 2010-06-05 16:17:18

+0

是的,它適用於所有其他機器。 – WilliamKF 2010-06-05 16:22:16

回答

4

你能運行到目標端口的防火牆過濾?你是否嘗試連接到端口22或你的sshd運行的端口;或者其他一些端口?

+0

首先通過端口22上的ssh進行連接,在端口22上協商調用:: connect()的端口。 – WilliamKF 2010-06-05 16:35:34

+0

目標端口被遠程服務器的防火牆阻止。 – WilliamKF 2010-06-05 18:35:56

+0

甜;很高興你找到了它。 :)我猜想,因爲我最近將防火牆與「主機不可達」和「網絡不可達」聯繫在一起。 – 2010-06-05 18:50:45

0

名稱解析有點奇怪嗎? (你可能被host文件絆住了?ssh忽略了DNS中的AAAA(IPv6)記錄?ssh_config?)可能值得在詳細模式下運行ssh來查看它連接到的主機。

1

看起來你顯式地綁定了客戶端的套接字 - 看看你綁定的地址是否在服務器端無法訪問(例如由於路由問題)。爲了能夠從潛在的防火牆問題(即允許端口22的防火牆,但拒絕您的應用程序端口)中得知這一點,請嘗試telnet到目標主機:端口,而不是ssh到端口22.

+0

Telnet到連接失敗的端口也會獲得「無路由到主機」。錯誤。 – WilliamKF 2010-06-05 17:31:43