Test if a port on a remote system is reachable (without telnet)
In the old days, we used telnet to see if a port on a remote host was open: telnet hostname port would attempt to connect to any port on any host and give you access to the raw TCP stream. These days, the systems I work on do not have telnet installed (for security reasons), and all outbound connections to all hosts are blocked by default. Over time, it’s easy to lose track of which ports are open to which hosts. Is there another way to test if a port on a remote system is open – using a Linux system with a limited number of packages installed, and telnet is not available?
I was having this same issue. The answer by @Subhranath Chunder below helped. However, I then found out that installing Telnet was a small matter of running brew install telnet . So I expect Linux users can do the same with yum and apt-get .
When «all outbound connections to all hosts are blocked by default» there will be no way to perform such a test — you are offline
14 Answers 14
Bash has been able to access TCP and UDP ports for a while. From the man page:
/dev/tcp/host/port If host is a valid hostname or Internet address, and port is an integer port number or service name, bash attempts to open a TCP connection to the corresponding socket. /dev/udp/host/port If host is a valid hostname or Internet address, and port is an integer port number or service name, bash attempts to open a UDP connection to the corresponding socket.
So you could use something like this:
However on ports that were not open it timed out after 22 seconds (tried on Ubuntu 14.04 (Trusty Tahr) for a remote server). Interestingly, the timeout period is much shorter than the one for nc (see thnee’s answer).
@lornix, ok, but in this case I have to get the same result with use nc without -z option, but it still does not work: # nc -v -w5 127.0.0.1 18080 Connection to 127.0.0.1 18080 port [tcp/*] succeeded! # cat < /dev/tcp/127.0.0.1/18080 Just hangs without any result. Just want to understand when I can use "/dev/tcp/host/port" option
@Alexandr. actually, «hangs without any result» is pretty much expected behavior. cat is waiting for input. nc has extra smarts to enable it to sense no-data pending and stops trying. cat isn’t quite as smart. Try cat < /dev/tcp/localhost/22 , you should get your sshd header. Evidently, your process on port 18080 waits for something to come in, before sending anything. Port 22 (ssh) greets you with it’s version and whatnot. Try it out!
@lornix, thank you very much for explanation! Now the restriction is clear. I think using nc should be a preferred way to check ports.
This was incredibly helpful when working with a docker container that had nothing installed. Was able to quickly verify that the container had access to non-containerized DB via DNS. Example: cat < /dev/tcp/hostname/5432
Nice and verbose! From the man pages.
Single port:
This hanged when tried on Ubuntu 14.04 (Trusty Tahr) for a remote server (same LAN) for closed ports (it timed out after 127 seconds) — thus not very suitable in scripts. It did work though for a service that had a port open. Using option «-w2» could be the solution.
that’s great, but only if nc is actually installed 😛 the accepted answer via bash works almost everywhere, more GNU/Linux servers have bash than nc
Will output 0 if port 123 is open, and 1 if it’s closed.
This is a far more elegant and scriptable answer than my own. It is unfortunate for me that the security-conscious sysadmins who withheld telnet also withheld nc (though – strangely – not curl or wget ).
This hanged when tried on Ubuntu 14.04 (Trusty Tahr) for a remote server (same LAN) for closed ports (it timed out after about 127 seconds) — thus not very suitable in scripts. It did work though for a service that had a port open, returning 0. Using option «-w2» could be the solution.
The simplest method, without making use of another tool, such as socat , is as described in @lornix’s answer above. This is just to add an actual example of how one would make use of the psuedo-device /dev/tcp/. within Bash if you wanted to, say, test if another server had a given port accessible via the command line.
Examples
Say I have a host on my network named skinner .
$ (echo > /dev/tcp/skinner/22) >/dev/null 2>&1 \ && echo "It's up" || echo "It's down" It's up $ (echo > /dev/tcp/skinner/222) >/dev/null 2>&1 && \ echo "It's up" || echo "It's down" It's down
The reason you want to wrap the echo > /dev/. in parentheses like this, (echo > /dev/. ) is because if you don’t, then with tests of connections that are down, you’ll get these types of messages showing up.
$ (echo > /dev/tcp/skinner/223) && echo hi bash: connect: Connection refused bash: /dev/tcp/skinner/223: Connection refused
These can’t simply be redirected to /dev/null since they’re coming from the attempt to write out data to the device /dev/tcp . So we capture all that output within a sub-command, i.e. (. cmds. ) and redirect the output of the sub-command.
How to Check Remote Ports are Reachable Using ‘nc’ Command
A port is a logical entity which acts as a endpoint of communication associated with an application or process on an Linux operating system. It is useful to know which ports are open and running services on a target machine before using them.
We can easily list open ports in Linux on a local machine using the netstat or several other Linux commands such NMAP.
In this guide, we will show you how to determine if ports on a remote host are reachable/open using simple netcat (in short nc) command.
netcat (or nc in short) is a powerful and easy-to-use utility that can be employed for just about anything in Linux in relation to TCP, UDP, or UNIX-domain sockets.
# yum install nc [On CentOS/RHEL] # dnf install nc [On Fedora 22+] $ sudo apt-get install netcat [On Debian/Ubuntu]
We can use it to: open TCP connections, listen on arbitrary TCP and UDP ports, send UDP packets, do port scanning under both IPv4 and IPv6 and beyond.
Using netcat, you can check if a single or multiple or a range of open ports as follows. The command below will help us see if the port 22 is open on the host 192.168.56.10:
In the command above, the flag:
- -z – sets nc to simply scan for listening daemons, without actually sending any data to them.
- -v – enables verbose mode.
The next command will check if ports 80, 22 and 21 are open on the remote host 192.168.5.10 (we can use the hostname as well):
nc -zv 192.168.56.10 80 22 21
It is also possible to specify a range of ports to be scanned:’
For more examples and usage of netcat command, read through our articles as follows.
That’s all. In this article, we explained how to check if ports on a remote host are reachable/open using simple netcat commands. Make use of the comment section below to write back to us concerning about this tip.
Test if remote TCP port is open from a shell script
I’m looking for a quick and simple method for properly testing if a given TCP port is open on a remote server, from inside a Shell script. I’ve managed to do it with the telnet command, and it works fine when the port is opened, but it doesn’t seem to timeout when it’s not and just hangs there. Here’s a sample:
l_TELNET=`echo "quit" | telnet $SERVER $PORT | grep "Escape character is"` if [ "$?" -ne 0 ]; then echo "Connection to $SERVER on port $PORT failed" exit 1 else echo "Connection to $SERVER on port $PORT succeeded" exit 0 fi
I either need a better way, or a way to force telnet to timeout if it doesn’t connect in under 8 seconds for example, and return something I can catch in Shell (return code, or string in stdout). I know of the Perl method, which uses the IO::Socket::INET module and wrote a successful script that tests a port, but would rather like to avoid using Perl if possible. Note: This is what my server is running (where I need to run this from) SunOS 5.10 Generic_139556-08 i86pc i386 i86pc
The answer lied with Expect. We wrote a simple script that sends a telnet on the port we needed, with a timeout of 8 seconds. There’s plenty of examples to pick from too. We based ours off this post: unix.com/shell-programming-scripting/…
check_tcp from github.com/monitoring-plugins/monitoring-plugins can do this, including entering strings and checking for an expected answer.
18 Answers 18
As pointed by B. Rhodes, nc ( netcat ) will do the job. A more compact way to use it:
That way nc will only check if the port is open, exiting with 0 on success, 1 on failure.
For a quick interactive check (with a 5 seconds timeout):
FWIW, I have completely overhauled my answer with an example, separately applicable to both RHEL 6 and RHEL 7.
on Mac at least, you may need to add -G# to set a connection timeout separate from/in addition to the -w# timeout, which basically functions as a read timeout.
@jolestar You can manually upgrade Ncat on Centos 7 to get the -z option. You may want to consider: unix.stackexchange.com/questions/393762/…
It’s easy enough to do with the -z and -w TIMEOUT options to nc , but not all systems have nc installed. If you have a recent enough version of bash, this will work:
# Connection successful: $ timeout 1 bash -c 'cat < /dev/null >/dev/tcp/google.com/80' $ echo $? 0 # Connection failure prior to the timeout $ timeout 1 bash -c 'cat < /dev/null >/dev/tcp/sfsfdfdff.com/80' bash: sfsfdfdff.com: Name or service not known bash: /dev/tcp/sfsfdfdff.com/80: Invalid argument $ echo $? 1 # Connection not established by the timeout $ timeout 1 bash -c 'cat < /dev/null >/dev/tcp/google.com/81' $ echo $? 124
What’s happening here is that timeout will run the subcommand and kill it if it doesn’t exit within the specified timeout (1 second in the above example). In this case bash is the subcommand and uses its special /dev/tcp handling to try and open a connection to the server and port specified. If bash can open the connection within the timeout, cat will just close it immediately (since it’s reading from /dev/null ) and exit with a status code of 0 which will propagate through bash and then timeout . If bash gets a connection failure prior to the specified timeout, then bash will exit with an exit code of 1 which timeout will also return. And if bash isn’t able to establish a connection and the specified timeout expires, then timeout will kill bash and exit with a status of 124.
Use a different syntax for Git Bash:
Otherwise, Git Bash will return an error where none is expected:
$ timeout 1 bash -c 'cat < /dev/null >/dev/tcp/google.com/80' $ echo $? 124