Test vom Shell-Skript, wenn der Remote-TCP-Port geöffnet ist

Ich bin auf der Suche nach einer schnellen und einfachen Methode, um zu testen, ob ein bestimmter TCP-Port auf einem Remote-Server innerhalb eines Shell-Skripts geöffnet ist.

Ich habe es geschafft, es mit dem Telnet-Befehl zu tun, und es funktioniert gut, wenn der Port geöffnet ist, aber es scheint nicht zu Timeout, wenn es nicht ist und einfach dort hängt …

Hier ist ein Beispiel:

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 

Ich brauche entweder einen besseren Weg, oder eine Möglichkeit, Telnet auf Timeout zu erzwingen, wenn es zum Beispiel keine Verbindung in weniger als 8 Sekunden herstellt, und etwas zurückzugeben, was ich in Shell abfangen kann (Rückgabecode oder String in stdout).

Ich kenne die Perl-Methode, die das IO :: Socket :: INET-Modul verwendet und ein erfolgreiches Skript geschrieben hat, das einen Port testet, aber lieber nicht mit Perl arbeiten möchte.

Hinweis: Dies ist, was mein Server ausführt (wo ich das ausführen muss)

SunOS 5.10 Generic_139556-08 i86pc i386 i86pc

   

    Wie B. Rhodes nc wird nc die Aufgabe übernehmen. Eine kompaktere Art, es zu benutzen:

     nc -z   

    Auf diese Weise prüft nc nur, ob der Port offen ist, und beendet sich mit 0 bei Erfolg, 1 bei Fehler.

    Für eine schnelle interaktive Überprüfung (mit einem Timeout von 5 Sekunden):

     nc -z -v -w5   

    Es ist leicht genug, mit den Optionen -z und -w TIMEOUT für nc , aber nicht alle Systeme haben nc installiert. Wenn Sie eine Basush Version haben, die in letzter Zeit genug ist, wird dies funktionieren:

     # 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 

    Was passiert hier ist, dass timeout den Unterbefehl ausführen und ihn timeout wird, wenn es nicht innerhalb der angegebenen Zeitüberschreitung (1 Sekunde im obigen Beispiel) beendet wird. In diesem Fall ist bash der Unterbefehl und verwendet seine spezielle / dev / tcp-Behandlung , um eine Verbindung zum angegebenen Server und Port herzustellen. Wenn bash die Verbindung innerhalb des Timeouts öffnen kann, wird cat sie sofort schließen (da sie von /dev/null liest) und mit einem Statuscode von 0 beenden, der sich über bash und dann über timeout ausbreitet. Wenn bash vor dem angegebenen Timeout einen Verbindungserrors erhält, wird bash mit einem Exit-Code von 1 beendet, der ebenfalls zurückkehrt. Und wenn bash nicht in der Lage ist, eine Verbindung herzustellen und das angegebene Zeitlimit abgelaufen ist, wird bash timeout und mit einem Status von 124 beendet.

    Inhaltsverzeichnis:

    • Bash und timeout
      • Befehl
      • Beispiele
    • Mit nc
      • Befehl
      • RHEL 6 (nc-1.84)
        • Installation
        • Beispiele
      • RHEL 7 (nmap-ncat-6.40)
        • Installation
        • Beispiele
    • Bemerkungen

    Bash und timeout :

    Beachten Sie, dass timeout mit RHEL 6+ oder alternativ in GNU Coreutils 8.22 vorhanden sein sollte. Auf MacOS installieren Sie es mit brew install coreutils und verwenden Sie es als gtimeout .

    Befehl:

     $ timeout $TIMEOUT_SECONDS bash -c " 

    Wenn Sie den Host und den Port parametrisieren, müssen Sie sie wie oben beschrieben als ${HOST} und ${PORT} angeben. Benenne sie nicht einfach als $HOST und $PORT , also ohne die geschweiften Klammern; In diesem Fall wird es nicht funktionieren.

    Beispiel:

    Erfolg:

     $ timeout 2 bash -c " 

    Fehler:

     $ timeout 2 bash -c " 

    Wenn Sie den Exit-Status von bash beibehalten müssen,

     $ timeout --preserve-status 2 bash -c " 

    Verwenden von nc :

    Beachten Sie, dass eine rückwärts inkompatible Version von nc auf RHEL 7 installiert wird.

    Befehl:

    Beachten Sie, dass der folgende Befehl insofern einzigartig ist, als er für RHEL 6 und 7 identisch ist. Nur die Installation und die Ausgabe unterscheiden sich.

     $ nc -w $TIMEOUT_SECONDS -v $HOST $PORT  

    RHEL 6 (nc-1.84):

    Installation:

     $ sudo yum install nc 

    Beispiele:

    Erfolg:

     $ nc -w 2 -v canyouseeme.org 80  

    Fehler:

     $ nc -w 2 -v canyouseeme.org 81  

    Wenn der Hostname mehreren IPs zugeordnet ist, wird der obige fehlgeschlagene Befehl viele oder alle von ihnen durchlaufen. Beispielsweise:

     $ nc -w 2 -v microsoft.com 81  

    RHEL 7 (nmap-ncat-6.40):

    Installation:

     $ sudo yum install nmap-ncat 

    Beispiele:

    Erfolg:

     $ nc -w 2 -v canyouseeme.org 80  

    Fehler:

     $ nc -w 2 -v canyouseeme.org 81  

    Wenn der Hostname mehreren IPs zugeordnet ist, wird der obige fehlgeschlagene Befehl viele oder alle von ihnen durchlaufen. Beispielsweise:

     $ nc -w 2 -v microsoft.com 81  

    Bemerkungen:

    Das Argument -v ( --verbose ) und das echo $? Befehl sind natürlich nur zur Veranschaulichung.

    Mit netcat Sie prüfen, ob ein Port wie folgt geöffnet ist:

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

    Der Rückgabewert von nc ist erfolgreich, wenn der TCP-Port geöffnet wurde, und der Fehler (normalerweise der Rückkehrcode 1), wenn die TCP-Verbindung nicht hergestellt werden konnte.

    In Bash mit Pseudo-Device-Dateien für TCP / UDP-Verbindungen ist unkompliziert. Hier ist das Skript:

     #!/usr/bin/env bash SERVER=example.com PORT=80  

    Testen:

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

    Hier ist ein Liner (Bash-Syntax):

      

    Beachten Sie, dass einige Server durch Firewall-Schutz vor SYN-Flood-Angriffen geschützt werden können, sodass es zu einem TCP-Verbindungstimeout kommen kann (ca. 75 Sek.). Um das Timeout-Problem zu umgehen, versuchen Sie Folgendes:

     timeout 1 bash -c " 

    Siehe: Wie kann die TCP-Verbindung () Systemanruf-Timeout verringert werden?

    Während eine alte Frage, ich habe gerade mit einer Variante davon behandelt, aber keine der Lösungen hier war anwendbar, so fand ich ein anderes, und füge es für die Nachwelt hinzu. Ja, ich weiß, dass das OP gesagt hat, dass sie sich dieser Option bewusst sind und es ihnen nicht passte, aber für jeden, der danach kommt, könnte es sich als nützlich erweisen.

    In meinem Fall möchte ich die Verfügbarkeit eines lokalen apt-cacher-ng Dienstes von einem docker Build testen. Das bedeutet, dass absolut nichts vor dem Test installiert werden kann. Nein nc , nmap , expect , telnet oder python . perl jedoch vorhanden, zusammen mit den corebibliotheken, also habe ich das verwendet:

     perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))' 

    Wenn Sie ksh oder bash verwenden , unterstützen beide die IO-Umleitung zu / von einem Socket mit dem Konstrukt / dev / tcp / IP / PORT . In diesem Korn Shell Beispiel leite ich No-Op’s (:) Std-In von einem Socket um:

     W$ python -m SimpleHTTPServer & [1] 16833 Serving HTTP on 0.0.0.0 port 8000 ... W$ :  

    Die Shell gibt einen Fehler aus, wenn der Socket nicht geöffnet ist:

     W$ :  

    Sie können dies daher als Test in einer if- Bedingung verwenden:

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

    Das No-Op ist in einer Subshell, also kann ich std-err wegcasting, wenn die Umleitung von std-in fehlschlägt.

    Ich verwende oft / dev / tcp, um die Verfügbarkeit einer Ressource über HTTP zu überprüfen:

     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$ 

    Dieser Einzeiler öffnet den Dateideskriptor 9 zum Lesen von und Schreiben in den Socket, druckt das HTTP GET auf den Socket und verwendet cat zum Lesen aus dem Socket.

    Ich brauchte eine flexiblere Lösung für die Arbeit an mehreren Git-Repositories, also schrieb ich den folgenden sh-Code basierend auf 1 und 2 . Sie können Ihre Serveradresse anstelle von gitlab.com und Ihren Port anstelle von 22 verwenden.

     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 

    In einigen Fällen, in denen Tools wie curl, telnet, nc o nmap nicht verfügbar sind, haben Sie immer noch eine Chance mit 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 

    Wenn Sie nc möchten, aber keine Version haben, die -z , versuchen Sie es mit --send-only :

     nc --send-only    

    und mit Zeitüberschreitung:

     nc -w 1 --send-only    

    und ohne DNS-Lookup, wenn es eine IP ist:

     nc -n -w 1 --send-only    

    Es gibt die Codes als -z basierend auf zurück, ob es sich verbinden kann oder nicht.

    Was ist mit Netcat oder Nmap ?

    Ich nehme an, dass es zu spät für eine Antwort ist, und das ist vielleicht nicht gut, aber hier gehst du …

    Wie wäre es, es in eine While-Schleife mit einem Timer zu stecken? Ich bin eher ein Perl-Typ als Solaris, aber abhängig von der Shell, die Sie verwenden, sollten Sie in der Lage sein, Folgendes zu tun:

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

    Fügen Sie dann einfach ein Flag in die while-Schleife ein, so dass Sie das Timeout als Grund für einen Fehler angeben können, wenn das Zeitlimit überschritten wird.

    Ich vermute, dass das Telnet auch einen Timeout-Schalter hat, aber ich glaube, dass das oben beschriebene funktioniert.

    Ich brauchte ein kurzes Skript, das in Cron ausgeführt wurde und nicht ausgegeben wurde. Ich löse meine Probleme mit 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 

    Um es auszuführen, sollten Sie nmap installieren, da es kein standardmäßig installiertes Paket ist.

    Dies verwendet Telnet hinter den Kulissen und scheint auf Mac / Linux gut zu funktionieren. Es verwendet netcat nicht wegen der Unterschiede zwischen den Versionen auf linux / mac, und dies funktioniert mit einer Standardinstallation von mac.

    Beispiel:

     $ is_port_open.sh 80 google.com OPEN $ is_port_open.sh 8080 google.com CLOSED 

    is_port_open.sh

     PORT=$1 HOST=$2 TIMEOUT_IN_SEC=${3:-1} VALUE_IF_OPEN=${4:-"OPEN"} VALUE_IF_CLOSED=${5:-"CLOSED"} function eztern() { if [ "$1" == "$2" ] then echo $3 else echo $4 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 

    Überprüfen Sie Ports mit bash

    Beispiel

     $ ./test_port_bash.sh 192.168.7.7 22 

    der Port 22 ist offen

    Code

     HOST=$1 PORT=$2 exec 3> /dev/tcp/${HOST}/${PORT} if [ $? -eq 0 ];then echo "the port $2 is open";else echo "the port $2 is closed";fi 

    Aufbauend auf der am häufigsten gewählten Antwort gibt es hier eine function, die darauf wartet, dass zwei Ports geöffnet sind, auch mit einer Zeitüberschreitung. Beachten Sie die beiden offenen Ports 8890 und 1111 sowie die max_attempts (1 pro Sekunde).

     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 } 

    nmap-ncat, um den lokalen Port zu testen, der noch nicht verwendet wird


     availabletobindon() { port="$1" nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q 'Idle timeout expired' return "$?" } 

    Die Antwort lag bei Expect. Wir haben ein einfaches Skript geschrieben, das mit einer Zeitüberschreitung von 8 Sekunden ein Telnet an den von uns benötigten Port sendet. Es gibt viele Beispiele zur Auswahl.

    Wir stützen uns auf diesen Beitrag: http://www.unix.com/shell-programming-scripting/146568-expect-telnet-testing-tacacs-cisco.html