Test à partir du script shell si le port TCP distant est ouvert

je cherche une méthode simple et rapide pour tester correctement si un port TCP donné est ouvert sur un serveur distant, à partir d'un script Shell.

j'ai réussi à le faire avec la commande telnet, et ça marche très bien quand le port est ouvert, mais ça ne semble pas être le temps mort quand ce n'est pas le cas et ça reste là...

voici un échantillon:

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

soit j'ai besoin d'une meilleure façon, ou d'un moyen de forcer telnet à la timeout si elle ne se connecte pas en moins de 8 secondes par exemple, et renvoie quelque chose que je peux attraper dans Shell (code de retour, ou chaîne dans stdout).

je connais la méthode Perl, qui utilise le module IO::Socket::INET et écrit un script qui teste un port, mais qui préfère éviter D'utiliser Perl si possible.

Note: C'est ce que mon serveur exécute (à partir duquel je dois l'exécuter)

SunOS 5.10 Generic_139556-08 i86pc i386 i86pc

247
demandé sur A-B-B 2011-02-07 18:19:06

16 réponses

comme L'a souligné B. Rhodes, nc fera le travail. Une façon plus compacte de l'utiliser:

nc -z <host> <port>

de cette façon nc vérifiera seulement si le port est ouvert, sortant avec 0 sur le succès, 1 sur l'échec.

pour une vérification interactive rapide (avec un temps d'arrêt de 5 secondes):

nc -z -v -w5 <host> <port>
389
répondu Alessio Gaeta 2015-11-17 10:50:43

il est assez facile de faire avec le -z et -w TIMEOUT options à nc , mais pas tous les systèmes ont nc installé. Si vous avez une version assez récente de bash, cela fonctionnera:

# 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

ce qui se passe ici est que timeout lancera la sous-commande et la tuera si elle ne sort pas dans le délai spécifié (1 seconde dans l'exemple ci-dessus). Dans ce cas bash est la sous-commande et utilise son /dev/tcp manipulation pour essayer de l'ouvrir une connexion au serveur et le port spécifiés. Si bash peut ouvrir la connexion dans le délai imparti, cat va juste la fermer immédiatement (puisqu'elle lit de /dev/null ) et sortir avec un code d'état de 0 qui se propagera par bash et puis timeout . Si bash obtient une défaillance de connexion avant le délai spécifié, alors bash sortira avec un code de sortie de 1 qui timeout reviendra aussi. Et si bash n'est pas capable d'établir une connexion et que le délai spécifié expire, alors timeout tuera bash et sortira avec un statut de 124.

111
répondu onlynone 2016-10-26 15:36:01

table des matières:

  • utilisant bash et timeout
    • commande
    • exemples
  • utilisant nc
    • commande
    • RHEL 6 (nc-1.84)
      • Installation
      • exemples
    • RHEL 7 (nmap-ncat-6.40)
      • Installation
      • exemples
  • Remarques

utilisant bash et timeout :

notez que timeout doit être présent avec RHEL 6+, ou se trouve alternativement dans GNU coreutils 8.22. Sur MacOS, installez-le en utilisant brew install coreutils et utilisez-le comme gtimeout .

"1519290920 de la Commande" :
$ timeout $TIMEOUT_SECONDS bash -c "</dev/tcp/${HOST}/${PORT}"; echo $?

si vous paramétrez l'hôte et le port, assurez-vous de Les spécifier comme ${HOST} et ${PORT} comme ci-dessus. Ne les spécifiez pas simplement comme $HOST et $PORT , c.-à-d. sans les bretelles; cela ne fonctionnera pas dans ce cas.

exemple:

Succès:

$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/80"; echo $?
0

echec:

$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
124

si vous devez conserver le statut de sortie de bash ,

$ timeout --preserve-status 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
143

utilisant nc :

notez qu'une version en arrière incompatible de nc est installée sur RHEL 7.

commande:

notez que la commande ci-dessous est unique en ce qu'elle est identique pour les RHEL 6 et 7. C'est juste l'installation et la sortie qui sont différentes.

$ nc -w $TIMEOUT_SECONDS -v $HOST $PORT </dev/null; echo $?

RHEL 6 (nc-1.84):

Installation:

$ sudo yum install nc

exemples:

Succès:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
Échec:
$ 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

si le nom d'hôte correspond à plusieurs IPs, la commande ci-dessus passera par plusieurs ou tous. Par exemple:

$ 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

exemples:

Succès:
$ 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
Échec:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1

Si le nom d'hôte est associé à plusieurs IPs, la commande ci-dessus passera par plusieurs ou la totalité d'entre eux. Par exemple:

$ 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

remarques:

l'argument -v ( --verbose ) et la commande echo $? sont bien sûr à titre d'illustration seulement.

86
répondu A-B-B 2016-12-18 21:46:15

Avec netcat , vous pouvez vérifier si un port est ouvert comme ceci:

nc my.example.com 80 < /dev/null

la valeur de retour de nc sera un succès si le port TCP a été ouvert, et un échec (typiquement le code de retour 1) s'il ne pouvait pas faire la connexion TCP.

44
répondu Brandon Rhodes 2017-07-03 23:41:36

en Bash en utilisant les fichiers de pseudo-périphérique pour les connexions TCP/UDP est simple. Voici le 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

Test:

$ ./test.sh 
Connection to example.com on port 80 succeeded

Voici une ligne (syntaxe de Bash):

</dev/tcp/localhost/11211 && echo Port open. || echo Port closed.

notez que certains serveurs peuvent être protégés par un pare-feu contre les attaques SYN flood, de sorte que vous pouvez éprouver un délai de connexion TCP (~75secs). De contourner la question de l'heure d'arrêt, essayer:

timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.

Voir: Comment réduire le TCP connect() de l'appel système timeout?

22
répondu kenorb 2017-05-23 12:18:19

bien qu'il s'agisse d'une vieille question, je viens d'en traiter une variante, mais aucune des solutions ici n'était applicable, donc j'en ai trouvé une autre, et je l'ajoute pour la postérité. Oui, je sais que L'OP a dit qu'ils étaient au courant de cette option et que cela ne leur convenait pas, mais pour quiconque suivrait par la suite, cela pourrait s'avérer utile.

dans mon cas, je veux tester la disponibilité d'un service local apt-cacher-ng à partir d'un service docker . Que signifie absolument rien ne peut être installé avant le test. Non. nc , nmap , expect , telnet ou python . perl cependant est présent, avec les bibliothèques de base, donc j'ai utilisé ceci:

perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))'
8
répondu mc0e 2015-05-04 19:50:53

si vous utilisez ksh ou bash ils supportent tous les deux la redirection IO vers/à partir d'une socket en utilisant la construction /dev/tcp/IP/PORT . Dans cet exemple Korn shell je redirige no-op's ( : ) std-in à partir d'une socket:

W$ python -m SimpleHTTPServer &
[1]     16833
Serving HTTP on 0.0.0.0 port 8000 ...
W$ : </dev/tcp/127.0.0.1/8000

le shell affiche une erreur si la prise n'est pas ouverte:

W$ : </dev/tcp/127.0.0.1/8001
ksh: /dev/tcp/127.0.0.1/8001: cannot open [Connection refused]

vous pouvez donc utiliser il s'agit de l'essai dans une si condition:

SERVER=127.0.0.1 PORT=8000
if (: < /dev/tcp/$SERVER/$PORT) 2>/dev/null
then
    print succeeded
else
    print failed
fi

le no-op est dans un sous-sol donc je peux jeter std-err si la redirection std-in échoue.

j'utilise souvent / dev /tcp pour vérifier la disponibilité D'une ressource sur 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$ 

Ce one-liner s'ouvre descripteur de fichier 9 pour la lecture et l'écriture à l' socket, imprime le HTTP GET sur la socket et utilise cat pour lire à partir de la socket.

7
répondu merebagatelle 2016-10-18 16:12:36

j'avais besoin d'une solution plus flexible pour travailler sur plusieurs dépôts git et j'ai donc écrit le Code sh suivant basé sur 1 et 2 . Vous pouvez utiliser votre adresse de serveur au lieu de gitlab.com et votre port en remplacement de 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
7
répondu Ahmad Yoosofan 2018-09-19 08:20:29

dans certains cas où des outils comme curl, telnet, nc OMAP ne sont pas disponibles, vous avez encore une chance avec 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
5
répondu PRF 2016-07-22 14:24:33

si vous voulez utiliser nc mais n'avez pas de version qui supporte -z , essayez d'utiliser --send-only :

nc --send-only <IP> <PORT> </dev/null

et avec timeout:

nc -w 1 --send-only <IP> <PORT> </dev/null

et sans recherche DNS si C'est un IP:

nc -n -w 1 --send-only <IP> <PORT> </dev/null

renvoie les codes comme le -z basé sur si elle peut se connecter ou non.

4
répondu Chris Mendez 2017-04-07 20:32:34

je suppose qu'il est trop tard pour une réponse, et peut-être pas une bonne idée, mais ici vous allez...

pourquoi ne pas le mettre dans une boucle de temps avec une minuterie. Je suis plus un gars Perl que Solaris, mais selon la coquille que vous utilisez, vous devriez être en mesure de faire quelque chose comme:

TIME = 'date +%s' + 15
while TIME != `date +%s'
do whatever

et puis ajoutez juste un drapeau dans la boucle while, de sorte que si elle s'étale avant de terminer, vous pouvez citer le timeout comme raison de l'échec.

je soupçonne que le telnet a un interrupteur de temporisation aussi, mais juste au-dessus de ma tête, je pense que le dessus fonctionnera.

1
répondu Red Thomas 2014-09-22 16:14:26

j'ai eu besoin de script court qui a été exécuté en cron et n'a pas produit. Je résous mon problème en utilisant 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

pour l'exécuter, vous devez installer nmap car il ne s'agit pas d'un paquet installé par défaut.

0
répondu Krystian Kulasza 2015-10-30 08:51:47

cela utilise telnet dans les coulisses, et semble bien fonctionner sur mac/linux. Il n'utilise pas netcat en raison des différences entre les versions sur linux/mac, et cela fonctionne avec une installation mac par défaut.

exemple:

$ is_port_open.sh 80 google.com
OPEN

$ is_port_open.sh 8080 google.com
CLOSED

is_port_open.sh

PORT=
HOST=
TIMEOUT_IN_SEC=${3:-1}
VALUE_IF_OPEN=${4:-"OPEN"}
VALUE_IF_CLOSED=${5:-"CLOSED"}

function eztern()
{
  if [ "" == "" ]
  then
    echo 
  else
    echo 
  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 
0
répondu Brad Parks 2016-02-19 18:23:05

vérifier les ports à l'aide de bash

exemple

$ ./test_port_bash.sh 192.168.7.7 22

le port 22 est ouvert

Code

HOST=
PORT=
exec 3> /dev/tcp/${HOST}/${PORT}
if [ $? -eq 0 ];then echo "the port  is open";else echo "the port  is closed";fi
0
répondu krbu 2017-07-02 09:33:54

en S'appuyant sur la réponse la plus votée, voici une fonction pour attendre que deux ports soient ouverts, avec un temps mort aussi. Notez les deux ports qui doivent être ouverts, 8890 et 1111, ainsi que le max_attempts (1 par seconde).

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
}
0
répondu João Rocha da Silva 2018-03-07 03:20:33

nmap-ncat de test pour le port local qui n'est pas déjà en cours d'utilisation


availabletobindon() {
  port=""
  nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q 'Idle timeout expired'
  return "$?"
}
-1
répondu isleofgray 2016-04-26 11:27:20