Test, ob ein Port auf einem Remote-System erreichbar ist (ohne Telnet)

353

Früher haben wir geprüft telnet, ob ein Port auf einem Remote-Host geöffnet war: Es wurde telnet hostname portversucht, eine Verbindung zu einem beliebigen Port auf einem beliebigen Host herzustellen, und Sie haben Zugriff auf den rohen TCP-Stream.

In diesen Tagen ist auf den Systemen, auf denen ich arbeite, aus Sicherheitsgründen kein Telnet installiert, und alle ausgehenden Verbindungen zu allen Hosts werden standardmäßig blockiert. Mit der Zeit ist es leicht, den Überblick zu verlieren, welche Ports für welche Hosts geöffnet sind.

Gibt es eine andere Möglichkeit zu testen, ob ein Port auf einem Remote-System offen ist - unter Verwendung eines Linux-Systems mit einer begrenzten Anzahl installierter Pakete, telnetdas nicht verfügbar ist?

Steve HHH
quelle
Ich hatte das gleiche Problem. Die Antwort von @Subhranath Chunder unten hat geholfen. Dann fand ich jedoch heraus, dass die Installation von Telnet nur eine kleine Sache des Laufens war brew install telnet. Daher erwarte ich, dass Linux-Benutzer dasselbe mit yumund tun können apt-get.
Mig82

Antworten:

277

Bash kann seit einiger Zeit auf TCP- und UDP- Ports zugreifen . Von der Manpage:

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

Sie könnten also so etwas verwenden:

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

Taa Daa!

Lornix
quelle
Dies scheint auch in MinGW zu funktionieren . Beispielsweise antwortet ein Remote- VNC- Server unter 192.168.2.100 mit "RFB 003.008", indem er "cat </dev/tcp/192.168.2.100/5900" verwendet.
Peter Mortensen
1
@lornix, ok, aber in diesem Fall muss ich das gleiche Ergebnis mit nc ohne -z Option erhalten, aber es funktioniert immer noch nicht: # nc -v -w5 127.0.0.1 18080 Verbindung zu 127.0.0.1 18080 Port [tcp / *] erfolgreich! # cat </dev/tcp/127.0.0.1/18080 Hängt nur ohne Ergebnis. Ich möchte nur verstehen, wann ich die Option "/ dev / tcp / host / port" verwenden kann
Alexandr
5
@Alexandr ... eigentlich ist "hängt ohne Ergebnis" ziemlich viel erwartetes Verhalten. Katze wartet auf Eingabe. nc verfügt über zusätzliche intelligente Funktionen, die es ermöglichen, ausstehende Daten zu erkennen und den Versuch abzubrechen. Katze ist nicht ganz so schlau. Versuchen Sie cat < /dev/tcp/localhost/22, Sie sollten Ihren sshd-Header erhalten. Offensichtlich wartet Ihr Prozess auf Port 18080 darauf, dass etwas eingeht, bevor Sie etwas senden. Port 22 ( ssh ) begrüßt Sie mit seiner Version und so weiter. Versuch es!
Lornix
1
@lornix, vielen Dank für die Erklärung! Jetzt ist die Einschränkung klar. Ich denke, die Verwendung von nc sollte ein bevorzugter Weg sein, um Ports zu überprüfen.
Alexandr
2
Dies war unglaublich hilfreich, wenn mit einem Docking-Container gearbeitet wurde, auf dem nichts installiert war. Konnte schnell überprüfen, ob der Container über DNS auf nicht containerisierte DB zugreifen konnte. Beispiel: cat </ dev / tcp / hostname / 5432
Michael Hobbs
404

Schön und ausführlich! Aus den Manpages.
Einzelner Port:

nc -zv 127.0.0.1 80

Mehrere Ports:

nc -zv 127.0.0.1 22 80 8080

Reihe von Häfen:

nc -zv 127.0.0.1 20-30
Subhranath Chunder
quelle
6
Scheint die mit Abstand beste Antwort zu sein, danke. ;-)
lpapp
6
Dies hing beim Versuch auf Ubuntu 14.04 (Trusty Tahr) für einen Remote-Server (gleiches LAN) für geschlossene Ports (Zeitüberschreitung nach 127 Sekunden) - daher in Skripten nicht sehr geeignet. Es funktionierte jedoch für einen Dienst, bei dem ein Hafen offen war. Die Verwendung der Option "-w2" könnte die Lösung sein.
Peter Mortensen
6
Verwenden Sie die Option -u für UDP-Ports.
Efren
8
In Version 6.4 wird ncat -z nicht erkannt. Auf z
smishra
5
Sie können mehrere Bereiche prüfen mit: nc -zv 127.0.0.1 22,80,8080,20-30,443-446(nc Version: 1.107-4).
Bobbel
102

Netcat ist ein nützliches Werkzeug:

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

Wird ausgegeben, 0wenn Port 123 offen und 1geschlossen ist.

Knie
quelle
Dies ist eine weitaus elegantere und skriptfähigere Antwort als meine. Es ist für mich bedauerlich, dass die sicherheitsbewussten Systemadministratoren, die vorenthalten haben, telnetauch vorenthalten haben nc(obwohl - seltsamerweise - nicht curloder wget).
Steve HHH
Ja das ist völlig willkürlich und albern.
Thnee
3
Lasst die FORAussagen beginnen!
Chad Harrison
1
Dies hing beim Versuch auf Ubuntu 14.04 (Trusty Tahr) für einen Remote-Server (gleiches LAN) für geschlossene Ports (Zeitüberschreitung nach ca. 127 Sekunden) - daher in Skripten nicht sehr geeignet. Es funktionierte jedoch für einen Dienst, bei dem ein Port offen war und 0 zurückgab. Die Verwendung der Option "-w2" könnte die Lösung sein.
Peter Mortensen
1
Ich denke, -G 2wäre besser geeignet für TCP-Timeout
AB
58

Die einfachste Methode, ohne ein anderes Tool wie z. B. zu verwenden socat, ist die in der obigen Antwort von @ lornix beschriebene. Dies ist nur ein Beispiel dafür, wie man das psuedo-Gerät /dev/tcp/...in Bash verwenden würde, wenn man beispielsweise testen möchte, ob ein anderer Server einen bestimmten Port hat, auf den über die Befehlszeile zugegriffen werden kann.

Beispiele

Angenommen, ich habe einen Host in meinem Netzwerk namens 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

Der Grund, warum Sie die echo > /dev/...Klammern wie (echo > /dev/...)folgt einschließen möchten , ist, dass Sie, wenn Sie dies nicht tun, bei Tests von Verbindungen, die inaktiv sind, diese Arten von Nachrichten angezeigt bekommen.

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

Diese können nicht einfach umgeleitet werden, /dev/nullda sie aus dem Versuch stammen, Daten auf das Gerät zu schreiben /dev/tcp. Wir erfassen also die gesamte Ausgabe innerhalb eines Unterbefehls (...cmds...)und leiten die Ausgabe des Unterbefehls um.

slm
quelle
Das ist ausgezeichnet. Ich wünschte, es würde bis an die Spitze gewählt. Ich habe die Seite nur so weit unten gelesen, weil ich versehentlich gescrollt habe, bevor ich sie geschlossen habe.
Still.Tony
@ Okuma.Tony - ja, das ist immer ein Problem mit Qs, die viele Antworten haben 8-). Vielen Dank für das Feedback.
Slm
46

Ich habe festgestellt, dass curlder Job möglicherweise auf ähnliche Weise erledigt wird telnet, und curlIhnen sogar sagen wird, welches Protokoll der Hörer erwartet.

Erstellen Sie einen HTTP-URI aus dem Hostnamen und dem Port als erstes Argument für curl. Wenn curleine Verbindung hergestellt werden kann, wird ein Protokollkonflikt gemeldet und beendet (wenn der Listener kein Webdienst ist). Wenn curlkeine Verbindung hergestellt werden kann, tritt eine Zeitüberschreitung auf.

Beispielsweise ist Port 5672 auf Host 10.0.0.99 entweder geschlossen oder von einer Firewall blockiert:

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

Von einem anderen System aus kann jedoch Port 5672 auf Host 10.0.0.99 erreicht werden, auf dem anscheinend ein AMQP-Listener ausgeführt wird.

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

Es ist wichtig, zwischen den verschiedenen Nachrichten zu unterscheiden: Der erste Fehler war, dass curlkeine Verbindung zum Port hergestellt werden konnte. Der zweite Fehler ist ein Erfolgstest, obwohl curlein HTTP-Listener anstelle eines AMQP-Listeners erwartet wird.

Steve HHH
quelle
5
Wenn keine Locke verfügbar ist, ist dies möglicherweise der Fall. wget -qS -O- http://ip.add.re.ss:portsollte effektiv das gleiche tun.
ein Lebenslauf vom
4
Dies funktioniert sogar mit einem Hostnamen, z. curl myhost:22.
25.
Dies kann falsch sein. Ich habe einen laufenden Tomcat-Dienst, erhalte aber den 404-Fehler. # curl -k 192.168.194.4:6443 <html> <head> <title> Apache Tomcat / 7.0.34 - Fehlerbericht </ title> <style> <! - H1 --- HR {color: # 525D76;} -> </ style> </ head> <body> <h1> HTTP-Status 404 - / </ h1> <HR size = "1" noshade = "noshade"> <p> <b> </ b> Statusbericht </ p> <p> <b> Nachricht </ b> <u> / </ u> </ p> <p> <b> Beschreibung </ b> <u> Die angeforderte Ressource ist nicht verfügbar. </ u> </ p> <HR size = "1" noshade = "noshade"> <h3> Apache Tomcat / 7.0.34 </ h3> </ body> </ html>
Siehe meinen Beitrag mit ähnlichem Ansatz.
Kenorb
12
[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!

Hoffe es löst dein Problem :)

Mohammad Shahid Siddiqui
quelle
1
Ja, das ist besser - bei geschlossenen Ports tritt fast sofort eine Zeitüberschreitung ein.
Peter Mortensen
1
Verwendet dies immer TCP oder gibt es eine Möglichkeit, UDP zu überprüfen?
kmoe
6

Ich kämpfte einen ganzen Tag lang, weil keine dieser Antworten für mich zu funktionieren schien. Das Problem ist, dass die neueste Version von ncdas -zFlag nicht mehr hat , während der direkte Zugriff über TCP (wie bei @lornix und @slm) fehlschlägt, wenn der Host nicht erreichbar ist. Ich fand schließlich diese Seite , auf der ich endlich nicht nur ein, sondern zwei Arbeitsbeispiele fand:

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

    (Das -wFlag kümmert sich um das Timeout und </dev/nullersetzt das -zFlag.)

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

    (Der timeoutBefehl kümmert sich um das Timeout und der Rest kommt von @slm)

Verwenden Sie dann einfach &&und / oder ||(oder sogar $?), um das Ergebnis zu extrahieren. Hoffentlich findet jemand diese Informationen nützlich.

Azukikuru
quelle
4

Wenn Sie die Antworten von @kenorb und @Azukikuru kombinieren, können Sie Port offen / geschlossen / Firewall testen.

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

Ein weiterer Ansatz mit Curl zum Erreichen eines beliebigen Ports

curl telnet://127.0.0.1:22
Miguel Ferreira
quelle
3

Hier ist eine Funktion, die eine der Methoden auswählt, je nachdem, was auf Ihrem System installiert ist:

# 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
Robert Boyd
quelle
2

Es sollte nicht auf Ihrer Box verfügbar sein, aber versuchen Sie es mit nmap.

peperunas
quelle
4
nmapist ein gutes Werkzeug, aber auf diesen Systemen nicht verfügbar. Anstatt es herunterzuladen nmap, zu kompilieren, in mein Home-Verzeichnis zu installieren und dann auf alle anderen Systeme zu kopieren, hoffte ich, einen Weg zu finden, vorhandene Tools zu verwenden, die in den meisten Linux-Installationen verfügbar sind.
Steve HHH
1

als Referenz, um die Antwort von @peperunas zu erweitern:

Mit nmap können Sie Folgendes testen:

nmap -p 22 127.0.0.1

(Beispiel oben verwendet localhost zu Demonstrationszwecken)

user138278
quelle
0

Wenn Sie mehr als nur ein System testen müssen, können Sie für solche Aufgaben unser Testtool dda-serverspec ( https://github.com/DomainDrivenArchitecture/dda-serverspec-crate ) verwenden. Sie können Ihre Erwartungen definieren

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

und testen Sie diese Erwartung entweder gegen localhost oder gegen Remote-Hosts (Verbindung über ssh). Für Ferntests müssen Sie Ziele definieren:

{: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"}}

Sie können den Test mit ausführen java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Unter der Haube benutzen wir Netcat wie oben vorgeschlagen ...

jerger
quelle