Search code examples
openssh

ssh "packet_write_wait: Connection to x.x.x.x port 22: Broken pipe" -- where is the source code?


We got a client ssh to a remote server showing this error. It has always been running fine, no firewall rules change either. When an ssh session is idled over the weekend, it is still connected. Just some times when we 'less' and shift-F on a file for couple of hours, it shows this error.

I'm not trying to solve this problem in this post. We want to look at the ssh source code to figure out what is going on. On Centos 7, I downloaded openssh-7.4p1-21.el7.src.rpm, and extracted openssh-7.4p1.tar.gz. 'grep' through source code and found 'packet_write_wait' function. But curiously, "Broken pipe" (or -i on each word separately) is not found in all the .h and .c files. Where is that error text coming from?


Solution

  • You can find a copy of the OpenSSH source code in github. The packet_write_wait function is in opacket.c:

    void
    packet_write_wait(void)
    {
        int r;
    
        if ((r = ssh_packet_write_wait(active_state)) != 0)
            sshpkt_fatal(active_state, __func__, r);
    }
    

    It calls another function to write the packet. If that fails, it calls sshpkt_fatal. sshpkt_fatal is in packet.c, and its job is to print an error message and then exit.

    /*
     * Pretty-print connection-terminating errors and exit.
     */
    void
    sshpkt_fatal(struct ssh *ssh, const char *tag, int r)
    {
        switch (r) {
        case SSH_ERR_CONN_CLOSED:
            logdie("Connection closed by %.200s port %d",
                ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
    [...code removed...]
                /* FALLTHROUGH */
        default:
            logdie("%s%sConnection %s %.200s port %d: %s",
                tag != NULL ? tag : "", tag != NULL ? ": " : "",
                ssh->state->server_side ? "from" : "to",
                ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), ssh_err(r));
        }
    }
    

    The message that you're asking about is handled by the default case. The last argument, which provides the text after the colon, is provided by calling ssh_err:

    const char *
    ssh_err(int n)
    {
        switch (n) {
        case SSH_ERR_SUCCESS:
            return "success";
        case SSH_ERR_INTERNAL_ERROR:
            return "unexpected internal error";
    [...etc...]
    

    The ssh_err case that you're interested in is this one:

    case SSH_ERR_SYSTEM_ERROR:
            return strerror(errno);
    

    In short, the "Broken pipe" message comes from the standard library function strerror, which converts error numbers to standard error messages.

    The list of standard error codes indicates that "Broken pipe" is associated with the EPIPE error.