Just to make sure we're on the same page (your question is ambiguous this way), asking to bind TCP on port 0 indicates a request to dynamically generate an unused port number. In other words, the port number you're actually listening on after that request is not zero. There's a comment about this in [linux kernel source]/net/ipv4/inet_connection_sock.c
on inet_csk_get_port()
:
/* Obtain a reference to a local port for the given sock,
* if snum is zero it means select any available local port.
*/
Which is a standard unix convention. There could be systems that will actually allow use of port 0, but that would be considered a bad practice. This behaviour is not officially specified by POSIX, IANA, or the TCP protocol, however.1 You may find this interesting.
That's why you cannot sensibly make a TCP connection to port zero. Presumably nc
is aware of this and informs you you're making a non-sensical request. If you try this in native code:
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = 0;
inet_aton("127.0.0.1", &addr.sin_addr);
if (connect(fd, (const struct sockaddr*)&addr, sizeof(addr)) == -1) {
fprintf(stderr,"%s", strerror(errno));
}
You get the same error you would trying to connect to any other unavailable port: ECONNREFUSED
, "Connection refused". So in reply to:
Where in the system is this handled? In the TCP stack of the OS kernel?
Probably not; it doesn't require special handling. I.e., if you can find a system that allows binding and listening on port 0, you could presumably connect to it.
1. But IANA does refer to it as "Reserved" (see here). Meaning, this port should not be used online. That makes it okay with regard to the dynamic assignment convention (since it won't actually be used). Stipulating that specifically as a purpose would probably be beyond the scope of IANA; in essence operating systems are free to do what they want with it, including nothing.
As for the official reference to the syntax, man bash and search for the section on Redirections.
to check connectivity on some ports for thousands of nodes from a Solaris box, where netcat or nc is not available
One way, using bash's network redirection feature, would be to echo some text into that host's port and see if it was successful. Bash returns true/false based on its ability to connect to that port on that host.
Sample code, showing an array of hosts, an array of ports, and attempts to connect to those ports over TCP:
#!/bin/bash
hosts=(127.0.0.1 127.0.0.2 127.0.0.3)
ports=(22 23 25 80)
for host in "${hosts[@]}"
do
for port in "${ports[@]}"
do
if echo "Hi from Bharat's scanner at $(uname -n)" 2>/dev/null > /dev/tcp/"$host"/"$port"
then
echo success at "$host":"$port"
else
echo failure at "$host":"$port"
fi
done
done
Since UDP is stateless, the return code from the test is not useful for scanning. You would have to use A.B's example to capture the output and see if it matches your expectations.
Best Answer
This snippet runs a new interactive instance of bash (
bash -i
), on a TCP connection to the specified port on the specified host which is created for the duration of the bash process. Standard output and standard error are sent through this connection (>& /dev/tcp/HOST/PORT
), and standard input is read through this connection (0>&1
— this should be0<&1
but0>&1
works too).There is no port forwarding going on. Obviously, a TCP server of some kind has to be listening and accepting connections on that HOST:PORT, and the firewall has to let the connection through.