Easyway to test two way network connectivity - bash

I have a situation where I'd need to check network connectivity from client A to 40 hosts and vice versa. As logging on to each client takes time. I was wondering is there an easy way to achieve this, Please show some light.
Ex:
Destination 1:
Source to destination: OK
Destination to Source: KO
Source:
10.1.2.3
Destination:
10.2.2.2
10.3.3.3
10.4.4.4
10.5.5.5
Port: 8080
Can anyone help which module should I be using? Please.

This should work but I did not test it. Let me know if it helps you.
EDIT : Im editing since I realize you needed a "viceversa" way too. so here it is, assuming you have ssh keys between your main server and the 40 hosts you are trying to test. And as noted on the comments this will work in Bash.
#!/bin/bash
port=8080
viceversaIp="10.1.2.3"
while read line
do
result=$( echo > /dev/tcp/$line/$port )
if [ -z "$result" ]
then
echo "Server : $line ; Port : $port ; The port is closed!!"
else
echo "Server : $line ; Port : $port ; The port is open!!"
fi
result=""
viceversa_result=$( ssh -n $line " echo > /dev/tcp/$viceversaIp/$port " | tail -1 )
if [ -z "$viceversa_result" ]
then
echo "Server $line can reach $viceversaIp at port $port "
else
echo "Server $line can NOT reach $viceversaIp at port $port "
fi
viceversa_result=""
done <( cat ips.txt )
Regards!

This is a oneliner using netcat nc:
cat hosts.txt| xargs -n 1 sh -c 'nc -G1 -w1 -z $1 8080' argv0
In where the file hosts.txt contains an IP/domain per line.
if you have custom port per IP you could follow this format:
# IP PORT
10.10.0.1 8080
10.10.0.2 80
And do:
cat hosts.txt| xargs -n 2 sh -c 'nc -G1 -w1 -z $1 $2' argv0
netcat is connecting via TPC which connection is bidirectional (three-way handshake) so maybe satisfy your requirement of testing in "two way"
The option -G and -w are for timeouts:
-G conntimeout TCP connection timeout in seconds
-w If a connection and stdin are idle for more than timeout sec-
onds, then the connection is silently closed.

Related

Bash script with netcat operations on different server and port

I am a bit lost. I have created a script which starts by retrieving data from a CSV file. Each line contains an IP address and a few ports to test. The goal is to verify that it is possible to connect to each server (under the given IP) on specifics ports. In order to verify, the following code is used:
nc -w 3 -v $ipValeur >> retour.txt 2>&1
Nevertheless, it doesn't work and it returns Connection Timed out. It is strange. In fact, if I launch a telnet command from a terminal, it works. Nevertheless, the goal is to check if a server can be connected to a lot of others. So, if telnet is used, it will be very long (one or two days ?)...
So, I am looking for a way which permits to automatically verify the access from one server to thirty others on a few ports. You can find the code which is actually used at How to continue next iteration when an error occurs in Bash.
Thank you for your help.
Solution
#!/bin/bash
INPUT_FILE=$1
while IFS='' read -r line || [ -n "$line" ]; do
IFS=';' read -ra cvsline <<<${line}
HOSTNAME=${cvsline[0]}
ports=("${cvsline[#]:1}")
for port in ${ports[*]}; do
echo -n "Verification ${HOSTNAME}:${port}..."
echo 'QUIT' | nc -w 3 -v "${HOSTNAME}" "${port}" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "OK"
else
echo "KO"
fi
done
done < $INPUT_FILE
Vinz
The answer may be, that in command: nc -w 3 -v $ipValeur >> retour.txt 2>&1 you not passed port number, and was used default one all the times
I not really able to understand your source code, so i have written my own based on description:
#!/bin/bash
INPUT_FILE=$1
while IFS='' read -r line || [ -n "$line" ]; do
IFS=';' read -ra cvsline <<<${line}
HOSTNAME=${cvsline[0]}
ports=("${cvsline[#]:1}")
for port in ${ports[*]}; do
echo -n "Cheking ${HOSTNAME}:${port}..."
nc -zw 3 "${HOSTNAME}" "${port}" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "connected"
else
echo "not connected"
fi
done
done < $INPUT_FILE
Usage:
./script hostlist.cvs
Where hostlist.cvs:
127.0.0.1;80;90;100;
127.0.0.2;80;88;21;
10.255.0.1;80;443;
And output sample:
$ ./test.sh /tmp/1
Cheking 127.0.0.1:80...not connected
Cheking 127.0.0.1:90...not connected
Cheking 127.0.0.1:100...not connected
Cheking 127.0.0.2:80...not connected
Cheking 127.0.0.2:88...not connected
Cheking 127.0.0.2:21...not connected
Cheking 10.255.0.1:80...connected
Cheking 10.255.0.1:443...not connected

Bash script that accepts TCP connection, when a client connection occurs, send the time of day as a response to the client

I'm not going to lie this is an homework assignment, but I've been googling constantly to try to get some idea on how the heck to approach this particular question.
"Create a script named lab6s6 that accepts TCP connections. When a client connection
occurs, send the time of day as a response to client. You may choose any port number as
the listening port, and don’t forget to close your connections."
I'm running the latest fedora OS on my virtualbox
So far after doing some research I've come across this particular piece of code
$ exec {file-descriptor}<>/dev/{protocol}/{host}/{port}
What i've come up with after doing some research would be
exec 3<>/dev/TCP/127.0.0.1/8000
So from my general understanding the file descriptor tends to always be set to 3 (is this because of the stdin, stdout, stderr, what is the purpose of this?) also the "<>" which represents reading and writing, and the directory is a way to actually use those protocols. and lastly, for my ip I read somewhere that I shouldnt be using the loopback that this wouldn't work but I'll be honest I was a bit clueless while reading the article, and for the port I never really understood that, is it like the higher the number the more available your signal is?
and another side question, do I need to install any other type of software to even accomplish something like this? If anyone could clarify if I'm basically opening up like a phone line on my computer to be able to talk to other computers at are on my LAN, is that even possible?
I'm not asking for direct answers, but if someone could nudge me in the right direction I would appreciate it greatly!
Thanks again!
I have prepared for you two scripts: client and server
after giving them the execution right: chmod u+x script_name you can run them in any order (client -> server or server -> client)
bash_server.sh
#!/usr/bin/env bash
#define port on which the server will listen
#and the output file that will be used to store the client port to send an answer
readonly PORT_LISTEN=22222;
readonly SERVER_FILE=server_file_tmp.out;
echo "Removing the server temporary file: ${SERVER_FILE}";
rm -f "${SERVER_FILE}";
#will open/bind/listen on PORT_LISTEN and whenever some information is received
#it will write it in the SERVER FILE
echo "Starting the server on port: ${PORT_LISTEN} with configuration file: ${SERVER_FILE}";
nc -k -l "${PORT_LISTEN}" | tee "${SERVER_FILE}" &
echo "Waiting for connection..."
#active listening to entry connection
while true;
do
#get always information about the external connection trying to connect to our open port
tmpNetworkString=$(lsof -i:"${PORT_LISTEN}" | grep "localhost:${PORT_LISTEN} (ESTABLISHED)" | awk '{print $9}');
echo -n "${tmpNetworkString}";
if [ -s "${SERVER_FILE}" ] && [ ! -z "${tmpNetworkString}" ]; then
answerPORT=$(cat "${SERVER_FILE}");
echo "Connection received on port ${PORT_LISTEN}...";
incomingIP=$(echo $tmpNetworkString | cut -d':' -f1);
incomingPort=$(echo $tmpNetworkString | cut -d'-' -f1 | cut -d':' -f2);
echo ">>Incoming traffic IP: ${incomingIP}";
echo ">>Incoming traffic Port: ${incomingPort}";
echo "Answering on IP: ${incomingIP}, port: ${answerPORT}...";
#wait client port to be ready
nc -z "${incomingIP}" "${answerPORT}";
isOpen=$?;
while [ ! "${isOpen}" -eq 0 ];
do
nc -z "${incomingIP}" "${answerPORT}";
isOpen=$?;
done
echo $(date) | nc -q 2 "${incomingIP}" "${answerPORT}";
echo "Closing the server, port: ${PORT_LISTEN}";
fuser -k -n tcp "${PORT_LISTEN}";
echo "Removing the server temporary file: ${SERVER_FILE}";
rm -f "${SERVER_FILE}";
exit 0;
fi
done
bash_client.sh
#!/usr/bin/env bash
#define port on which the client will listen
#and the output file that will be used to store the answer from the server
readonly PORT_LISTEN=33333;
readonly CLIENT_FILE=client_file_tmp.out;
readonly SERVER_PORT=22222;
readonly SERVER_IP=localhost
echo "Removing the client temporary file: ${CLIENT_FILE}";
rm -f "${CLIENT_FILE}";
#will open/bind/listen on PORT_LISTEN and whenever some information is received
#it will write it in the CLIENT FILE
echo "Starting the server on port: ${PORT_LISTEN} with configuration file: ${CLIENT_FILE}";
nc -k -l "${PORT_LISTEN}" > "${CLIENT_FILE}" &
echo "Connecting to the server: ${SERVER_IP}, on port: ${SERVER_PORT} and waiting for answer";
#sending port information for answer:
#wait client port to be ready
nc -z "${SERVER_IP}" "${SERVER_PORT}";
isOpen=$?;
while [ ! "${isOpen}" -eq 0 ];
do
nc -z "${SERVER_IP}" "${SERVER_PORT}";
isOpen=$?;
done
echo "${PORT_LISTEN}" | nc -q 2 "${SERVER_IP}" "${SERVER_PORT}";
while true;
do
if [ -s "${CLIENT_FILE}" ]; then
echo "Answer received from server...";
echo "##############################";
echo "##############################";
cat "${CLIENT_FILE}";
echo "##############################";
echo "##############################";
#sleep 10;
echo "Closing the open port of the client, port: ${PORT_LISTEN}";
fuser -k -n tcp "${PORT_LISTEN}";
echo "Removing the answer file: ${CLIENT_FILE}";
rm -f "${CLIENT_FILE}";
exit 0;
fi
done

Shell Script - telnet multiple hosts:ports

I'm not an expert in shell script by any means.
I got the structure idea from another post (Bash script telnet to test multiple addresses and ports)
My need is to verify LAN connections between specific hosts and ports via telnet.
The reason for using telnet is the fact that both the LAN and machines are heavily secure and I don't have access to netcat, nmap or /dev/tcp. I'm also no where near comfortable with Python or Pearl to try that route... ( I know silly me, I'll get there though :P ).
The following code works, however for reasons beyond my understanding the while loop iterates only once and no more... :( .
Note: it is important for me to know if the connection failed due to timeout or was refused (port is closed at the endpoint).
Can anyone help me in 1) fixing it and 2) understanding why?
FYI: For anyone else that might have a similar need here's the fully operational updated code for the script.
In this case connection refused is being handled as a success (testing firewall rules) which can be changed to failed depending on necessities.
#!/bin/bash
path=`pwd`;
touch $path/test_telnet.out || exit;
touch $path/success.log || exit;
touch $path/failed.log || exit;
echo "10.192.168.1 1200
10.10.10.2 80
10.220.2.8 6090
10.220.2.9 6090" | ( while read host port; do
telnet $host $port </dev/null > $path/test_telnet.out 2>&1 & sleep 1; kill $!;
if grep Connected $path/test_telnet.out >/dev/null;
then
echo # $(date +"%b %d %H:%M %Y") $host:$port [ OPEN ] | tee -a $path/success_log.txt;
elif grep refused $path/telnet_test.txt >/dev/null; then
echo # $(date +"%b %d %H:%M %Y") $host:$port [ REFUSED ] | tee -a $path/success_log.txt;
else
echo # $(date +"%b %d %H:%M %Y") $host:$port [ TIMEOUT ] | tee -a $path/failed_log.txt;
fi;
cp /dev/null $path/test_telnet.out;
done
) 2>/dev/null #avoid bash messages
As Etan commented, telnet is eating the rest of your input. The fix is to redirect the input for telnet.
Change this:
telnet $host $port > ~/test_con/telnet_test.txt
to this:
telnet $host $port </dev/null > ~/test_con/telnet_test.txt
I have added a shell script file and just run this. This script get servers and ports from below list.
for i in {10.21.xxx.yyy,10.21.xxx.yyy,10.23.xxx.yyy};
do
for j in {5501,5502,5503,5504,7701,7702,7703,7704,5551,5552,5553,7771,7772,7773};
do
(echo > /dev/tcp/${i}/${j}) > /dev/null 2>&1 && echo "${i}:${j} :: it's getting connected" || echo "${i}:${j} :: it's not connecting"
done
done

Issue with netcat timeout

Why does the following netcat command not time out if the attempt to connect takes longer than 3 seconds (ie: when the port isn't open)? I assumed that the -w flag would be what I needed. OS is OSX 10.9.
nc -v -z -w 3 127.0.0.1 5050
Assuming that worked, I planned to implement like this (unsure if this will work, total bash noob)
nc -v -z -w 3 127.0.0.1 5050 | /dev/null && echo "Online" || echo "Offline"
You need to redirect to /dev/null, not pipe to it. Try the following:
nc -v -z -w 3 127.0.0.1 5050 &> /dev/null && echo "Online" || echo "Offline"
On my machine, port 5050 isn't open, and I get the following:
$ nc -v -z -w 3 localhost 5050 &> /dev/null && echo "Online" || echo "Offline"
Offline
Since Mac OS X 10.8.x, nc has used the -G option to set the timeout for initiating a connection. This is separate from the -w option, which sets the timeout for a connection that has been made but has gone idle.
If you are trying to use nc for port scanning, i.e. nc -v -z 10.0.1.1 1-1023, it will spend over a minute trying to connect to each non-responding port unless you add a -G timeout value:
nc -v -z -G 1 10.0.1.1 1-1023
That's one second per port scanned — much more useful.
Nc: nc is usually installed already , however on some systems such as Mac OS X, the command hangs on unreachable systems without the -G option. If that does not work use the Workaround.
nc -v -z -w 3 127.0.0.1 22 &> /dev/null && echo "Online" || echo "Offline"
Mac OSX:
nc -z -G 3 127.0.0.1 22 &> /dev/null && echo "Online" || echo "Offline"
Alternative workaround option:
bash -c '(sleep 3; kill $$) & exec nc -z 127.0.0.1 22' &> /dev/null
echo $?
0
bash -c '(sleep 3; kill $$) & exec nc -z 1.2.3.4 22' &> /dev/null
echo $?
143
(examples illustrate connecting to port 22 ssh over a good and bad host example, use the $? to determine if it reached the host with the sleep time of 3 seconds)
Alternatively For Mac Users (mainly) etc, you can use the command in the script like so :
# -- use NMAP, if not avail. go with nc --
if command -v nmap | grep -iq nmap ; then
nmap ${ip} -PN -p ${ssh_port} | grep -iq "open"
res=$?
elif command -v nc | grep -iq nc ; then
# -- run command if fails to complete in 3 secs assume host unreachable --
( nc -z ${ip} ${ssh_port} ) & pid=$!
( sleep 3 && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
pkill -HUP -P $watcher
wait $watcher
# -- command finished (we have connection) --
res=0
else
# -- command failed (no connection) --
res=1
fi
else
echo "Error: You must have NC or NMAP installed"
fi
if [[ ${res} -lt 1 ]] ;then
success=1
echo "testing => $ip SUCCESS connection over port ${ssh_port}"
break;
else
echo "testing => $ip FAILED connection over port ${ssh_port}"
fi
There is an old bug report about this on debian (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=97583) and still having the same behavior in Debian GNU/Linux 7.7 (wheezy)
I found a "solution" to this: installing the openbsd version of nc:
apt-get install netcat-openbsd
On Mac OS X (10.14.6) the -w 3 parameter is somehow ignored.
The workaround I found is: timeout 3 nc -vz 10.18.50.134 23

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
As pointed by B. Rhodes, nc (netcat) will do the job. A more compact way to use it:
nc -z <host> <port>
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):
nc -z -v -w5 <host> <port>
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.
TOC:
Using bash and timeout
Command
Examples
Using nc
Command
RHEL 6 (nc-1.84)
Installation
Examples
RHEL 7 (nmap-ncat-6.40)
Installation
Examples
Remarks
Using bash and timeout:
Note that timeout should be present with RHEL 6+, or is alternatively found in GNU coreutils 8.22. On MacOS, install it using brew install coreutils and use it as gtimeout.
Command:
$ timeout $TIMEOUT_SECONDS bash -c "</dev/tcp/${HOST}/${PORT}"; echo $?
If parametrizing the host and port, be sure to specify them as ${HOST} and ${PORT} as is above. Do not specify them merely as $HOST and $PORT, i.e. without the braces; it won't work in this case.
Example:
Success:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/80"; echo $?
0
Failure:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
124
If you must preserve the exit status of bash,
$ timeout --preserve-status 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
143
Using nc:
Note that a backward incompatible version of nc gets installed on RHEL 7.
Command:
Note that the command below is unique in that it is identical for both RHEL 6 and 7. It's just the installation and output that are different.
$ nc -w $TIMEOUT_SECONDS -v $HOST $PORT </dev/null; echo $?
RHEL 6 (nc-1.84):
Installation:
$ sudo yum install nc
Examples:
Success:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
Failure:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
nc: connect to canyouseeme.org port 81 (tcp) timed out: Operation now in progress
1
If the hostname maps to multiple IPs, the above failing command will cycle through many or all of them. For example:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
1
RHEL 7 (nmap-ncat-6.40):
Installation:
$ sudo yum install nmap-ncat
Examples:
Success:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connected to 52.202.215.126:80.
Ncat: 0 bytes sent, 0 bytes received in 0.22 seconds.
0
Failure:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1
If the hostname maps to multiple IPs, the above failing command will cycle through many or all of them. For example:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection to 104.43.195.251 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.100.122.175 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.96.52.53 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 191.239.213.197 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection timed out.
1
Remarks:
The -v (--verbose) argument and the echo $? command are of course for illustration only.
With netcat you can check whether a port is open like this:
nc my.example.com 80 < /dev/null
The return value of nc will be success if the TCP port was opened, and failure (typically the return code 1) if it could not make the TCP connection.
Some versions of nc will hang when you try this, because they do not close the sending half of their socket even after receiving the end-of-file from /dev/null. On my own Ubuntu laptop (18.04), the netcat-openbsd version of netcat that I have installed offers a workaround: the -N option is necessary to get an immediate result:
nc -N my.example.com 80 < /dev/null
In Bash using pseudo-device files for TCP/UDP connections is straight forward. Here is the script:
#!/usr/bin/env bash
SERVER=example.com
PORT=80
</dev/tcp/$SERVER/$PORT
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
Testing:
$ ./test.sh
Connection to example.com on port 80 succeeded
Here is one-liner (Bash syntax):
</dev/tcp/localhost/11211 && echo Port open. || echo Port closed.
Note that some servers can be firewall protected from SYN flood attacks, so you may experience a TCP connection timeout (~75secs). To workaround the timeout issue, try:
timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.
See: How to decrease TCP connect() system call timeout?
I needed a more flexible solution for working on multiple git repositories so I wrote the following sh code based on 1 and 2. You can use your server address instead of gitlab.com and your port in replace of 22.
SERVER=gitlab.com
PORT=22
nc -z -v -w5 $SERVER $PORT
result1=$?
#Do whatever you want
if [ "$result1" != 0 ]; then
echo 'port 22 is closed'
else
echo 'port 22 is open'
fi
check ports using bash
Example
$ ./test_port_bash.sh 192.168.7.7 22
the port 22 is open
Code
HOST=$1
PORT=$2
exec 3> /dev/tcp/${HOST}/${PORT}
if [ $? -eq 0 ];then echo "the port $2 is open";else echo "the port $2 is closed";fi
If you're using ksh or bash they both support IO redirection to/from a socket using the /dev/tcp/IP/PORT construct. In this Korn shell example I am redirecting no-op's (:) std-in from a socket:
W$ python -m SimpleHTTPServer &
[1] 16833
Serving HTTP on 0.0.0.0 port 8000 ...
W$ : </dev/tcp/127.0.0.1/8000
The shell prints an error if the socket is not open:
W$ : </dev/tcp/127.0.0.1/8001
ksh: /dev/tcp/127.0.0.1/8001: cannot open [Connection refused]
You can therefore use this as the test in an if condition:
SERVER=127.0.0.1 PORT=8000
if (: < /dev/tcp/$SERVER/$PORT) 2>/dev/null
then
print succeeded
else
print failed
fi
The no-op is in a subshell so I can throw std-err away if the std-in redirection fails.
I often use /dev/tcp for checking the availability of a resource over HTTP:
W$ print arghhh > grr.html
W$ python -m SimpleHTTPServer &
[1] 16863
Serving HTTP on 0.0.0.0 port 8000 ...
W$ (print -u9 'GET /grr.html HTTP/1.0\n';cat <&9) 9<>/dev/tcp/127.0.0.1/8000
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.6.1
Date: Thu, 14 Feb 2013 12:56:29 GMT
Content-type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Feb 2013 12:55:44 GMT
arghhh
W$
This one-liner opens file descriptor 9 for reading from and writing to the socket, prints the HTTP GET to the socket and uses cat to read from the socket.
While an old question, I've just dealt with a variant of it, but none of the solutions here were applicable, so I found another, and am adding it for posterity. Yes, I know the OP said they were aware of this option and it didn't suit them, but for anyone following afterwards it might prove useful.
In my case, I want to test for the availability of a local apt-cacher-ng service from a docker build. That means absolutely nothing can be installed prior to the test. No nc, nmap, expect, telnet or python. perl however is present, along with the core libraries, so I used this:
perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))'
In some cases where tools like curl, telnet, nc o nmap are unavailable you still have a chance with wget
if [[ $(wget -q -t 1 --spider --dns-timeout 3 --connect-timeout 10 host:port; echo $?) -eq 0 ]]; then echo "OK"; else echo "FAIL"; fi
If you want to use nc but don't have a version that support -z, try using --send-only:
nc --send-only <IP> <PORT> </dev/null
and with timeout:
nc -w 1 --send-only <IP> <PORT> </dev/null
and without DNS lookup if it's an IP:
nc -n -w 1 --send-only <IP> <PORT> </dev/null
It returns the codes as the -z based on if it can connect or not.
Building on the most highly voted answer, here is a function to wait for two ports to be open, with a timeout as well. Note the two ports that mus be open, 8890 and 1111, as well as the max_attempts (1 per second).
function wait_for_server_to_boot()
{
echo "Waiting for server to boot up..."
attempts=0
max_attempts=30
while ( nc 127.0.0.1 8890 < /dev/null || nc 127.0.0.1 1111 < /dev/null ) && [[ $attempts < $max_attempts ]] ; do
attempts=$((attempts+1))
sleep 1;
echo "waiting... (${attempts}/${max_attempts})"
done
}
I needed short script which was run in cron and hasn't output. I solve my trouble using nmap
open=`nmap -p $PORT $SERVER | grep "$PORT" | grep open`
if [ -z "$open" ]; then
echo "Connection to $SERVER on port $PORT failed"
exit 1
else
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
fi
To run it You should install nmap because it is not default installed package.
I'm guessing that it's too late for an answer, and this might not be a good one, but here you go...
What about putting it inside of a while loop with a timer on it of some sort. I'm more of a Perl guy than Solaris, but depending on the shell you're using, you should be able to do something like:
TIME = 'date +%s' + 15
while TIME != `date +%s'
do whatever
And then just add a flag in the while loop, so that if it times out before completing, you can cite the timeout as reason for failure.
I suspect that the telnet has a timeout switch as well, but just off the top of my head, I think the above will work.
This uses telnet behind the scenes, and seems to work fine on mac/linux. It doesn't use netcat because of the differences between the versions on linux/mac, and this works with a default mac install.
Example:
$ is_port_open.sh 80 google.com
OPEN
$ is_port_open.sh 8080 google.com
CLOSED
is_port_open.sh
PORT=$1
HOST=$2
TIMEOUT_IN_SEC=${3:-1}
VALUE_IF_OPEN=${4:-"OPEN"}
VALUE_IF_CLOSED=${5:-"CLOSED"}
function eztern()
{
if [ "$1" == "$2" ]
then
echo $3
else
echo $4
fi
}
# cross platform timeout util to support mac mostly
# https://gist.github.com/jaytaylor/6527607
function eztimeout() { perl -e 'alarm shift; exec #ARGV' "$#"; }
function testPort()
{
OPTS=""
# find out if port is open using telnet
# by saving telnet output to temporary file
# and looking for "Escape character" response
# from telnet
FILENAME="/tmp/__port_check_$(uuidgen)"
RESULT=$(eztimeout $TIMEOUT_IN_SEC telnet $HOST $PORT &> $FILENAME; cat $FILENAME | tail -n1)
rm -f $FILENAME;
SUCCESS=$(eztern "$RESULT" "Escape character is '^]'." "$VALUE_IF_OPEN" "$VALUE_IF_CLOSED")
echo "$SUCCESS"
}
testPort
My machine does not support nc or /dev/tcp/$hostname/$port but timeout, so I came back to telnet as follows:
if echo "quit" | timeout 2 telnet $SERVER $PORT 2>&1 | grep -q 'Connected to'; then
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
else
echo "Connection to $SERVER on port $PORT failed"
exit 1
fi
nmap-ncat to test for local port that is not already in use
availabletobindon() {
port="$1"
nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q 'Idle timeout expired'
return "$?"
}

Resources