Getting EOF as error in golang ssh session close

Viewed 2277

Im using 'ssh' golang module and I'm wondering if I implemented it (or trying to). Is "EOF" as an error expected at the session.Close()? In the examples I've seen online nobody is checking for the session.Close() error. Is this something I should ignore or handle? From what I can tell there is no error expected from the server either. Im wondering if Im not executing the command properly or not, or not reading the buffer properly.

Here is my code:

package main

import (
    "bytes"
    "fmt"
    "strings"

    "golang.org/x/crypto/ssh"
)

func main() {
    sshConfig := &ssh.ClientConfig{
        User: “my_username”,
        Auth: []ssh.AuthMethod{
            ssh.Password(“my password”),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
    connection, err := ssh.Dial("tcp", "localhost:22", sshConfig)
    if err != nil {
        fmt.Printf("Failed to dial: %s\n", err)
        return
    }

    defer func() {
        if err := connection.Close(); err != nil {
            fmt.Println("Received an error closing the ssh connection: ", err)
        } else {
            fmt.Println("No error found closing ssh connection")
        }
    }()

    session, err := connection.NewSession()
    if err != nil {
        fmt.Printf("Failed to create session: %s\n", err)
        return
    }

    defer func() {
        if err := session.Close(); err != nil {
            fmt.Println("Received an error closing the ssh session: ", err)
        } else {
            fmt.Println("No error found closing ssh session")
        }
    }()
    fmt.Println("created session")
    var stdOut bytes.Buffer
    var stdErr bytes.Buffer

    session.Stdout = &stdOut
    session.Stderr = &stdErr
    err = session.Run("pwd")
    fmt.Println("Executed command")

    fmt.Println("Command stdOut is:", strings.TrimRight(stdOut.String(), "\n"), " --- stdError is:", strings.TrimRight(stdErr.String(), "\n"))

}

The output I getting is:

$ go run main.go
created session
Executed command
Command stdOut is: /Users/my_username  --- stdError is: 
Received an error closing the ssh session:  EOF
No error found closing ssh connection
$ 

Any advice?

1 Answers

That seems similar to golang/go/issue 31401 (which then refers to issue 32453: " x/crypto/ssh: semantics around running session.Wait() after calling session.Run(), when EOF messages are sent")

The error is returned because the session has already been closed (by Run()).
The SSH connection leaks because it is never closed — the client object returned from Dial() is discarded, but that's the object that needs to be closed to clean up the underlying TCP connection.

As an aside, this seems to be a subtle API to use correctly.
The session can be closed asynchronously at any time by the other side, and so it's always possible for correctly-written code to get an EOF from Close()

So you might want to test for that particular error, and ignore it in your defer function.

Related