it-swarm.com.de

Testen Sie, ob der Remote-Port TCP über ein Shell-Skript geöffnet ist

Ich suche nach einer schnellen und einfachen Methode, um zu testen, ob ein bestimmter TCP -Port auf einem Remote-Server in einem Shell-Skript geöffnet ist.

Ich habe es mit dem Telnet-Befehl geschafft und es funktioniert einwandfrei, wenn der Port geöffnet ist, aber es scheint keine Zeitüberschreitung zu geben, wenn dies nicht der Fall ist, und hängt einfach dort ...

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 eine bessere Methode oder eine Methode, um das Timeout für Telnet zu erzwingen, wenn die Verbindung nicht in weniger als 8 Sekunden hergestellt werden kann, und etwas zurückzugeben, das ich in Shell abfangen kann (Rückkehrcode oder Zeichenfolge 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 wenn möglich lieber auf Perl verzichten möchte.

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

SunOS 5.10 Generic_139556-08 i86pc i386 i86pc

279
Yanick Girouard

Wie von B. Rhodes angedeutet, wird nc die Arbeit erledigen. Eine kompaktere Art, es zu benutzen:

nc -z <Host> <port>

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

Für eine schnelle interaktive Überprüfung (mit einer Zeitüberschreitung von 5 Sekunden):

nc -z -v -w5 <Host> <port>
426
Alessio Gaeta

Es ist einfach genug, die Optionen -z und -w TIMEOUT auf nc zu setzen, aber nicht auf allen Systemen ist nc installiert. Wenn Sie eine ausreichend aktuelle Version von bash haben, funktioniert Folgendes:

# 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 hier passiert, ist, dass timeout den Unterbefehl ausführt und beendet, wenn er nicht innerhalb des angegebenen Zeitlimits (1 Sekunde im obigen Beispiel) beendet wird. In diesem Fall ist bash der Unterbefehl und verwendet sein spezielles / dev/tcp-Behandlung , um eine Verbindung zu dem angegebenen Server und Port herzustellen. Wenn bash die Verbindung innerhalb der Zeitüberschreitung öffnen kann, wird cat sie sofort schließen (da sie von /dev/null liest) und mit dem Statuscode 0 beenden, der sich ausbreitet durch bash und dann timeout. Wenn bash vor dem angegebenen Zeitlimit einen Verbindungsfehler erhält, wird bash mit dem Beendigungscode 1 beendet, und timeout wird ebenfalls zurückgegeben. Und wenn bash keine Verbindung herstellen kann und das angegebene Zeitlimit abläuft, wird timeoutbash beendet und mit dem Status 124 beendet.

133
onlynone

Inhaltsverzeichnis:

  • Mit bash und timeout
    • Befehl
    • Beispiele
  • nc Verwenden
    • Befehl
    • RHEL 6 (nc-1,84)
      • Installation
      • Beispiele
    • RHEL 7 (nmap-ncat-6.40)
      • Installation
      • Beispiele
  • Bemerkungen

Mit bash und timeout:

Beachten Sie, dass timeout in RHEL 6+ vorhanden sein sollte oder alternativ in GNU coreutils 8.22 zu finden ist. Installieren Sie es unter MacOS mit brew install coreutils und verwenden Sie es als gtimeout.

Befehl:

$ timeout $TIMEOUT_SECONDS bash -c "</dev/tcp/${Host}/${PORT}"; echo $?

Wenn Sie den Host und den Port parametrisieren, müssen Sie diese wie oben angegeben als ${Host} und ${PORT} angeben. Geben Sie sie nicht nur als $Host und $PORT an, d. H. Ohne geschweifte Klammern. In diesem Fall funktioniert es nicht.

Beispiel:

Erfolg:

$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/80"; echo $?
0

Fehler:

$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
124

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

$ timeout --preserve-status 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
143

nc verwenden:

Beachten Sie, dass eine abwä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. Es sind nur die Installation und die Ausgabe, die unterschiedlich sind.

$ nc -w $TIMEOUT_SECONDS -v $Host $PORT </dev/null; echo $?

RHEL 6 (NC-1,84):

Installation:

$ Sudo yum install nc

Beispiele:

$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
nc: connect to canyouseeme.org port 81 (tcp) timed out: Operation now in progress
1

Wenn der Hostname mehreren IPs zugeordnet ist, werden mit dem oben genannten fehlgeschlagenen Befehl viele oder alle durchlaufen. Zum Beispiel:

$ nc -w 2 -v Microsoft.com 81 </dev/null; echo $?
nc: connect to Microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to Microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to Microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to Microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to Microsoft.com port 81 (tcp) timed out: Operation now in progress
1

RHEL 7 (nmap-ncat-6.40):

Installation:

$ Sudo yum install nmap-ncat

Beispiele:

$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connected to 52.202.215.126:80.
Ncat: 0 bytes sent, 0 bytes received in 0.22 seconds.
0
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1

Wenn der Hostname mehreren IPs zugeordnet ist, werden mit dem oben genannten fehlgeschlagenen Befehl viele oder alle durchlaufen. Zum Beispiel:

$ nc -w 2 -v Microsoft.com 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection to 104.43.195.251 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.100.122.175 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.96.52.53 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 191.239.213.197 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection timed out.
1

Bemerkungen:

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

98
Acumenus

Mit netcat können Sie überprü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 ein Fehler (normalerweise der Rückgabecode 1), wenn die TCP -Verbindung nicht hergestellt werden konnte.

Einige Versionen von nc hängen, wenn Sie dies versuchen, da sie die sendende Hälfte ihres Sockets nicht schließen, selbst nachdem sie das Dateiende von /dev/null empfangen haben. Auf meinem eigenen Ubuntu-Laptop (18.04) bietet die netcat-openbsd -Version von Netcat, die ich installiert habe, eine Problemumgehung: Die -N -Option ist erforderlich, um ein sofortiges Ergebnis zu erhalten:

nc -N my.example.com 80 < /dev/null
50
Brandon Rhodes

In Bash ist die Verwendung von Pseudo-Gerätedateien für TCP/UDP-Verbindungen unkompliziert. Hier ist das Skript:

#!/usr/bin/env bash
SERVER=example.com
PORT=80
</dev/tcp/$SERVER/$PORT
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

Testen:

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

Hier ist ein Einzeiler (Bash-Syntax):

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

Beachten Sie, dass einige Server durch eine Firewall vor SYN-Flood-Angriffen geschützt sein können. Daher kann es zu einem TCP -Verbindungs-Timeout (~ 75 Sek.) Kommen. Versuchen Sie, um das Timeout-Problem zu umgehen:

timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.

Siehe: So verringern Sie das Zeitlimit für TCP connect () - Systemaufrufe?

26
kenorb

Ich brauchte eine flexiblere Lösung für die Arbeit an mehreren Git-Repositorys, 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
11
Ahmad Yoosofan

Wenn Sie ksh oder bash verwenden, unterstützen beide die IO -Umleitung zu/von einem Socket mithilfe von / dev/tcp/IP/PORT konstruieren. In diesem Korn Shell Beispiel leite ich No-Ops (:) std-in von einem Socket um:

W$ python -m SimpleHTTPServer &
[1]     16833
Serving HTTP on 0.0.0.0 port 8000 ...
W$ : </dev/tcp/127.0.0.1/8000

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

W$ : </dev/tcp/127.0.0.1/8001
ksh: /dev/tcp/127.0.0.1/8001: cannot open [Connection refused]

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 befindet sich in einer Subshell, sodass ich std-err wegwerfen kann, wenn die std-in-Umleitung 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 Dateideskriptor 9 zum Lesen von und Schreiben in den Socket, druckt HTTP GET in den Socket und verwendet cat zum Lesen aus der Steckdose.

10
merebagatelle

Während einer alten Frage habe ich mich gerade mit einer Variante davon befasst, aber keine der Lösungen hier war anwendbar, also habe ich eine andere gefunden und füge sie für die Nachwelt hinzu. Ja, ich weiß, dass das OP sagte, sie wüssten von dieser Option und es passte nicht zu ihnen, aber für jeden, der danach folgt, könnte sie sich als nützlich erweisen.

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

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

In einigen Fällen, in denen Tools wie Curl, Telnet, Nc oder 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
6
PRF

überprüfen Sie die 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
5
krbu

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

nc --send-only <IP> <PORT> </dev/null

und mit timeout:

nc -w 1 --send-only <IP> <PORT> </dev/null

und ohne DNS-Lookup, wenn es sich um eine IP handelt:

nc -n -w 1 --send-only <IP> <PORT> </dev/null

Es gibt die Codes als -z zurück, basierend darauf, ob eine Verbindung hergestellt werden kann oder nicht.

4
Chris Mendez

Ich vermute, es ist zu spät für eine Antwort, und dies könnte keine gute sein, aber los geht's ...

Was ist, wenn Sie es in eine while-Schleife mit einem Timer einfügen? Ich bin eher ein Perl-Typ als Solaris, aber je nachdem, welche Shell 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, damit Sie das Zeitlimit als Grund für den Fehler angeben können, wenn das Zeitlimit vor dem Abschluss abläuft.

Ich vermute, dass das Telnet auch einen Timeout-Schalter hat, aber ich denke, dass das oben Genannte funktionieren wird.

1
Red Thomas

Ich brauchte ein kurzes Skript, das in Cron ausgeführt 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 nicht das standardmäßig installierte Paket ist.

1

Dies nutzt Telnet hinter den Kulissen und scheint unter Mac/Linux einwandfrei zu funktionieren. Aufgrund der Unterschiede zwischen den Versionen unter Linux/Mac wird Netcat nicht verwendet. Dies funktioniert bei einer standardmäßigen Mac-Installation.

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' "[email protected]"; }

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 
0
Brad Parks

Aufbauend auf der am häufigsten gewählten Antwort können Sie hier darauf warten, dass zwei Ports geöffnet sind, wobei auch eine Zeitüberschreitung auftritt. 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
}