Repository navigation
Make it possible to forcibly RST a net.Socket #27428
Description
Activity
Have you tried doing a
socket.destroy()? It won't send a RST, but if more data arrives from the server after the .destroy(), that should trigger a RST response.Interesting! You're right, it's possible to make that work, but it ends up a little hacky. You can get close by translating the Python code and removing the delay, but you have a race to make sure you destroy after the request is sent but before the server response. To test I'm doing that with
setTimeout(f, 0)straight afterwrite(), which seems to win that race reliably, but it doesn't fill me with confidence.I'd like to leave this open, as I would much prefer to be able to explicitly send the RST myself on demand rather than depending on this. It's easy to imagine similar situations where you don't know that there's imminent incoming data from the server, so
destroy()wouldn't work. It's useful for me & very interesting though, thanks!The resulting JS code for reference:
const net = require('net'); const socket = new net.Socket(); socket.connect(8000, "127.0.0.1", () => { socket.write( `CONNECT example.com:80 HTTP/1.1 Host: example.com GET / HTTP/1.1 Host: example.com ` ); // If this is synchronous, it doesn't work // If it waits for write(), but no longer, it 50% works // Scheduling it immediately seems fairly reliable setTimeout(() => socket.destroy(), 0); });
- addedfeature requestIssues requesting new Node.js features.Issues requesting new Node.js features.
on Apr 26, 2019 Get rid of the setTimeout, its racy because
setTimeout(..., 0)actually meanssetTimeout(..., 1)(check the docs), and there is no causal relationship between 1 ms of time passing and the data exchange with the server. Trysocket.write('blah', () => socket.destroy());.Btw, you describe this as hacky, but I'm not sure that is fair. Many things can cause an RST, but most of them are TCP protocol violations, and faking a bug in the OS TCP stack is probably not something node tests need to do.
The most common cause of an RST is exactly what you are doing: a socket is read-closed, but the peer continues to send data.
Get rid of the setTimeout
Sadly I tested
socket.write('blah', () => socket.destroy())before, and it's significantly less reliable - works a little over half the time, talking to a local server. Just manual tests, nothing rigorous, but I'm yet to see thesetTimeoutapproach fail at all.faking a bug in the OS TCP stack is probably not something node tests need to do.
I'm not sure about the reasons, but I'm seeing a fair few unexpected RST packets from end-user clients, in real-world HTTP traffic. My product is an HTTP debugger (httptoolkit.tech) - effectively a local HTTP proxy for developers - this is coming from my end-user error reporting, with RST packets being sent by whatever people are connecting to that. For me it'd be really useful to able to precisely reproduce that behaviour in my tests.
Any client that does
write(socket, 'GET ...'); exit();will cause RSTs when the server replies (exit implicitly closes all open sockets), you could be seeing variations of that.See libuv/libuv#1991 (comment), the main problem is the interaction between SO_LINGER and shutdown().
Since this suggestion,
uv_tcp_close_resetis now available in libuv to do exactly this, for similar reasons. Presumably this could now presumably be implemented relatively easily by exposing that as a method on sockets.I'd still find this useful. I'm in the same situation again right now of trying to test certain kinds of error reporting & handling with RST packets, and some cases are still not testable in node without a separate tool (Python).
@pimterry That's right. Pull request welcome, the places to look at are
src/tcp_wrap.ccandlib/net.js. Adding the method to the former exposes it onsocket._handlein the latter (but only when it's a wrapper around a TCP connection, of course.)I'm inclined to leave out a forwarding method on
tls.Socketfor now.I'd like to prepare PR, any suggestions on method name?
@kolontsov Just spitballing:
net.Socket.prototype.reset()?Reacted by Becky Conning and Vikas Gautam@bnoordhuis sounds great. ok.
Any progress on that one?
I've been investigating this for a while, although I'm a bit lost in the source code...
Will update if I make any progress
Any update on this issue?
This way works for node 16,
https://stackoverflow.com/questions/22836424/simulate-an-econnreset-error-on-a-node-js-net-socket-instance
but this will let the node process crash with unhandled exception.3 remaining items
Hi folks,
After some weeks of reading the code, I'm making some progress on this feature.Now I can reset a TCP socket in my Javascript code, using my own Node build.
To achieve it, I added a wrap function
TCPWrap::Resetforuv_tcp_close_resetin theTCPWrapClass.
I'm referencing theHandleWrap::Closecode to implement it.Also, I have some suggestions and questions to ask:
Socket.prototype.resetAndDestroycould be better?
Sinceuv_tcp_close_resetwill reset and close the handle.- If
Socketis not a TCP handle (For examplePIPE), do we throw an Error? Or do we do nothing?
I guess we have three options: a) do nothing b) call destroy c)throw Error - Are we going to emit the
closeevent?
I prefer 'yes'
- added a commit that references this issue
on May 15, 2022 #43112
just created a draft PR for it. Still have some test cases to add.Reacted by Szymon Marczak- added a commit that references this issue
on May 30, 2022 - added a commit that references this issue
on Jul 12, 2022 - added a commit that references this issue
on Jul 31, 2022 - added a commit that references this issue
on Oct 10, 2022 - added a commit that references this issue
on Mar 21, 2024
Is your feature request related to a problem? Please describe.
I'd like to forcibly reset a socket. Primarily for testing - I'm seeing unexpected RST packets in production, which is crashing my node HTTP proxy (my bug, that's fine), and I'd like to be able to write automated tests to ensure I've fixed correctly.
As far as I can tell it's only possible to cleanly close sockets with FIN, you can never intentionally RST.
Describe the solution you'd like
Something like
socket.reset()would be great for my specific case, or alternatively low-level controls (e.g. the ability to set socket options as in the Python code below) would be equally useful.Describe alternatives you've considered
For now, I've implemented this in Python instead. This Python 2.7.1 code is working for me:
Obviously I'd much prefer to test my Node server with JavaScript though, instead of having to bring in another language.