I don't ask a lot of questions on Stack Overflow, but this is one of these times where I'm miserably stuck.
TLDR I need to know how channel.Close()
of golang.org/x/crypto/ssh
works and where I am supposed to call it (assuming that's what I need).
I'm writing a 'small' program to automatically synchronize my Git repositories, including stash, extra files, etc. I use go-ssh to handle the most important part on the server. The current state of the project can be found on GitHub
I tried to narrow it down to a simple example. This is one of the few things I adjusted from the official example in the Golang repository. I got rid of the terminal
references and made it explicitly handle a (random) command:
go func(in <-chan *ssh.Request) {
for req := range in {
switch req.Type {
case "exec":
channel.Stderr().Write([]byte("Request received!\n"))
req.Reply(true, nil)
// Do some more work here
channel.Close() // ???
default:
req.Reply(false, nil)
}
}
wg.Done()
}(requests)
The Gist is over here. There's also another example from someone else over here.
Whenever I try to connect with something like ssh localhost -T -vvvv -p 2022 git-receive-pack foo
to the example, I get the following:
Authenticated to localhost ([::1]:2022) using "publickey".
debug1: channel 0: new session [client-session] (inactive timeout: 0)
debug3: ssh_session2_open: channel_new: 0
debug2: channel 0: send open
debug3: send packet: type 90
debug1: Entering interactive session.
debug1: pledge: filesystem
debug3: client_repledge: enter
debug3: receive packet: type 91
debug2: channel_input_open_confirmation: channel 0: callback start
debug2: fd 3 setting TCP_NODELAY
debug3: set_sock_tos: set socket 3 IPV6_TCLASS 0x20
debug2: client_session2_setup: id 0
debug1: Sending command: git-receive-pack foo
debug2: channel 0: request exec confirm 1
debug3: send packet: type 98
debug3: client_repledge: enter
debug2: channel_input_open_confirmation: channel 0: callback done
debug2: channel 0: open confirm rwindow 2097152 rmax 32768
debug2: channel 0: rcvd ext data 6
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: exec request accepted on channel 0
debug3: receive packet: type 97
debug2: channel 0: rcvd close
debug2: channel 0: output open -> drain
debug2: chan_shutdown_read: channel 0: (i0 o1 sock -1 wfd 4 efd 6 [write])
debug2: channel 0: input open -> closed
debug3: channel 0: will not send data after close
debug2: channel 0: obuf_empty delayed efd 6/(6)
Request received!
debug2: channel 0: written 6 to efd 6
debug3: channel 0: will not send data after close
debug2: channel 0: obuf empty
debug2: chan_shutdown_write: channel 0: (i3 o1 sock -1 wfd 5 efd 6 [write])
debug2: channel 0: output drain -> closed
debug2: channel 0: almost dead
debug2: channel 0: gc: notify user
debug2: channel 0: gc: user detached
debug2: channel 0: send_close2
debug2: channel 0: send close for remote id 0
debug3: send packet: type 97
debug2: channel 0: is dead
debug2: channel 0: garbage collecting
debug1: channel 0: free: client-session, nchannels 1
debug3: channel 0: status: The following connections are open:
#0 client-session (t4 [session] r0 nm0 i3/0 o3/0 e[write]/0 fd -1/-1/6 sock -1 cc -1 nc0 io 0x00/0x00)
debug3: send packet: type 1
Transferred: sent 3624, received 2892 bytes, in 0.0 seconds
Bytes per second: sent 3203530.2, received 2556459.6
debug1: Exit status -1
On my personal project, a 'broken pipe' gets thrown in as well.
Does anyone know how to solve this issue?
From your question, it sounds like maybe you're asking about this bit at the end of the debug output:
debug1: Exit status -1
This isn't an "error" in the sense that your code is behaving as written. An exit status of -1
is the default behavior of go-ssh
if you don't provide an explicit exit code. If you want to return an exit code other than -1
to the client, you can send an exit-status
request back to the client, like this:
go func(in <-chan *ssh.Request) {
for req := range in {
switch req.Type {
case "exec":
channel.Stderr().Write([]byte("Request received!\n"))
req.Reply(true, nil)
// Do some more work here
status := 0
channel.SendRequest("exit-status", false, ssh.Marshal(struct{ Status uint32 }{uint32(status)}))
channel.Close() // ???
default:
req.Reply(false, nil)
}
}
wg.Done()
}(requests)
With this change in place, the debug output looks like:
.
.
.
debug3: send packet: type 1
Transferred: sent 2100, received 2232 bytes, in 0.0 seconds
Bytes per second: sent 3457951.3, received 3675308.2
debug1: Exit status 0