Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SFTP Server] Client hangs on exit #1443

Open
hugeblank opened this issue Feb 8, 2025 · 9 comments
Open

[SFTP Server] Client hangs on exit #1443

hugeblank opened this issue Feb 8, 2025 · 9 comments

Comments

@hugeblank
Copy link

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)
@arpadgabor
Copy link

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.

@arpadgabor
Copy link

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) => {
    ...
  })

@hugeblank
Copy link
Author

hugeblank commented Feb 13, 2025

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.

@arpadgabor
Copy link

That's why I added that if (session) because I got that error for other clients. Yes, 1.16.0.

@arpadgabor
Copy link

arpadgabor commented Feb 13, 2025

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

@hugeblank
Copy link
Author

Wait, did you add it in the correct place maybe?

I think so?
Image

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)

@arpadgabor
Copy link

Hmm interesting, now I see this too. Apparently the error caused the disconnection 😅 I'll investigate.

@arpadgabor
Copy link

arpadgabor commented Feb 13, 2025

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

@hugeblank
Copy link
Author

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants