web-dev-qa-db-fra.com

Teste si un port sur un système distant est accessible (sans telnet)

Auparavant, nous utilisions telnet pour savoir si un port d'un hôte distant était ouvert: telnet hostname port tentait de se connecter à n'importe quel port de n'importe quel hôte et vous donnait accès au flux brut TCP.

De nos jours, telnet n'est pas installé sur les systèmes sur lesquels je travaille (pour des raisons de sécurité) et toutes les connexions sortantes vers tous les hôtes sont bloquées par défaut. Avec le temps, il est facile de ne plus savoir quels ports sont ouverts pour quels hôtes.

Existe-t-il un autre moyen de vérifier si un port d'un système distant est ouvert - en utilisant un système Linux sur lequel un nombre limité de packages est installé et que telnet n'est pas disponible?

322
Steve HHH

Bash a pu accéder à TCP et UDP ports pendant un certain temps. De la page de manuel:

/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.

Donc, vous pouvez utiliser quelque chose comme ceci:

xenon-lornix:~> cat < /dev/tcp/127.0.0.1/22
SSH-2.0-OpenSSH_6.2p2 Debian-6
^C pressed here

Taa Daa!

261
lornix

Nice et verbeux! À partir des pages de manuel.
Port unique:

nc -zv 127.0.0.1 80

Plusieurs ports:

nc -zv 127.0.0.1 22 80 8080

Gamme de ports:

nc -zv 127.0.0.1 20-30
373
Subhranath Chunder

Netcat est un outil utile:

nc 127.0.0.1 123 &> /dev/null; echo $?

Produira 0 si le port 123 est ouvert et 1 s'il est fermé.

100
thnee

La méthode la plus simple, sans faire appel à un autre outil, tel que socat, est telle que décrite dans la réponse de @ lornix ci-dessus. Ceci est juste pour ajouter un exemple concret de la façon dont on utiliserait le psuedo-device /dev/tcp/... dans Bash si, par exemple, vous vouliez tester si un autre serveur avait un port donné accessible via la ligne de commande.

Exemples

Supposons que j'ai un hôte sur mon réseau nommé 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

La raison pour laquelle vous souhaitez placer le echo > /dev/... entre parenthèses comme ceci, (echo > /dev/...), est que si vous ne le faites pas, alors, avec des tests de connexions en panne, vous obtiendrez ces types de messages.

$ (echo > /dev/tcp/skinner/223) && echo hi
bash: connect: Connection refused
bash: /dev/tcp/skinner/223: Connection refused

Ceux-ci ne peuvent pas simplement être redirigés vers /dev/null car ils proviennent de la tentative d'écriture de données sur le périphérique /dev/tcp. Nous capturons donc toute cette sortie dans une sous-commande, c'est-à-dire (...cmds...), et redirigeons la sortie de la sous-commande.

56
slm

J'ai trouvé que curl peut faire le travail de la même manière que telnet, et curl vous dira même quel protocole attend l'auditeur.

Construisez un URI HTTP à partir du nom d'hôte et du port en tant que premier argument de curl. Si curl peut se connecter, il signalera une incompatibilité de protocole et se fermera (si le programme d'écoute n'est pas un service Web). Si curl ne parvient pas à se connecter, le délai d'expiration est dépassé.

Par exemple, le port 5672 sur l'hôte 10.0.0.99 est fermé ou bloqué par un pare-feu:

$ curl http://10.0.0.99:5672
curl: (7) couldn't connect to Host

Toutefois, à partir d'un autre système, le port 5672 de l'hôte 10.0.0.99 est accessible et semble exécuter un écouteur AMQP.

$ curl http://10.0.0.99:5672
curl: (56) Failure when receiving data from the peer
AMQP

Il est important de faire la distinction entre les différents messages: la première défaillance a été causée par le fait que curl n'a pas pu se connecter au port. Le deuxième échec est un test de réussite, même si curl s'attend à un écouteur HTTP au lieu d'un écouteur AMQP.

41
Steve HHH
[admin@automation-server 1.2.2]# nc -v -z -w2 192.168.193.173 6443
nc: connect to 192.168.193.173 port 6443 (tcp) failed: Connection refused

[admin@automation-server 1.2.2]# nc -v -z -w2 192.168.194.4 6443
Connection to 192.168.194.4 6443 port [tcp/Sun-sr-https] succeeded!

J'espère que cela résoudra votre problème :)

Voici un one-liner:

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

en utilisant la syntaxe Bash expliquée dans @lornix answer .

Pour plus d'informations, consultez: Guide de script Bash avancé: Chapitre 29. /dev et /proc .

9
kenorb

Je me suis battu toute la journée parce qu'aucune de ces réponses ne semblait fonctionner pour moi. Le problème est que la version la plus récente de nc n'a plus l'indicateur -z, alors que l'accès direct via TCP (selon @lornix et @slm) échoue lorsque l'hôte n'est pas accessible. J'ai finalement trouvé cette page , où j'ai finalement trouvé non pas un mais deux exemples de travail:

  1. nc -w1 127.0.0.1 22 </dev/null

    (l'indicateur -w prend en charge le délai d'attente et le </dev/null remplace l'indicateur -z)

  2. timeout 1 bash -c '(echo > /dev/tcp/127.0.0.1/22) >/dev/null 2>&1'

    (la commande timeout prend en charge le délai d'attente et le reste provient de @slm)

Ensuite, utilisez simplement && et/ou || (ou même $?) pour extraire le résultat. Espérons que quelqu'un trouvera cette information utile.

6
Azukikuru

Il ne devrait pas être disponible sur votre boîte, mais essayez avec nmap.

2
peperunas

En combinant les réponses de @kenorb et de @ Azukikuru, vous pouvez tester le port ouvert/fermé/avec un pare-feu.

timeout 1 bash -c '</dev/tcp/127.0.0.1/22 && echo Port is open || echo Port is closed' || echo Connection timeout

Une autre approche avec curl pour atteindre n'importe quel port

curl telnet://127.0.0.1:22
1
Miguel Ferreira

Voici une fonction qui va choisir l'une des méthodes en fonction de ce qui est installé sur votre système:

# Check_port <address> <port> 
check_port() {
if [ "$(which nc)" != "" ]; then 
    tool=nc
Elif [ "$(which curl)" != "" ]; then
     tool=curl
Elif [ "$(which telnet)" != "" ]; then
     tool=telnet
Elif [ -e /dev/tcp ]; then
      if [ "$(which gtimeout)" != "" ]; then  
       tool=gtimeout
      Elif [ "$(which timeout)" != "" ]; then  
       tool=timeout
      else
       tool=devtcp
      fi
fi
echo "Using $tool to test access to $1:$2"
case $tool in
nc) nc -v -G 5 -z -w2 $1 $2 ;;
curl) curl --connect-timeout 10 http://$1:$2 ;;
telnet) telnet $1 $2 ;;
gtimeout)  gtimeout 1 bash -c "</dev/tcp/${1}/${2} && echo Port is open || echo Port is closed" || echo Connection timeout ;;
timeout)  timeout 1 bash -c "</dev/tcp/${1}/${2} && echo Port is open || echo Port is closed" || echo Connection timeout ;;
devtcp)  </dev/tcp/${1}/${2} && echo Port is open || echo Port is closed ;;
*) echo "no tools available to test $1 port $2";;
esac

}
export check_port
1
Robert Boyd

Si vous devez tester plus que sur le système, vous pouvez utiliser notre outil de test, dda-serverspec ( https://github.com/DomainDrivenArchitecture/dda-serverspec-crate ) pour ces tâches. Vous pouvez définir vos attentes

{:netcat [{:Host "mywebserver.com" :port "443"}
          {:Host "telnet mywebserver.com" :port "80"}
          {:Host "telnet mywebserver.com" :port "8443"}]}

et testez ces attentes soit avec localhost, soit avec des hôtes distants (connectez-vous via ssh). Pour les tests à distance, vous devez définir une cible:

{:existing [{:node-name "test-vm1"
             :node-ip "35.157.19.218"}
            {:node-name "test-vm2"
             :node-ip "18.194.113.138"}]
 :provisioning-user {:login "ubuntu"}}

Vous pouvez exécuter le test avec Java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Sous le capot, nous utilisons netcat tel que proposé ci-dessus ...

0
jerger