Uzak TCP bağlantı noktasının kabuk komut dosyasından açık olup olmadığını sınama


299

Belirli bir TCP bağlantı noktası uzak bir sunucuda, bir kabuk komut dosyası içinde açık olup olmadığını düzgün sınamak için hızlı ve basit bir yöntem arıyorum.

Telnet komutuyla yapmayı başardım ve bağlantı noktası açıldığında iyi çalışıyor, ancak açılmadığında zaman aşımına uğramıyor ve sadece orada asılı ...

İşte bir örnek:

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

Ben ya da daha iyi bir yol, ya da örneğin 8 saniyenin altında bağlanmazsa telnet zaman aşımı zorlamak için bir yol ve Shell (dönüş kodu ya da stdout dize) yakalayabileceğiniz bir şey dönmek gerekir.

IO :: Socket :: INET modülünü kullanan ve bir bağlantı noktasını test eden başarılı bir komut dosyası yazdıran, ancak mümkünse Perl kullanmaktan kaçınmak isteyen Perl yöntemini biliyorum.

Not: Sunucum budur (bunu çalıştırmam gereken yer)

SunOS 5.10 Genel_139556-08 i86pc i386 i86pc


Netcat veya Nmap ne olacak ?
Jeremiah Willcock

Cevap Expect ile yalan söyledi. İhtiyacımız olan portta 8 saniyelik bir zaman aşımı ile bir telnet gönderen basit bir komut dosyası yazdık. Aralarından seçim yapabileceğiniz çok sayıda örnek var. Bizimki bu yazıya dayanıyoruz: unix.com/shell-programming-scripting/…
Yanick Girouard

1
github.com/monitoring-plugins/monitoring-plugins adresinden check_tcp bunu, dizeleri girmek ve beklenen bir cevabı kontrol etmek de dahil olmak üzere yapabilir.

Yanıtlar:


453

B. Rodos'un işaret ettiği ncgibi, işi yapacak. Kullanmanın daha kompakt bir yolu:

nc -z <host> <port>

Bu şekilde nc, yalnızca bağlantı noktasının açık olup olmadığını kontrol eder, başarılı olduğunda 0, başarısızlıkta 1 ile çıkar.

Hızlı bir etkileşimli kontrol için (5 saniye zaman aşımı ile):

nc -z -v -w5 <host> <port>

48
centos7 varsayılan olarak nmap netcat kullanır ve -z seçeneği yoktur.
jolestar

7
Bu RHEL / Centos'ta çalışmaz. Bu dağıtımlar için yapmanız gerekenler: nc -vn <host> <port>
Justin Dennahower

2
FWIW, cevabımı RHEL 6 ve RHEL 7 için ayrı ayrı geçerli olan bir örnekle tamamen elden geçirdim .
Acumenus

4
en azından Mac'te, temel olarak bir okuma zaman aşımı işlevi gören zaman -G#aşımından ayrı olarak / buna ek olarak bir bağlantı zaman aşımı ayarlamak için eklemeniz gerekebilir -w#.
Doktor J

1
@jolestar -zSeçeneği almak için Centos 7'de Ncat'i manuel olarak yükseltebilirsiniz . Dikkate almak isteyebilirsiniz: unix.stackexchange.com/questions/393762/…
Damien Ó Ceallaigh

151

-zVe -w TIMEOUTseçenekleri ile yapmak yeterince kolaydır nc, ancak tüm sistemler ncyüklenmemiştir. Yeterince bash sürümünüz varsa, bu işe yarayacaktır:

# 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

Burada olan timeout, alt komutunu çalıştıracak ve belirtilen zaman aşımı süresi içinde çıkmazsa (yukarıdaki örnekte 1 saniye) öldürecek olmasıdır. Bu durumda bashalt komut ve belirtilen sunucu ve bağlantı noktası bağlantısını denemek ve açmak için özel / dev / tcp işlemesini kullanır . Eğer bashzaman aşımı süresi içinde bağlantı açabilir catolacak sadece yakın hemen ( 's den okuma beri /dev/nulldurum koduyla ve çıkış) ait 0olan yayılması olacak bashve daha sonra timeout. Eğer bashbelirtilen zaman aşımı öncesinde bir bağlantı hatası buluyor, sonra bash1 çıkış koduyla çıkılacak timeoutda dönecektir. Ve bash bir bağlantı kuramazsa ve belirtilen zaman aşımı süresi dolarsa,timeoutbash124 statüsünde öldürecek ve çıkacak .


1
/dev/tcpLinux dışındaki sistemlerde kullanılabilir? Özellikle Mac'ler ne olacak?
Peter

8
/ Dev / tcp olayı bash'ın bir özelliğidir, yani evet. Ancak
mac'larda

1
@onlynone - Görünüşe göre timeoutFreeBSD'de mevcut değil ve eski Ubuntu kutumda kurulabilir bir paket, ancak varsayılan olarak orada değil. Zaman aşımı veya netcat gibi üçüncü taraf araçları olmadan, bunu sadece bash'da yapmanın bir yolu olsaydı harika olurdu.
Graham

3
Sadece belirtmek istedim timeoutgörünür GNU coreutils bir parçası olmak ve homebrew ile Mac'ler üzerinde kurulabilir: brew install coreutils. Daha sonra olarak kullanılabilir olacak gtimeout.
onlynone

1
@Wildcard Ana bilgisayar adlarına destek eklenmiş olsa da, bash değişiklik günlüğü önerir . bash-2.04-develbash-2.05-alpha1
Acumenus

110

TOK:

  • Bash ve timeout
    • komuta
    • Örnekler
  • kullanma nc
    • komuta
    • RHEL 6 (nc-1.84)
      • Kurulum
      • Örnekler
    • RHEL 7 (nmap-ncat-6.40)
      • Kurulum
      • Örnekler
  • Uyarılar

Bash ve kullanarak timeout:

timeoutRHEL 6+ ile mevcut olması veya GNU coreutils 8.22'de bulunması gerektiğini unutmayın . MacOS'ta kullanarak yükleyin brew install coreutilsve olarak kullanın gtimeout.

Komut:

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

Ana bilgisayarı ve bağlantı noktasını parametrelendirirseniz, bunları yukarıda olduğu gibi ${HOST}ve belirttiğinizden emin olun ${PORT}. Bunları yalnızca $HOSTve diğer bir $PORTdeyişle parantez olmadan belirtmeyin ; bu durumda çalışmaz.

Misal:

Başarı:

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

Başarısızlık:

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

Sitesinin çıkış durumunu korumanız gerekiyorsa bash,

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

Kullanma nc:

ncRHEL 7'ye geriye dönük uyumsuz bir sürümün yüklendiğini unutmayın.

Komut:

Aşağıdaki komutun hem RHEL 6 hem de 7 için aynı olması bakımından benzersiz olduğunu unutmayın. Sadece kurulum ve çıkış farklıdır.

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

RHEL 6 (nc-1.84):

Kurulum:

$ sudo yum install nc

Örnekler:

Başarı:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
Başarısızlık:
$ 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

Ana bilgisayar adı birden çok IP ile eşleşirse, yukarıdaki başarısız komut bunların birçoğu veya tümü arasında geçiş yapar. Örneğin:

$ 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):

Kurulum:

$ sudo yum install nmap-ncat

Örnekler:

Başarı:
$ 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
Başarısızlık:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1

Ana bilgisayar adı birden çok IP ile eşleşirse, yukarıdaki başarısız komut bunların birçoğu veya tümü arasında geçiş yapar. Örneğin:

$ 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

Uyarılar:

-v( --verbose) Bağımsız değişken ve echo $?komutu sadece gösterim amacıyla elbette.


3
timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?harika bir nokta!
ipeacocks

eklemek 2>&1değil yankı durum için result_test=$(nc -w 2 $ip_addreess 80 </dev/null 2>&1 ; echo $?)
Sanya Snex

56

İle netcatbir portun açık olup olmadığını kontrol edebilirsiniz:

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

ncTCP bağlantı noktası açılırsa dönüş değeri başarılı olur ve TCP bağlantısı kurulamadıysa hata (genellikle dönüş kodu 1) olur.

ncBunu denediğinizde bazı sürümleri kilitlenir, çünkü dosya sonunu aldıktan sonra bile soketlerinin gönderici yarısını kapatmazlar /dev/null. Kendi Ubuntu dizüstü bilgisayarımda (18.04), netcat-openbsdyüklediğim netcat sürümü bir geçici çözüm sunuyor: -Nhemen sonuç almak için seçenek gerekli:

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

1
Bayrağı ncdesteklemeyen lezzetler için harika çalışıyor -w.
David Dossot

5
teşekkürler - ayrıca desteksiz nc sürümleri için -zçalışır - RHEL / CentOS 7 üzerinde çalışır, örneğin
Andrew

1
Her ne kadar bu yaklaşım iyi olsa da -w, bir komut dosyasında kullanıldığında komutun on saniyeden fazla askıya alınamaması gerekir. Ben de içeren bir cevap yazdım -w.
Acumenus

2
+1 bu harika çünkü nc standart olarak alp linux ve ubuntu ile birlikte geliyor. muhtemelen diğerleri. Eğer uzaktayken ve yükleyemiyorsanız ekstra yüklemeye gerek yoktur. Bunun için teşekkürler! Ben ekleyebilirim,nc host port -w 2 && echo it works
std''OrgnlDave

2
Ben tercih ederim nc -vz localhost 3306. Daha ayrıntılı bir çıktı verir. Sadece Mac'te denedim.
EFreak

29

Bash'de TCP / UDP bağlantıları için sözde aygıt dosyaları kullanmak basittir. İşte senaryo:

#!/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

Test yapmak:

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

İşte bir astar (Bash sözdizimi):

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

Bazı sunucuların SYN sel saldırılarına karşı güvenlik duvarı korumalı olabileceğini unutmayın, bu nedenle TCP bağlantı zaman aşımı (~ 75 saniye) yaşayabilirsiniz. Zaman aşımı sorununu çözmek için şunu deneyin:

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

Bkz: TCP connect () sistem çağrısı zaman aşımı nasıl azaltılır?


1
@ABB Bu, sunucunun herhangi bir SYN sel saldırısını önlemek için herhangi bir yanıt vermeyen güvenlik duvarı yapılandırmasıyla ilgilidir. Koşu telnet canyouseeme.org 81da takılıyor. Bu, muhtemelen bash olarak kodlanmış zaman aşımı sınırlarınız tarafından kontrol edilir. Bkz: TCP connect () sistem çağrısı zaman aşımını azaltma .
kenorb

Parametrelemesine için, şimdi belirtmek gerekir gibi görünüyor $SERVERve $PORTparantezi ile, en azından olarak ${SERVER}ve ${PORT}.
Acumenus

13

Birden fazla git depolarında çalışmak için daha esnek bir çözüme ihtiyacım vardı, bu yüzden aşağıdaki sh kodunu 1 ve 2'ye göre yazdım . Gitlab.com yerine sunucu adresinizi ve 22 yerine portunuzu kullanabilirsiniz.

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

1
Teşekkürler! /Etc/rc.local için hayatımı kolaylaştırıyor
Shahin Khaled

10

Ksh veya bash kullanıyorsanız , her ikisi de / dev / tcp / IP / PORT yapısını kullanarak bir sokete G / Ç yönlendirmesini destekler . Bu ise Korn kabuk Örneğin ben yönlendirme am no-op en ( : ) std-bir soketten:

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

Yuva açık değilse kabuk bir hata yazdırır:

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

Bu nedenle bunu bir if durumunda test olarak kullanabilirsiniz :

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

No-op bir alt kabuktadır, böylece std-in yönlendirme başarısız olursa std-err'i atabilirim.

Genellikle HTTP üzerinden bir kaynağın kullanılabilirliğini kontrol etmek için / dev / tcp kullanıyorum :

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$ 

Bu tek astar soketten okumak ve sokete yazmak için dosya tanımlayıcısını 9 açar , HTTP GET'i sokete yazdırır ve soketten catokumak için kullanır .


1
@ABB Bağlantı noktası yanıt vermiyorsa, örneğin filtrelendiğinde veya IP'de hiçbir şey olmadığında uzun süre askıda kaldığını kastediyorsunuz. Bağlantı noktası aktif olarak bağlantıyı reddederse, kapalı bir bağlantı noktası gecikmeye neden olmaz. Birçok amaç için bu oldukça kabul edilebilir.
mc0e

Bu teknik daha önce kenorb tarafından verilen bir cevapta bu cevaptan önce gönderilmişti . Her neyse, daha büyük nokta, liman yanıt vermiyorsa uzun süre askıda kalmasıdır. Örneğin, deneyin </dev/tcp/canyouseeme.org/80ve ardından </dev/tcp/canyouseeme.org/81.
Acumenus

9

Eski bir soru olsa da, bunun bir çeşidi ile uğraştım, ancak buradaki çözümlerin hiçbiri uygulanabilir değildi, bu yüzden başka bir tane buldum ve bunu gelecek nesiller için ekliyorum. Evet, OP'nin bu seçeneğin farkında olduklarını söylediğini ve onlara uygun olmadığını biliyorum, ancak daha sonra takip eden herkes için yararlı olabilir.

Benim durumumda, bir derlemeden yerel bir apt-cacher-nghizmetin kullanılabilirliğini test etmek istiyorum docker. Bu, testten önce kesinlikle hiçbir şeyin kurulamayacağı anlamına gelir. Hayır nc, nmap, expect, telnetveya python. perlAncak çekirdek kütüphaneleri ile birlikte, bu yüzden bunu kullandım:

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

7

bash kullanarak portları kontrol et

Misal

$ ./test_port_bash.sh 192.168.7.7 22

22 numaralı bağlantı noktası açık

kod

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

6

Kıvrılma, telnet, nc o nmap gibi araçların kullanılamadığı bazı durumlarda hala wget yapma şansınız var

if [[ $(wget -q -t 1 --spider --dns-timeout 3 --connect-timeout 10  host:port; echo $?) -eq 0 ]]; then echo "OK"; else echo "FAIL"; fi

4

Kullanmak istiyor ncancak destekleyen bir sürümünüz yoksa şunları -zkullanmayı deneyin --send-only:

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

ve zaman aşımı ile:

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

ve bir IP ise DNS araması olmadan:

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

Bağlanıp -zbağlanamadığına bağlı olarak kodları döndürür .


1

Bir cevap için çok geç olduğunu tahmin ediyorum ve bu iyi bir yanıt olmayabilir, ama işte gidiyorsunuz ...

Bir çeşit zamanlayıcı ile bir while döngüsünün içine koymaya ne dersiniz? Ben Solaris'ten daha çok bir Perl adamıyım, ancak kullandığınız kabuğa bağlı olarak, aşağıdaki gibi bir şey yapabilmelisiniz:

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

Ve sonra while döngüsüne bir bayrak ekleyin, böylece tamamlanmadan önce zaman aşımına uğrarsa, zaman aşımını başarısızlık nedeni olarak gösterebilirsiniz.

Telnet'in de bir zaman aşımı anahtarına sahip olduğundan şüpheleniyorum, ancak başımın üstünde, yukarıdakilerin işe yarayacağını düşünüyorum.


1

Ben cron çalıştırıldı ve çıktı olmayan kısa komut dosyası gerekiyordu. Nmap kullanarak sorunumu çözdüm

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

Çalıştırmak için nmap'i yüklemeniz gerekir, çünkü varsayılan yüklü paket değildir.


nmap'ın grepable çıktısı -oG -stdout'a göndermek için de yararlı olabilir . (grep'in biraz modifikasyona ihtiyacı olacak)
Gert van den Berg

0

Bu, perde arkasında telnet kullanıyor ve mac / linux'da iyi çalışıyor gibi görünüyor. Linux / mac üzerindeki sürümler arasındaki farklar nedeniyle netcat kullanmaz ve bu, varsayılan bir mac kurulumuyla çalışır.

Misal:

$ 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 

0

En yüksek oyu alan cevaba dayanarak, iki bağlantı noktasının da zaman aşımı ile açık olmasını bekleyen bir işlev var. Açık olan iki portun, 8890 ve 1111'in yanı sıra max_attempts'e (saniyede 1) dikkat edin.

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
}

-1

nmap-ncat, kullanımda olmayan yerel bağlantı noktasını test etmek için


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

80 numaralı limanımın açık olduğunu söylemiyor.
totoro
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.