Sprawdź, czy port w systemie zdalnym jest osiągalny (bez telnet)

353

W dawnych czasach telnetsprawdzaliśmy, czy port na zdalnym hoście był otwarty: telnet hostname portpróbował połączyć się z dowolnym portem na dowolnym hoście i dać ci dostęp do surowego strumienia TCP.

Obecnie w systemach, na których pracuję, nie ma zainstalowanego Telnet (ze względów bezpieczeństwa), a wszystkie połączenia wychodzące do wszystkich hostów są domyślnie blokowane. Z czasem łatwo stracić orientację, które porty są otwarte dla których hostów.

Czy istnieje inny sposób sprawdzenia, czy port w systemie zdalnym jest otwarty - przy użyciu systemu Linux z zainstalowaną ograniczoną liczbą pakietów i telnetnie jest dostępny?

Steve HHH
źródło
Miałem ten sam problem. Odpowiedź @Subhranath Chunder poniżej pomogła. Jednak później dowiedziałem się, że instalacja Telnetu była niewielką sprawą brew install telnet. Spodziewam się, że użytkownicy Linuxa mogą zrobić to samo z yumi apt-get.
Mig82

Odpowiedzi:

277

Bash od dłuższego czasu ma dostęp do portów TCP i UDP . Ze strony podręcznika:

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

Możesz więc użyć czegoś takiego:

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

Taa Daa!

lornix
źródło
Wydaje się, że działa to również w MinGW . Na przykład zdalny serwer VNC na 192.168.2.100 odpowiada „RFB 003.008”, używając „cat </dev/tcp/192.168.2.100/5900”.
Peter Mortensen
1
@lornix, ok, ale w tym przypadku muszę uzyskać ten sam wynik z użyciem nc bez opcji -z, ale nadal nie działa: # nc -v -w5 127.0.0.1 18080 Połączenie z portem 127.0.0.1 18080 [tcp / *] się udało! # cat </dev/tcp/127.0.0.1/18080 Po prostu zawiesza się bez żadnego wyniku. Chcę tylko zrozumieć, kiedy mogę użyć opcji „/ dev / tcp / host / port”
Alexandr
5
@Alexandr ... właściwie „zawiesza się bez żadnego rezultatu” to zachowanie, którego się prawie spodziewałem. kot czeka na dane wejściowe. nc ma dodatkowe inteligentne funkcje umożliwiające wykrywanie braku danych w toku i przestaje próbować. kot nie jest tak mądry. Spróbuj cat < /dev/tcp/localhost/22, powinieneś dostać swój nagłówek sshd. Najwyraźniej twój proces na porcie 18080 czeka na coś przed wejściem. Port 22 ( ssh ) wita Cię swoją wersją i tym podobne. Wypróbuj to!
lornix
1
@lornix, dziękuję bardzo za wyjaśnienie! Teraz ograniczenie jest jasne. Myślę, że używanie nc powinno być preferowanym sposobem sprawdzania portów.
Alexandr
2
Było to niezwykle pomocne podczas pracy z kontenerem dokującym, w którym nic nie zainstalowano. Był w stanie szybko sprawdzić, czy kontener miał dostęp do DB bez konteneryzacji przez DNS. Przykład: cat </ dev / tcp / hostname / 5432
Michael Hobbs
404

Miły i pełny! Ze stron podręcznika.
Pojedynczy port:

nc -zv 127.0.0.1 80

Wiele portów:

nc -zv 127.0.0.1 22 80 8080

Zakres portów:

nc -zv 127.0.0.1 20-30
Subhranath Chunder
źródło
6
Dzięki, to chyba najlepsza odpowiedź. ;-)
lpapp
6
Zostało zawieszone, gdy wypróbowano na Ubuntu 14.04 (Trusty Tahr) dla zdalnego serwera (ta sama sieć LAN) dla zamkniętych portów (upłynął limit czasu po 127 sekundach) - w związku z tym nie jest to bardzo przydatne w skryptach. Działa to jednak w przypadku usługi z otwartym portem. Rozwiązaniem może być opcja „-w2”.
Peter Mortensen
6
Użyj opcji -u dla portów UDP.
Efren
8
W wersji 6.4 programu ncat -z nie jest rozpoznawany. Byłem w stanie obejść się bez z
smishra
5
Możesz sprawdzić wiele zakresów za pomocą: nc -zv 127.0.0.1 22,80,8080,20-30,443-446(wersja nc: 1.107-4).
bobbel
102

Netcat to przydatne narzędzie:

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

Wyjdzie, 0jeśli port 123 jest otwarty i 1jeśli jest zamknięty.

thnee
źródło
To jest o wiele bardziej elegancka i skryptowalna odpowiedź niż moja własna. Dla mnie niefortunne jest to, że świadomi bezpieczeństwa sysadmini, którzy odmówili, telnetrównież odmówili nc(choć - o dziwo - nie curllub wget).
Steve HHH,
Tak, to jest całkowicie arbitralne i głupie.
wtorek,
3
Niech FORzaczną się oświadczenia!
Chad Harrison
1
Zostało zawieszone, gdy wypróbowano na Ubuntu 14.04 (Trusty Tahr) dla zdalnego serwera (ta sama sieć LAN) dla zamkniętych portów (upłynął limit czasu po około 127 sekundach) - dlatego nie jest bardzo odpowiednie w skryptach. Działa to jednak w przypadku usługi, która ma otwarty port, zwracając wartość 0. Użycie opcji „-w2” może być rozwiązaniem.
Peter Mortensen
1
Myślę, -G 2że bardziej odpowiednie byłoby przekroczenie limitu czasu TCP
AB
58

Najprostsza metoda bez użycia innego narzędzia, takiego jak socat, jest opisana w powyższej odpowiedzi @ lornix. To po prostu dodać faktyczny przykład wykorzystania urządzenia psuedo /dev/tcp/...w Bash, jeśli chcesz, powiedzmy, przetestować, czy inny serwer ma dany port dostępny za pośrednictwem wiersza poleceń.

Przykłady

Powiedz, że mam hosta w mojej sieci o nazwie 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

Powodem, dla którego chcesz zawijać echo > /dev/...nawiasy w ten sposób, (echo > /dev/...)jest to, że jeśli tego nie zrobisz, to przy testach połączeń, które nie działają, pojawią się tego rodzaju wiadomości.

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

Nie można ich po prostu przekierować, /dev/nullponieważ pochodzą one z próby zapisania danych na urządzeniu /dev/tcp. Przechwytujemy więc wszystkie dane wyjściowe w ramach podrzędnego polecenia, tj. (...cmds...)I przekierowujemy dane wyjściowe tego polecenia.

slm
źródło
To jest wspaniałe. Żałuję, że nie zagłosuje na szczycie. Przeczytałem tylko tę stronę, ponieważ przypadkowo przewinąłem ją przed zamknięciem.
Still.Tony
@ Okuma.Tony - tak, to zawsze jest problem z Q, które mają wiele odpowiedzi 8-). Dziękujemy za opinie, ale to doceniamy.
slm
46

Odkryłem, że curlmoże to zrobić zadanie w podobny sposób telnet, a curlnawet powie ci, jakiego protokołu oczekuje słuchacz.

Skonstruuj identyfikator URI HTTP z nazwy hosta i portu jako pierwszy argument curl. Jeśli curlmożna się połączyć, zgłosi niezgodność protokołu i zakończy działanie (jeśli nasłuchiwanie nie jest usługą internetową). Jeśli curlnie można się połączyć, upłynie limit czasu.

Na przykład port 5672 na hoście 10.0.0.99 jest zamknięty lub zablokowany przez zaporę:

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

Jednak z innego systemu można uzyskać dostęp do portu 5672 na hoście 10.0.0.99 i wydaje się, że działa on jako detektor AMQP.

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

Ważne jest, aby rozróżniać różne komunikaty: pierwsza awaria była spowodowana brakiem curlpołączenia z portem. Druga porażka to test powodzenia, choć curloczekiwany jest odbiornik HTTP zamiast odbiornika AMQP.

Steve HHH
źródło
5
Jeśli curl nie jest dostępny, może być wget. wget -qS -O- http://ip.add.re.ss:portpowinien skutecznie zrobić to samo.
CVn
4
Działa to nawet z nazwą hosta, np. curl myhost:22.
에이 바
To może być niepoprawne. Mam uruchomioną usługę tomcat, ale pojawia się błąd 404. # curl -k 192.168.194.4:6443 <html><head> <title> Apache Tomcat / 7.0.34 - Raport błędów </title> <style> <! - H1 --- HR {kolor: # 525D76;} -> </style> </head><body> <h1> Status HTTP 404 - / </h1> <HR size = "1" noshade = "noshade"> <p> <b> typ </b> Raport o stanie </p> <p> <b> komunikat </b> <u>/</u></p><p> <b> opis </b> <u> Żądany zasób jest niedostępny. </u> </p> <HR size = "1" noshade = "noshade"> <h3> Apache Tomcat / 7.0.34 </h3> </body> </html>
Zobacz mój post z podobnym podejściem.
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!

Mam nadzieję, że to rozwiąże twój problem :)

Mohammad Shahid Siddiqui
źródło
1
Tak, jest to lepsze - prawie natychmiast upływa limit czasu dla zamkniętych portów.
Peter Mortensen
1
Czy to zawsze używa TCP, czy jest sposób, aby sprawdzić UDP?
kmoe
6

Walczyłem cały dzień, ponieważ żadna z tych odpowiedzi nie działała dla mnie. Problem polega na tym, że najnowsza wersja ncnie ma już -zflagi, podczas gdy bezpośredni dostęp przez TCP (zgodnie z @lornix i @slm) nie działa, gdy host jest nieosiągalny. W końcu znalazłem tę stronę , na której w końcu znalazłem nie jeden, ale dwa działające przykłady:

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

    ( -wflaga ustala limit czasu i </dev/nullzastępuje -zflagę)

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

    ( timeoutpolecenie zajmuje limit czasu, a reszta pochodzi z @slm)

Następnie po prostu użyj &&i / lub ||(lub nawet $?), aby wyodrębnić wynik. Mam nadzieję, że ktoś uzna te informacje za przydatne.

Azukikuru
źródło
4

Łącząc odpowiedzi z @kenorb i @Azukikuru, możesz przetestować port otwarty / zamknięty / firewalled.

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

Inne podejście z zawinięciem do osiągnięcia dowolnego portu

curl telnet://127.0.0.1:22
Miguel Ferreira
źródło
3

Oto funkcja, która wybierze jedną z metod w zależności od tego, co jest zainstalowane w systemie:

# 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
źródło
2

Nie powinno być dostępne na twoim pudełku, ale spróbuj nmap.

peperunas
źródło
4
nmapjest dobrym narzędziem, ale niedostępnym w tych systemach. Zamiast pobierać nmap, kompilować, instalować w moim katalogu domowym, a następnie kopiować do wszystkich innych systemów, miałem nadzieję znaleźć sposób, korzystając z istniejących narzędzi dostępnych w większości instalacji Linuksa.
Steve HHH,
1

dla odniesienia, rozwijając odpowiedź @peperunas:

sposobem użycia nmap do testowania jest:

nmap -p 22 127.0.0.1

(powyższy przykład używa localhost do celów demonstracyjnych)

użytkownik138278
źródło
0

Jeśli chcesz przetestować więcej niż na systemie, możesz użyć naszego narzędzia testowego dda-serverspec ( https://github.com/DomainDrivenArchitecture/dda-serverspec-crate ) do takich zadań. Możesz określić swoje oczekiwania

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

i przetestuj te oczekiwania na hoście lokalnym lub na hoście zdalnym (połącz przez ssh). W przypadku testów zdalnych musisz zdefiniować cele:

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

Możesz uruchomić test z java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Pod maską używamy netcata tak jak wyżej ...

jerger
źródło