1. Overview

In this tutorial, we’ll look at ways to check if a network port is open for connections in Linux. We’ll take a closer look at some of the Bash utilities that can be used for this purpose. We’ll also benchmark the performance of the methods offered to achieve a time-efficient solution.

2. Using the netstat Command

The netstat command-line utility in Linux prints the network statistics for a number of network protocols and interfaces. We can use it to investigate network sockets and test the status of network ports in Linux. First, let’s verify the default output of the netstat command:

$ netstat | head
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 localhost:34702         localhost:8684          ESTABLISHED
tcp        0      0 localhost:5747          localhost:55488         ESTABLISHED
tcp        0      0 localhost:5161          localhost:44858         ESTABLISHED
tcp        0      0 localhost:8580          localhost:42432         ESTABLISHED
tcp        0      0 localhost:54090         localhost:3852          ESTABLISHED
tcp        0      0 localhost:8186          localhost:52896         ESTABLISHED
tcp        0      0 localhost:7367          localhost:43282         ESTABLISHED
tcp        0      0 localhost:4441          localhost:35762         ESTABLISHED
$

In this output, under the “Local Address” and “Foreign Address” columns, the port number is listed after the colon, “*:*“. The state of the network address (a combination of IP and port) is listed in the “State” column.

Let’s modify our command to check the status of a specific port:

$ netstat -nap | grep ":8001"
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN      19135/nc
tcp        0      0 127.0.0.1:8001          127.0.0.1:55368         ESTABLISHED 19135/nc
tcp        0      0 127.0.0.1:55368         127.0.0.1:8001          ESTABLISHED 19138/nc

Here, we’re checking the status of port “8001” using the grep command.

Note that we’re using the -n option to force it to print numerical addresses rather than trying to determine hostnames. The –a option allows us to print all of the listening sockets as well as the non-listening sockets. The -p option is used to print the PID of the process to which this socket belongs.

When a port is in LISTEN mode, it’s open for a connection. Therefore, let’s grep for LISTEN. We’ll also take a look at the execution time of the command using the time command:

$ time (netstat -nap | grep ":8001" | grep LISTEN)
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN      19135/nc

real    0m0.471s
user    0m0.199s
sys     0m0.302s

It took around half a second (0.471 sec) to verify the port status using the above command. Let’s tweak the command options a bit and re-evaluate the execution time:

$ time (netstat -nl | grep ":8001")
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN

real    0m0.072s
user    0m0.039s
sys     0m0.041s
$

Great! We’re able to bring down the execution time from 0.471 sec to 0.072 sec. Here, we’re using the -l option to list only the sockets in LISTEN mode. In the previous approach, netstat was listing all the sockets and we were using the grep command to filter the sockets in the LISTEN mode, which caused additional overhead.

We also eliminated the -p option from our command, since getting the PID of the corresponding process isn’t of much value here.

Let’s also verify a negative test case:

$ time (netstat -ne | grep ":10001" ; echo $?)
1

real    0m0.088s
user    0m0.079s
sys     0m0.022s
$

Here, as expected, netstat doesn’t give any output, and $? also holds a non-zero value since the port 10001 is not open for connections.

3. Using the ss Command

ss is a Linux utility for dumping socket statistics. Let’s take a look at its default output:

$ ss | head -10
Netid  State  Recv-Q  Send-Q    Local Address:Port                 Peer Address:Port                                        Process
tcp    ESTAB  0       0             127.0.0.1:34702                   127.0.0.1:8684
tcp    ESTAB  0       0             127.0.0.1:5747                    127.0.0.1:55488
tcp    ESTAB  0       0             127.0.0.1:5161                    127.0.0.1:44858
tcp    ESTAB  0       0             127.0.0.1:8580                    127.0.0.1:42432
tcp    ESTAB  0       0             127.0.0.1:54090                   127.0.0.1:3852
tcp    ESTAB  0       0             127.0.0.1:8186                    127.0.0.1:52896
tcp    ESTAB  0       0             127.0.0.1:7367                    127.0.0.1:43282
tcp    ESTAB  0       0             127.0.0.1:4441                    127.0.0.1:35762
tcp    ESTAB  0       0             127.0.0.1:7024                    127.0.0.1:57206

Note that the output of the utility is similar to the netstat output. Interestingly, the argument options of this utility are also similar to the netstat command. Let’s verify the output with the -l option to only list the sockets in LISTEN mode:

$ time (ss -nl | grep ":8001")
tcp   LISTEN 0      1                     0.0.0.0:8001             0.0.0.0:*

real    0m0.029s
user    0m0.039s
sys     0m0.000s

This utility is faster as compared to netstat. With this utility, we were able to further reduce the timing to 0.029 secs, as compared to the execution time of 0.072 secs.

4. Using the lsof Command

We can also use the lsof utility with the -i option to verify if the port is open for connection:

$ lsof -i:8001
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      19135 shubh    3u  IPv4 326527      0t0  TCP *:8001 (LISTEN)
nc      19135 shubh    4u  IPv4 326528      0t0  TCP localhost:8001->localhost:55368 (ESTABLISHED)
nc      19138 shubh    3u  IPv4 326555      0t0  TCP localhost:55368->localhost:8001 (ESTABLISHED)
$

Since we’re interested only in the LISTEN mode, let’s add a grep filter to our command:

$ time (lsof -i:8001 | grep "LISTEN")
nc      19135 shubh    3u  IPv4 326527      0t0  TCP *:8001 (LISTEN)

real    0m0.625s
user    0m0.133s
sys     0m0.492s
$

Notably, it takes more time than the netstat or the ss utility to display the relevant information. Here, we explicitly filtered the output using the grep command. Let’s also try to use the inbuilt flags -iTCP -sTCP:LISTEN to list the network files in LISTEN mode:

$ time (lsof -iTCP:8001 -sTCP:LISTEN)
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nc      19135 shubh    3u  IPv4 326527      0t0  TCP *:8001 (LISTEN)

real    0m0.496s
user    0m0.090s
sys     0m0.407s

Although we were able to bring down the execution time, it’s still considerably large as compared to the netstat and ss utilities.

5. Conclusion

In this article, we discussed ways to test if a port is open for connections in Linux.

We started by discussing the solution using the netstat tool. Additionally, we also explored the various netstat options to achieve a time-efficient solution. Then, we checked the solution using the ss command.

Finally, we presented techniques to test the port state using the lsof command. From our benchmarking, we can conclude that using the ss utility with the best-suited options can be an efficient way to test the port state in Linux.