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?
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!
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
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é.
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.
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.
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.
[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
.
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:
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
)
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.
Il ne devrait pas être disponible sur votre boîte, mais essayez avec nmap
.
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
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
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 ...