[SFTP Server] Client hangs on exit
I'm using a lightly modified version of the SFTP server example in the readme, along with the REALPATH logic from the SFTP example in the examples directory of this repo (found here). When I attempt to exit with this configuration, the server refuses to respond with an EOF after the client sends one.
Client logs:
What I see:
Connected to nmdebug.
debug2: Sending SSH2_FXP_REALPATH "."
debug3: Sent message fd 3 T:16 I:1
debug3: SSH2_FXP_REALPATH . -> /
sftp> exit
debug2: channel 0: read failed rfd 4 maxlen 32768: Broken pipe
debug2: channel 0: read failed
debug2: chan_shutdown_read: channel 0: (i0 o0 sock -1 wfd 4 efd 6 [write])
debug2: channel 0: input open -> drain
debug2: channel 0: ibuf empty
debug2: channel 0: send eof
debug3: send packet: type 96
debug2: channel 0: input drain -> closed
What I expect to see:
Connected to nmdebug.
debug2: Sending SSH2_FXP_REALPATH "."
debug3: Sent message fd 3 T:16 I:2
debug3: SSH2_FXP_REALPATH . -> /
sftp> exit
debug2: channel 0: read failed rfd 4 maxlen 32768: Broken pipe
debug2: channel 0: read failed
debug2: chan_shutdown_read: channel 0: (i0 o0 sock -1 wfd 4 efd 6 [write])
debug2: channel 0: input open -> drain
debug2: channel 0: ibuf empty
debug2: channel 0: send eof
debug3: send packet: type 96
debug2: channel 0: input drain -> closed
debug3: receive packet: type 96
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
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
debug3: receive packet: type 98
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug3: receive packet: type 97
debug2: channel 0: rcvd close
debug3: channel 0: will not send data after close
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 4644, received 4684 bytes, in 5.2 seconds
Bytes per second: sent 887.8, received 895.4
debug1: Exit status 0
Server Logs:
Client authenticated!
[49892.626835718] Inbound: CHANNEL_OPEN (s:0, session)
[49892.626835718] Outbound: Sending CHANNEL_OPEN_CONFIRMATION (r:0, l:0)
[49892.626835718] Inbound: CHANNEL_REQUEST (r:0, subsystem: sftp)
Client SFTP session
[49892.626835718] Outbound: Sending CHANNEL_SUCCESS (r:0)
[49892.626835718] Inbound: CHANNEL_DATA (r:0, 9)
[49892.626835718] SFTP: Inbound: Received INIT (v3)
[49892.626835718] Outbound: Sending CHANNEL_DATA (r:0, 9)
[49892.626835718] Inbound: CHANNEL_DATA (r:0, 14)
[49892.626835718] SFTP: Inbound: Received REALPATH (id:1)
[49892.626835718] Outbound: Sending CHANNEL_DATA (r:0, 67)
[49892.626835718] SFTP: Outbound: Buffered NAME
[49892.626835718] Inbound: CHANNEL_EOF (r:0)
We're facing the exact same issue. We haven't found any way to listen to the client disconnecting and force that disconnection. We also tried adding a lower limit for the keepalive timeout with no success.
Managed to fix it. Had to dig into the code. Seems like the session emits undocumented end and eof events. I added the code below:
const session = accept()
+ session.on('end', () => {
+ // session can be undefined for clients other than `sftp`.
+ if (session) session.end()
+ })
session.on('sftp', (accept, reject) => {
...
})
What version are you using? I get an error that says session.end() is not a function for me when I do that (part of why I reported this issue)
edit: I assume 1.16.0, it's been out for a while.
That's why I added that if (session) because I got that error for other clients. Yes, 1.16.0.
Wait, did you add it in the correct place maybe? This is before the sftp handler.
Edit: our code pretty heavily deviates from the examples that's why I provided an excerpt Edit 2: Also, we are on Node 20 if that helps
Wait, did you add it in the correct place maybe?
I think so?
Error:
/run/media/watergate/programming/netmountcc/src/sftp.ts:29
if (session) session.end()
^
TypeError: session.end is not a function
at Session.<anonymous> (/run/media/watergate/programming/netmountcc/src/sftp.ts:29:42)
at Session.emit (node:events:507:28)
at Session.emit (node:domain:489:12)
at CHANNEL_EOF (/run/media/watergate/programming/netmountcc/node_modules/ssh2/lib/server.js:1024:23)
at 96 (/run/media/watergate/programming/netmountcc/node_modules/ssh2/lib/protocol/handlers.misc.js:978:16)
at Protocol.onPayload (/run/media/watergate/programming/netmountcc/node_modules/ssh2/lib/protocol/Protocol.js:2059:10)
at ChaChaPolyDecipherBinding.decrypt (/run/media/watergate/programming/netmountcc/node_modules/ssh2/lib/protocol/crypto.js:851:26)
at Protocol.parsePacket [as _parse] (/run/media/watergate/programming/netmountcc/node_modules/ssh2/lib/protocol/Protocol.js:2028:25)
at Protocol.parse (/run/media/watergate/programming/netmountcc/node_modules/ssh2/lib/protocol/Protocol.js:313:16)
at Socket.<anonymous> (/run/media/watergate/programming/netmountcc/node_modules/ssh2/lib/server.js:1213:17)
Hmm interesting, now I see this too. Apparently the error caused the disconnection 😅 I'll investigate.
Seems like closing the parent client ssh Connection works instead of the SFTP session, I don't see any errors.
Edit: deploying now to our live server and testing that as well.
Edit2: works now without issues, so in your code, doing client.end() should solve the problem
Nice, that worked!
Going to leave the issue open for now, since it's technically an issue with documentation/example code. Thanks for the help!