Tester efficacement si un port est ouvert sous Linux?

197

À partir d'un script bash, comment savoir rapidement si un port 445est ouvert / à l'écoute sur un serveur.

J'ai essayé quelques options, mais je veux quelque chose de rapide:
1. lsof -i :445 (prend quelques secondes)
2. netstat -an |grep 445 |grep LISTEN(prend des secondes)
3. telnet(il ne revient pas)
4. nmap, netcatne sont pas disponibles sur le serveur

Ce sera bien de connaître un moyen qui ne fait pas d'énumération en premier et qui fait ensuite la greps.

Aman Jain
la source
1
Netcat est-il disponible? Il a un chemin d'échec rapide IIRC. netcat.sourceforge.net
JimR
5
netstat -lnt(avec -tet sans -a) limitera la sortie à l'écoute des connexions TCP uniquement. Cela peut accélérer un peu. Vous pouvez ajouter -4pour IPv4 uniquement si vous n'avez pas besoin d'IPv6.
Bartosz Moczulski
lsof -i est un favori personnel.
Matt Joyce
14
netstat -an | grep PORTNUMBER | grep -i listenSi la sortie est vide, le port n'est pas utilisé.
automatix
Je ne sais pas pourquoi lsofest lent pour vous, mais normalement c'est la meilleure des solutions que vous avez énumérées. Votre netstatsolution n'est pas très fiable (vous pouvez la deviner à chaque fois que vous l'utilisez grep; de toute façon elle revient vraie si quelqu'un écoute par exemple sur 4450). telnetet netcatessayez de créer une connexion, ce qui n'est pas toujours ce que vous voulez.
petersohn

Réponses:

155

Une surprise que j'ai découverte récemment est que Bash supporte nativement les connexions TCP comme descripteurs de fichiers . Utiliser:

exec 6<>/dev/tcp/ip.addr.of.server/445
echo -e "GET / HTTP/1.0\n" >&6
cat <&6

J'utilise 6 comme descripteur de fichier parce que 0,1,2 sont stdin, stdout et stderr. 5 est parfois utilisé par Bash pour les processus enfants , donc 3,4,6,7,8 et 9 devraient être sûrs.

Selon le commentaire ci-dessous, pour tester l'écoute sur un serveur local dans un script:

exec 6<>/dev/tcp/127.0.0.1/445 || echo "No one is listening!"
exec 6>&- # close output connection
exec 6<&- # close input connection

Pour déterminer si quelqu'un écoute, essayez de vous connecter par bouclage. S'il échoue, le port est fermé ou nous ne sommes pas autorisés à y accéder. Ensuite, fermez la connexion.

Modifiez cela pour votre cas d'utilisation, comme l'envoi d'un e-mail, la fermeture du script en cas d'échec ou le démarrage du service requis.

Spencer Rathbun
la source
2
Cela vient de pendre pour moi.
Aman Jain
@AmanJain cat attend que EOF ou Ctrl-C se ferme. Vous devrez ajuster cela pour votre protocole. BTW exécutez-vous cela sur un serveur distant?
Spencer Rathbun
Je veux intégrer le code de vérification de port dans un script sur le serveur, sous /etc/init.d/
Aman Jain
@AmanJain Je l'ai mis à jour pour un système local. Vous voulez juste vérifier si l'écoute est correcte? Il n'y a pas de vérification de protocole, comme demander une page via http?
Spencer Rathbun
1
Ce n'est pas une méthode fiable car tous les systèmes d'exploitation (par exemple, ubuntu 16 comme je l'ai découvert aujourd'hui) sont livrés avec bash compilé pour la construction de l' /dev/tcp/IP/PORTarbre
dyasny
107

Il y a une très courte réponse rapide ici: comment tester si le port TCP distant est ouvert à partir du script Shell?

nc -z <host> <port>; echo $?

Je l'utilise avec 127.0.0.1 comme adresse "distante".

cela renvoie "0" si le port est ouvert et "1" si le port est fermé

par exemple

nc -z 127.0.0.1 80; echo $?

-z Spécifie que nc doit simplement rechercher les démons à l'écoute, sans leur envoyer de données. C'est une erreur d'utiliser cette option en conjonction avec l'option -l.

Noir
la source
2
Cela semble être le moyen le plus simple, merci. L'exemple de lien de script ne fonctionne plus, cependant, il s'explique tout de même de toute façon.
derFunk
Agréable! C'est beaucoup plus rapide que les autres réponses sur un serveur avec de nombreux ports ouverts. Retourne en <0,01 seconde pour moi tandis que netstat / lsof prend 1s +
Tim
2
L'indicateur -z n'est pas disponible dans le ncat basé sur nmap avec lequel les distributions les plus récentes sont livrées: Fedora, Centos, etc. (nmap-ncat-6.01-9.fc18.x86_64)
Zack
9
Contre-intuitivement, cela renvoie "0" si le port est ouvert et "1" si le port est fermé.
Sean
3
Les commandes @Sean unix renvoient généralement '0' pour indiquer le succès et non nul pour l'échec. Ainsi, «0» indique qu'il s'est correctement connecté et différent de zéro qu'il ne s'est pas connecté pour une raison quelconque. Notez cependant que certaines versions de «nc» ne prennent pas en charge l'argument «-z», donc stackoverflow.com/a/25793128/6773916 est sans doute une meilleure solution.
Rich Sedman
89

Vous pouvez utiliser netstat de cette façon pour des résultats beaucoup plus rapides:

Sous Linux:

netstat -lnt | awk '$6 == "LISTEN" && $4 ~ /\.445$/'

Sur Mac:

netstat -anp tcp | awk '$6 == "LISTEN" && $4 ~ /\.445$/'

Cela produira une liste de processus écoutant sur le port (445 dans cet exemple) ou ne produira rien si le port est libre.

anubhava
la source
1
votre syntaxe netstat est incorrecte. netstat -ln --tcp fonctionne, mais reste lent
Aman Jain
6
En fait, c'est une syntaxe correcte, mais vous utilisez probablement Linux et je suis sur Mac. Pour Linux, utilisez ceci:netstat -lnt | awk '$6 == "LISTEN" && $4 ~ ".445"'
anubhava
21
cela n'a rien donné.
Jürgen Paul
1
La question concernait cependant Linux, donc le commentaire devrait peut-être figurer dans la réponse.
UpTheCreek
1
Afin de vérifier le port 80, je devais utiliser awk '$6 == "LISTEN" && $4 ~ "80$"'. Au lieu de vérifier le point avant le numéro de port avec \.80, j'ai utilisé80$ . Sinon, cela correspond également aux adresses IP contenant .80et aux ports commençant par 80tels que 8000.
Patrick Oscity le
37

Vous pouvez utiliser netcat pour cela.

nc ip port < /dev/null

se connecte au serveur et ferme directement à nouveau la connexion. Si netcat n'est pas en mesure de se connecter, il renvoie un code de sortie différent de zéro. Le code de sortie est stocké dans la variable $ ?. Par exemple,

nc ip port < /dev/null; echo $?

renverra 0 si et seulement si netcat a réussi à se connecter au port.

Tony
la source
1
Cette réponse a besoin de plus de votes positifs. nc fonctionne parfaitement pour ce cas. l'astuce / dev / tcp est intelligente, mais semble difficile à implémenter un script avec des interruptions de signal.
Avindra Goolcharan
5
nca le -zdrapeau à cet effet, qui ne nécessite pas de prendre des entrées /dev/null. Il y a déjà une réponse en utilisant le -zdrapeau ci-dessus.
Abe Voelker
2
@AbeVoelker Toutes les versions de nc ne prennent pas en charge l'indicateur -z. Je suis sur CentOS 7 et j'ai trouvé que la solution de Tony était ce dont j'avais besoin.
Shadoninja
@Shadoninja Bon à savoir! Si je pouvais éditer la désinvolture de mon commentaire de 2014, je le ferais.
Abe Voelker
'nc' ne prend plus en charge '-z' et cette réponse semble donc être la meilleure solution.
Rich Sedman
18

Basé sur la réponse de Spencer Rathbun, en utilisant bash:

true &>/dev/null </dev/tcp/127.0.0.1/$PORT && echo open || echo closed
user1338062
la source
Bon, cela supprimera le message "Connexion refusée". Quitte automatiquement si le service accepte la connexion sans attendre indéfiniment.
Seff
Meilleure solution pour les services qui n'envoient aucune donnée après une nouvelle connexion. Environ 20 fois plus rapide que d'appeler netcat. Peut être raccourci à: &>/dev/null </dev/tcp/127.0.0.1/$PORT
ens
16

ils sont répertoriés dans / proc / net / tcp.

c'est la deuxième colonne, après le ":", en hex:

> cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 10863 1 ffff88020c785400 99 0 0 10 -1                     
   1: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7983 1 ffff88020eb7b3c0 99 0 0 10 -1                      
   2: 0500010A:948F 0900010A:2328 01 00000000:00000000 02:00000576 00000000  1000        0 10562454 2 ffff88010040f7c0 22 3 30 5 3                   
   3: 0500010A:E077 5F2F7D4A:0050 01 00000000:00000000 02:00000176 00000000  1000        0 10701021 2 ffff880100474080 41 3 22 10 -1                 
   4: 0500010A:8773 16EC97D1:0050 01 00000000:00000000 02:00000BDC 00000000  1000        0 10700849 2 ffff880104335440 57 3 18 10 -1                 
   5: 0500010A:8772 16EC97D1:0050 01 00000000:00000000 02:00000BF5 00000000  1000        0 10698952 2 ffff88010040e440 46 3 0 10 -1                  
   6: 0500010A:DD2C 0900010A:0016 01 00000000:00000000 02:0006E764 00000000  1000        0 9562907 2 ffff880104334740 22 3 30 5 4                    
   7: 0500010A:AAA4 6A717D4A:0050 08 00000000:00000001 02:00000929 00000000  1000        0 10696677 2 ffff880106cc77c0 45 3 0 10 -1  

donc je suppose que l'un de ceux :50 de la troisième colonne doit être stackoverflow: o)

regardez man 5 procpour plus de détails. et choisir cela avec sed, etc. est laissé comme un exercice pour le lecteur doux ...

Andrew Cooke
la source
10
ss -tl4 '( sport = :22 )'

2 ms est assez rapide?

Ajoutez les deux points et cela fonctionne sur Linux

leucos
la source
2
Grand, ssest même légèrement plus rapide que nc. lest pour l' écoute , 4est pour IPv4; sportsignifie (bien sûr) port source . La commande ci-dessus suppose un port TCP d'écoute ( toption): utilisez l' uoption pour les UDP, ou aucun d'entre eux pour les deux protocoles. Plus d'informations sur sscomme toujours sur Nixcraft . REMARQUE: les ssfiltres ne fonctionnent pas ici, je ne sais pas pourquoi (bash 4.3.11, utilitaire ss, iproute2-ss131122), doivent aller avec grep .
Campa
Dommage que la sscommande ne retourne pas de code de sortie reflétant sa découverte; il retourne toujours 0 code de sortie.
John Greene
| grep LISTEN?
leucos
Je reçois State Recv-Q Send-Q Local Address:Port Peer Address:Portet maintenant? Qu'est-ce que ça veut dire?
noir
6

En voici une qui fonctionne pour Mac et Linux:

netstat -aln | awk '$6 == "LISTEN" && $4 ~ "[\\.\:]445$"'
Artur Bodera
la source
Je pense que vous pouvez retirer le [\\.\:].
Patrick Oscity
6
nc -l 8000

Où 8000 est le numéro de port. Si le port est libre, il démarrera un serveur que vous pourrez fermer facilement. Si ce n'est pas le cas, cela générera une erreur:

nc: Address already in use
Jose Enrique
la source
5

Je voulais vérifier si un port est ouvert sur l'un de nos serveurs de test Linux. J'ai pu le faire en essayant de me connecter avec telnet de ma machine de développement au serveur de test. Sur votre machine de développement, essayez d'exécuter:

$ telnet test2.host.com 8080
Trying 05.066.137.184...
Connected to test2.host.com

Dans cet exemple, je veux vérifier si le port 8080 est ouvert sur l'hôte test2.host.com

razvang
la source
1

tcping est un excellent outil avec une surcharge très faible, ainsi qu'un argument de timeout pour le rendre plus rapide:

[root@centos_f831dfb3 ~]# tcping 10.86.151.175 22 -t 1
10.86.151.175 port 22 open.
[root@centos_f831dfb3 ~]# tcping 10.86.150.194 22 -t 1
10.86.150.194 port 22 user timeout.
[root@centos_f831dfb3 ~]# tcping 1.1.1.1 22 -t 1
1.1.1.1 port 22 closed.
Payam
la source
1
Je ne suis pas sûr que tcping vaille la peine d'être installé lorsque la solution de Spencer ne nécessite aucune installation supplémentaire, mais c'est la solution la plus propre et la plus lisible par l'homme.
bdombro
1

Vous pouvez également utiliser la commande netcat

[location of netcat]/netcat -zv [ip] [port]

ou

nc -zv [ip] [port]

-z - définit nc pour simplement rechercher les démons à l'écoute, sans leur envoyer de données.
-v - active le mode détaillé.

Saurabh
la source
-2

nmapest le bon outil. Utilisez simplementnmap example.com -p 80

Vous pouvez l'utiliser à partir d'un serveur local ou distant. Il vous aide également à identifier si un pare-feu bloque l'accès.

zainengineer
la source
-4

Si vous utilisez iptables, essayez:

iptables -nL

ou

iptables -nL | grep 445
Noz
la source
qui répertorie simplement les règles iptables ... qui peuvent ne pas avoir de corrélation avec les ports ouverts.
David Goodwin