10

I need a tool that tells me if a connection to a host is open or not -- no data to send or receive, just see if the connection is successful.

Today I use telnet.

$ telnet myhost myport
Trying 192.168.1.99...
Connected to myhost.
Escape character is '^]'.
^[^]
telnet> quit
Connection closed.

... but I need to have manual input there: the ^] and then also the quit.

I need to check several hosts, and that's too much for my simple method.

How can I do check for connectivity to multiple hosts more effectively? I would prefer to use a pre-existing tool.

2
  • 2
    Is this something you’re looking to run regularly on a schedule? If so, you may want to look into monit, which has built-in support for this type of thing as part of it’s support for monitoring remote hosts and would require zero scripting. Commented Dec 13, 2024 at 12:35
  • Can you expand on "I need to check several hosts" ? This feels like an XY problem without more background. Commented Dec 16, 2024 at 0:22

5 Answers 5

11

An existing tool that does this is nmap, a port scanner:

$ nmap -sT -p 22 192.168.1.1-5
Starting Nmap 7.95 ( https://nmap.org ) at 2024-12-12 22:52 Eastern Standard Time
Nmap scan report for 192.168.1.1
Host is up (0.0039s latency).

PORT   STATE SERVICE
22/tcp open  ssh
MAC Address: 74:AC:B9:12:E1:93 (Ubiquiti)

Nmap done: 5 IP addresses (1 host up) scanned in 1.47 seconds

-sT indicates a TCP portscan - it will SYN, SYN/ACK, ACK and then RST the connection.

-p 22 indicates port 22 will be tested.

It can scan individual IPs, IP ranges (as shown above), IP CIDR blocks, or any combination of these three.

It also supports grep-able (-oG) and XML (-oX) output, like such:

$ nmap -sT -p 22 -oG - 192.168.1.1,3,5
# Nmap 7.95 scan initiated Thu Dec 12 22:59:14 2024 as: nmap -sT -p 22 -oG - 192.168.1.1,3,5
Host: 192.168.1.1 ()    Status: Up
Host: 192.168.1.1 ()    Ports: 22/open/tcp//ssh///
# Nmap done at Thu Dec 12 22:59:16 2024 -- 3 IP addresses (1 host up) scanned in 1.45 seconds
8

Bash has native redirection (originating in KSH) that can check for open ports

host=192.168.1.99
if (<"/dev/tcp/${host}/22") >/dev/null 2>&1; then
  echo 'port is open'
else
  echo 'port is closed'
fi

or you can use nc(1):

host=192.168.1.99
if timeout 3 nc -z "$host" 22 2>/dev/null; then
  echo 'port is open'
else
  echo 'port is closed'
fi

You can also use telnet programmatically by piping it to something like grep:

host=192.168.1.99
if telnet "$host" 22 2>&1 | grep -q "Connected"; then
  echo 'port is open'
else
  echo 'port is closed'
fi
1
  • 2
    BTW, that feature is from ksh. It's not specific to bash. echo > "/dev/tcp/${host}/22" sends a newline character (see no data to send or receive in the OP's question) Commented Dec 15, 2024 at 13:19
4

With this scripts you can check if a host is response on a given port with:

bash's built-in /dev/tcp.

You can use ip address or domains(hostnames).

Script 1 Single Port

#!/bin/bash

HOST_NAME="127.1"
HOST_PORT="80"

if ( (exec 3<>/dev/tcp/${HOST_NAME}/${HOST_PORT}) 2> /dev/null); then
    echo -e "PORT: ${HOST_PORT} | ON"
else
    echo -e "PORT: ${HOST_PORT} | OFF"
fi

Script 2 Range of ports

#!/bin/bash

HOST_NAME="127.1"

for HOST_PORT in {1..1000}
do

if ( (exec 3<>/dev/tcp/${HOST_NAME}/${HOST_PORT}) 2> /dev/null); then
    echo -e "PORT: ${HOST_PORT} | ON"
else
    echo -e "PORT: ${HOST_PORT} | OFF"
fi
done

Script 3 Port 1-65535

#!/bin/bash

HOST_NAME="127.1"
declare -A PORT_ON

for HOST_PORT in {1..65535}
do
    if ( (exec 3<>/dev/tcp/${HOST_NAME}/${HOST_PORT}) 2> /dev/null); then
        PORT_ON[${HOST_PORT}]="ON"
    fi
done

for i in ${!PORT_ON[*]}
do
    echo -e "$i : ${PORT_ON[$i]}"
done

6
  • 1
    Note that Bash can be built with support for /dev/tcp disabled, usually for security reasons. Commented Dec 13, 2024 at 22:26
  • @Mark Yes, that's correct, but in most distros, that's not the case by default, but rather enabled ist the Standard. Commented Dec 13, 2024 at 22:32
  • @Mark do you mean alpine or minimal bash Like in busybox? Commented Dec 13, 2024 at 22:35
  • 1
    I mean Bash built using the --disable-net-redirections configuration parameter. I don't know which distros do this by default, but I do know that it's an option. Commented Dec 14, 2024 at 4:33
  • 1
    @Z0OM: Busybox's shell isn't bash at all, it's just ash which I think is mostly just POSIX sh, without any(?) bash extensions. Commented Dec 14, 2024 at 4:53
2

I believe the simplest way is with netcat's nc -vz <host>. For multiple hosts could be:

#!/bin/bash

hosts=("example.com" "anotherhost.com")
port=1234

for host in "${hosts[@]}"; do
  nc -vz "$host" "$port"
done

A more fancy way with one line:

echo -e "example.com\nanotherhost.com" | xargs -I {} nc -vz {} 80 # or any port

From manual:

-z      Only scan for listening daemons, without sending any data to them.
-v      Produce more verbose output.
1

Since the OP asks for a simple method, within a private subnet, and says nothing about detecting multiple ports - another good existing tool is fping.

fping is a program like ping which uses the Internet Control Message Protocol echo request to determine if a target host is responding. On most private subnets ICMP traffic will be allowed (if it isn't, then it's a sure bet that the firewalls or security appliances present will also block telnet and most other ports, leaving you with a very different question, more suited to port scanning prior to intrusion).

fping differs from ping in that you can specify any number of targets on the command-line, or specify a file containing the lists of targets to ping, or generate a range from a subnet on the command-line (the most common form that I generally use).

For example:

fping -a -r 0 -qs -g 192.168.1.99/24
  • -a : show targets that are alive
  • -r n : number of retries (default 3)
  • -q : quiet (don't show per-target/per-ping results). This limits output to live IP's only.
  • -s : print final stats, showing number of pings sent, number of live vs. dead IP's etc.
  • -g : generate target list (only if no -f specified). Specify the start and end IP in the target list, or supply a IP netmask "-g 192.168.1.0 192.168.1.25" or "-g 192.168.1.0/24"
  • "targets" : list of targets to check (if no -f specified)
  • --help for more options...

fping is installable from standard repositories for most distros.

apt-get install fping #Ubuntu: installed from the universe repo pool
zypper install fping #OpenSUSE
... etc.
2
  • 3
    With fping, you cannot scan ports as requested in the question, and if ICMP Echo Requests are blocked, as is standard on all servers and clients in our company, you also won’t receive any response. Commented Dec 13, 2024 at 14:11
  • The original question says nothing about multiple ports. It says multiple hosts. Also, the OP uses telnet on a private subnet. As such it's a good bet they are on a private network, where ping will be enabled 99.99% of the time. If ICMP echo is blocked, then it stands to reason that other ports would be too, and then it becomes a whole different question (eg. where NMAP or similar is now required, because you're trying to scan open ports and IP's). Commented Jan 17 at 12:07

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.