NodeJS: disable SO_REUSEADDR or otherwise guarantee ECONNREFUSED - node.js

I'm trying to write a test in Node for the behavior of a networking client when it fails to make a TCP connection to a given server. Ideally, I'd like this to be as close as possible to the ECONNREFUSED case rather than some other error like DNS lookup failure, connection closed before receiving a response, etc.
A method I've tried is to make a server that listens binding port 0, then close the server, then connect to the port that was chosen when the server listened. This mostly works, but in CI when many tests are running in parallel sometimes some other test claims the port that was just bound and closed.
If this were C, I could just not set SO_REUSEADDR when binding the port, which should prevent the port from being quickly reused. But as far as I can tell, there's no way in Node to create a listening socket without SO_REUSEADDR.
Any thoughts about achieving this goal? Things I've thought about but not quite gotten to work include:
finding an npm package that lets me setsockopt to turn off SO_REUSEADDR (though I suspect that once the bind has happened it's too late?)
finding some other mechanism that isn't net.Server to bind to a port without SO_REUSEADDR
finding a different mechanism of tricking the client into thinking the connection was refused
(That said, some of the tests I'm writing involve "first the connection works and a later connection doesn't" so ideally something that lets me actually have a real server would be great --- ie my first idea somehow!)

Related

Node+supertest flakes with "Client network socket disconnected before secure TLS connection was established"

My node tests are randomly failing “Client network socket disconnected before secure TLS connection was established” and I’ve been debugging this for weeks. What’s going wrong? I’m using supertest
Tldr; Don’t rely on supertest to call listen and close on your server. Call server.listen before calling supertest.agent and handle calling close on your own.
Useful reading: https://gavv.github.io/articles/ephemeral-port-reuse/
The sockets created by net.Server.listen have the SO_REUSEADDR flag added to them. This means there can be multiple binds to the same port as along as they all add the SO_REUSEADDR flag.
Supertest by default will call server.listen(0) which creates and ipv6 socket on an ephemeral port using SO_REUSEADDR.
When you later use supertest to talk to your local server, it seems to prefer connecting over ipv4 instead of ipv6. And that’s ok at least on Macs because if dual-stacking, I.e. binding to “::” on ipv6 also listens to the same port on ipv4 if it isn’t taken by some other process.
However, every once in a while there can exist another process listening on the ipv4 version of the ephemeral port that’s being used by the test (SO_REUSEADDR allows this). The dual stacking logic from above will choose the ipv4 socket to a random process over the ipv6 socket that’s actually from your test.
There’s a million reasons why this shouldn’t work and the foreign process closes its end before the TLS handshake finishes, randomly giving you the error in the question. 

Thankfully, if your server is already listening when you call supertest.agent, supertest no longer tries to be smart about implicitly calling listen/close and you can use a fixed port outside of the ephemeral range to avoid all of this.

Can TCPv4 source and destination ports conflict with each other? Or do source and destination ports live in their own address spaces?

Let me be more specific about my question with an example: Let's say that I have a slew of little servers that all start up on different ports using TCPv4. These ports are going to be destination ports, of course. Let's further assume that these little servers don't just start up at boot time like a typical server, but rather they churn dynamically based on demand. They start up when needed, and may shut themselves down for a while, and then later start up again.
Now let's say that on this same computer, we also have lots of client processes making requests to server processes on other computers via TCPv4. When a client makes such a request, it is assigned a source port by the OS.
Let's say for the sake of this example that a client processes makes a web request to a RESTful server running on a different computer. Let's also say that the source port assigned by the OS to this request is port 7777.
For this example let's also say that while the above request is still occurring, one of our little servers wants to start up, and it wants to start up on destination port 7777.
My question is will this cause a conflict? I.e., will the server get an error because port 7777 is already in use? Or will everything be fine because these two different kinds of ports live in different address spaces that cannot conflict with each other?
One reason I'm worried about the potential for conflict here is that I've seen web pages that say that "ephemeral source port selection" is typically done in a port number range that begins at a relatively high number. Here is such a web page:
https://www.cymru.com/jtk/misc/ephemeralports.html
A natural assumption for why source ports would begin at high numbers, rather than just starting at 1, is to avoid conflict with the destination ports used by server processes. Though I haven't yet seen anything that explicitly comes out and says that this is the case.
P.S. There is, of course, a potential distinction between what the TCPv4 protocol spec has to say on this issue, and what OSes actually do. E.g., perhaps the protocol is agnostic, but OSes tend to only use a single address space? Or perhaps different OSes treat the issue differently?
Personally, I'm most interested at the moment in what Linux would do.
The TCP specification says that connections are identified by the tuple:
{local addr, local port, remote addr, remote port}
Based on this, there theoretically shouldn't be a conflict between a local port used in an existing connection and trying to bind that same port for a server to listen on, since the listening socket doesn't have a remote address/port (these are represented as wildcards in the spec).
However, most TCP implementations, including the Unix sockets API, are more strict than this. If the local port is already in use in any existing socket, you won't be able to bind it, you'll get the error EADDRINUSE. A special exception is made if the existing sockets are all in TIME_WAIT state and the new socket has the SO_REUSEADDR socket option; this is used to allow a server to restart while the sockets left over from a previous process are still waiting to time out.
For this reason, the port range is generally divided into ranges with different uses. When a socket doesn't bind a local port (either because it just called connect() without calling bind(), or by specifying IPPORT_ANY as the port in bind()), the port is chosen from the ephemeral range, which is usually very high numbered ports. Servers, on the other hand, are expected to bind to low-numbered ports. If network applications follow this convention, you should not run into conflicts.

linux refuse to open listening port from localhost

I have problem to open a listening port from localhost in a heavy loaded production system.
Sometimes some request to my port 44000 failed. During that time , I checked the telnet to the port with no response, I'm wonder to know the underneath operations takes there. Is the application that is listening to the port is failing to response to the request or it is some problem in kernel side or number of open files.
I would be thankful if someone could explain the underneath operation to opening a socket.
Let me clarify more. I have a java process which accept state full connection from 12 different server.requests are statefull SOAP message . this service is running for one year without this problem. Recently we are facing a problem that sometimes connection from source is not possible to my server in port 44000. As I checked During that time telnet to the service is not possible even from local server. But all other ports are responding good. they all are running with same user and number of allowed open files are much more bigger than this all (lsof | wc -l )
As I understood there is a mechanism in application that limits the number of connection from source to 450 concurrent session, And the problem will likely takes when I'm facing with maximum number of connection (but not all the time)
My application vendor doesn't accept that this problem is from his side and points to os / network / hardware configuration. To be honest I restarted the network service and the problem solved immediately for this special port. Any idea please???
Here's a quick overview of the steps needed to set up a server-side TCP socket in Linux:
socket() creates a new socket and allocates system resources to it (*)
bind() associates a socket with an address
listen() causes a bound socket to enter a listening state
accept() accepts a received incoming attempt, and creates a new socket for this connection. (*)
(It's explained quite clearly and in more detail on wikipedia).
(*): These operations allocate an entry in the file descriptor table and will fail if it's full. However, most applications fork and there shouldn't be issues unless the number of concurrent connections you are handling is in the thousands (see, the C10K problem).
If a call fails for this or any other reason, errno will be set to report the error condition (e.g., to EMFILE if the descriptor table is full). Most applications will report the error somewhere.
Back to your application, there are multiple reasons that could explain why it isn't responding. Without providing more information about what kind of service you are trying to set up, we can only guess. Try testing if you can telnet consistently, and see if the server is overburdened.
Cheers!
Your description leaves room for interpretation, but as we talked above, maybe your problem is that your terminated application is trying to re-use the same socket port, but it is still in TIME_WAIT state.
You can set your socket options to reuse the same address (and port) by this way:
int srv_sock;
int i = 1;
srv_sock = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
Basically, you are telling the OS that the same socket address & port combination can be re-used, without waiting the MSL (Maximum Segment Life) timeout. This timeout can be several minutes.
This does not permit to re-use the socket when it is still in use, it only applies to the TIME_WAIT state. Apparently there is some minor possibility of data coming from previous transactions, though. But, you can (and should anyway) program your application protocol to take care of unintelligible data.
More information for example here: http://www.unixguide.net/network/socketfaq/4.5.shtml
Start TCP server with sudo will solve or, in case, edit firewalls rules (if you are connecting in LAN).
Try to scan ports with nmap (like with TCP Sync Handshake), or similar, to see if the port is opened to any protocol (maybe network security trunkates pings ecc.. to don't show hosts up). If the port isn't responsive, check privileges used by the program, check firewalls rules maybe the port is on but you can't get to it.
Mh I mean.. you are talking about enterprise network so I'm supposing you are on a LAN environment so you are just trying to localhost but you need it to work on LAN.
Anyway if you just need to open localhost port check privileges and routing, try to "tracert" and see what happens and so on...
Oh and check if port is used by a higher privilege service or deamon.
Anyway I see now that this is a 2014 post, np gg nice coding byebye

Is there a way to switch the connection to another TCP server?

I have made my personal project using WebSocket.
I already know that WebSocket will not connect directly raw TCP Socket.
so, I have thought what if I connect, at first, to Web Server(NodeJS) and then switch to TCP server.
is It possible to switch connection to another server using NodeJS?
If so.
Please let me happy.. Thank you! have a nice day.
I would assume it might be both possible and straightforward to tunnel/proxy TCP traffic. The high level design would be:
Start up a web server with integrated websocket server (use socket.io, really)
When a client makes a websocket connection, create an upstream TCP connection to your target server
Then do full bidirectional piping of messages between the browser<->node socket and the node<->otherServer socket
Devil might be in the details. I haven't tried, but seems feasible.
There's a node project called ws-tcp-bridge as well as a python project that claim to do this already. Neither luke terribly mature, but they might just work or at least provide good reference material.

TCP Servers: Drop Connection, instead of resetting or responding?

Is it possible in Node.JS to "drop" a connection in such a way that
The client never receives a response (200, 404 or otherwise)
The client is never notified that the connection is terminated (never receives connection reset or end of stream)
The server's resources are released (the server should not attempt to maintain the connection in any way)
I am specifically asking about Node.JS HTTP Servers (which are really just complex TCP servers) on Solaris., but if there are cases on other OSes (Windows, Linux) or programming languages (C/C++, Java) that permit this, I am interested.
Why do I want this?
To annoy or slow down (possibly single-threaded) robots such as phpMyAdmin Probe.
I know this is not really something that matters, but these types of questions can better help me learn the boundaries of my programs.
I am aware that the client host is likely to re-transmit the packets of the connection since I am never sending reset.
These are not possible in a generic TCP stack (vs. your own custom TCP stack). The reasons are:
Closing a socket sends a RST
Even if you avoid sending a RST, the client continues to think the connection is open while the server has closed the connection. If the client sends any packet on this connection, the server is going to send a RST.
You may want to explore firewalling these robots and block / rate limit their IP addresses with something like iptables (linux) or the equivalent on solaris.
closing a connection should NOT send an RST. There is a 3 way tear down process.

Resources