Перевірте, чи доступ до порту на віддаленій системі (без telnet)


353

За старих часів ми telnetбачили, чи відкритий порт на віддаленому хості: telnet hostname portнамагатиметься підключитися до будь-якого порту будь-якого хоста і надасть вам доступ до необмеженого потоку TCP.

У ці дні в системах, над якими я працюю, не встановлено telnet (з міркувань безпеки), а всі вихідні з'єднання з усіма хостами блокуються за замовчуванням. З часом легко не вдається відстежити, які порти відкриті для яких хостів.

Чи є інший спосіб перевірити, чи відкритий порт у віддаленій системі - за допомогою системи Linux з обмеженою кількістю встановлених пакетів, і telnetвін недоступний?



У мене було таке саме питання. Відповідь @Subhranath Chunder нижче допомогла. Однак я дізнався, що встановлення Telnet - справа мала brew install telnet. Тож я очікую, що користувачі Linux можуть зробити те ж саме з yumі apt-get.
Mig82

Відповіді:


277

Bash деякий час мав доступ до портів TCP та UDP . На чоловіковій сторінці:

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

Отже, ви можете використовувати щось подібне:

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

Таа Даа!


Це, здається, працює і в MinGW . Наприклад, віддалений сервер VNC на 192.168.2.100 відповідає "RFB 003.008", використовуючи "cat </dev/tcp/192.168.2.100/5900".
Пітер Мортенсен

1
@lornix, добре, але в цьому випадку я повинен отримати той же результат, використовуючи nc без опції -z, але він все ще не працює: # nc -v -w5 127.0.0.1 18080 Підключення до 127.0.0.1 18080 порт [tcp / *] вдалося! # cat </dev/tcp/127.0.0.1/18080 Просто висить без жодного результату. Просто хочу зрозуміти, коли я можу використовувати варіант "/ dev / tcp / host / port"
Олександр

5
@ Александр ... насправді "висить без жодного результату" - це дуже очікувана поведінка. кішка чекає введення. nc має додаткові розумні можливості, щоб він міг відчути відсутність даних і перестає намагатися. кішка НЕ зовсім такий розумний. Спробуйте cat < /dev/tcp/localhost/22, вам слід отримати заголовок sshd. Очевидно, що ваш процес на порту 18080 чекає, коли щось увійде, перш ніж щось надсилати. Порт 22 ( ssh ) вітає вас своєю версією та іншим. Спробуй!
lornix

1
@lornix, дуже дякую за пояснення! Тепер обмеження зрозуміло. Я думаю, що використання nc має бути кращим способом перевірки портів.
Олександр

2
Це було надзвичайно корисно при роботі з контейнером docker, в якому нічого не було встановлено. Був в змозі швидко перевірити, що контейнер мав доступ до неконтейнерної БД через DNS. Приклад: cat </ dev / tcp / hostname / 5432
Michael Hobbs

404

Приємно і багатослівно! Із сторінок man.
Один порт:

nc -zv 127.0.0.1 80

Кілька портів:

nc -zv 127.0.0.1 22 80 8080

Діапазон портів:

nc -zv 127.0.0.1 20-30

6
Здається, це набагато найкраща відповідь, дякую. ;-)
lpapp

6
Це висіло при спробі на Ubuntu 14.04 (Trusty Tahr) для віддаленого сервера (тієї ж локальної мережі) для закритих портів (він вимкнувся через 127 секунд) - таким чином, не дуже підходить у сценаріях. Він працював, хоча для служби, у якій був відкритий порт. Використання опції "-w2" може бути рішенням.
Пітер Мортенсен

6
Використовуйте параметр -u для портів UDP.
Ефрен

8
У версії 6.4 ncat -z не розпізнається. Мені вдалося обійтися без z
smishra

5
Ви можете перевірити кілька діапазонів за допомогою: nc -zv 127.0.0.1 22,80,8080,20-30,443-446(nc Версія: 1.107-4).
боббел

102

Netcat - корисний інструмент:

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

Виводиться, 0якщо порт 123 відкритий, і 1якщо він закритий.


Це набагато більш елегантна та чудова відповідь, ніж моя власна. Мені прикро, що свідомі безпеки, які telnetтакож утримувались nc(проте - як не дивно - ні curlабо wget).
Стів HHH

Так, це абсолютно довільно і нерозумно.
thnee

3
Нехай FORпочинаються заяви!
Чад Гаррісон

1
Це висіло, коли його приміряли на Ubuntu 14.04 (Trusty Tahr) для віддаленого сервера (тієї ж локальної мережі) для закритих портів (він вимкнувся приблизно через 127 секунд) - таким чином, не дуже підходить у сценаріях. Це спрацювало, хоча для сервісу, який відкрив порт, повертаючи 0. Використання опції "-w2" може бути рішенням.
Пітер Мортенсен

1
Я думаю, -G 2що буде більш підходящим для тайм-ауту TCP
AB

58

Найпростіший метод без використання іншого інструменту, наприклад socat, описаний у відповіді @ lornix вище. Це лише для того, щоб додати фактичний приклад того, як можна було б використовувати psuedo-пристрій /dev/tcp/...у Bash, якби ви хотіли, скажімо, перевірити, чи був інший сервер певним портом, доступним через командний рядок.

Приклади

Скажіть, у мене в мережі розміщений хост 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

Причина, за якою ви хочете вписати такі echo > /dev/...круглі дужки, (echo > /dev/...)полягає в тому, що якщо ви цього не зробите, тоді з тестами з'єднань, які не працюють, ви отримаєте такі типи повідомлень.

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

Їх просто не можна переспрямувати, /dev/nullоскільки вони надходять із спроби виписати дані на пристрій /dev/tcp. Таким чином, ми фіксуємо все, що виводиться в підкоманду, тобто (...cmds...)перенаправляємо висновок підкоманди.


Це чудово. Хотілося б, щоб вона проголосувала до вершини. Я читав це далеко внизу сторінки, тому що випадково прокрутив її перед тим, як закрити її.
Все-таки.Тоні

@ Okuma.Tony - так, це завжди питання з питаннями Q, на які є багато відповідей 8-). Дякуємо за відгук, але це вдячно.
slm

46

Я виявив, що це curlможе зробити роботу аналогічним чином telnet, і curlнавіть підкаже, який протокол очікує слухач.

Побудуйте URI HTTP з імені хоста та порту в якості першого аргументу curl. Якщо curlможна підключитися, він повідомить про невідповідність протоколу та вихід (якщо слухач не веб-служба). Якщо curlне вдалося підключитися, воно закінчиться.

Наприклад, порт 5672 на хості 10.0.0.99 закривається або блокується брандмауером:

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

Однак з іншої системи до порту 5672 на хості 10.0.0.99 можна дістатися, і він, як видається, працює з слухачем AMQP.

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

Важливо розрізняти різні повідомлення: перша помилка була через те, що curlне вдалося підключитися до порту. Другий збій - це тест на успіх, хоча curlочікується, що слухач HTTP замість слухача AMQP.


5
Якщо завитка недоступна, може бути wget. wget -qS -O- http://ip.add.re.ss:portповинні ефективно робити те саме.
CVn

4
Це навіть працює з ім'ям хоста, наприклад. curl myhost:22.
에이 바

Це може бути неправильним. Я працюю в службі Tomcat, але отримую помилку 404. # curl -k 192.168.194.4:6443 <html><head> <title> Apache Tomcat / 7.0.34 - повідомлення про помилки </title> <style> <! - H1 --- HR {color: # 525D76;} -> </style> </head><body> <h1> HTTP-статус 404 - / </h1> <HR size = "1" noshade = "noshade"> <p> <b> type </b> Звіт про стан </p> <p> <b> повідомлення </b> <u>/</u></p><p> <b> опис </b> <u> Запитаний ресурс недоступний. </u> </p> <HR size = "1" noshade = "noshade"> <h3> Apache Tomcat / 7.0.34 </h3> </body> </html>

Дивіться мій пост із подібним підходом.
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!

Сподіваюся, це вирішить вашу проблему :)


1
Так, це краще - вичерпання часу майже для закритих портів.
Пітер Мортенсен

1
Чи завжди це використовується TCP чи є спосіб, щоб його перевірити UDP?
kmoe

9

Ось один вкладиш:

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

використовуючи синтаксис Баша, пояснений у відповіді @lornix .

Для отримання додаткової інформації перегляньте: Розширений посібник із написання сценарію: Глава 29. /devта/proc .


який час очікування для закритих портів?
Тіло

6

Я цілий день боровся, бо жодна з цих відповідей мені не здавалася. Проблема полягає в тому, що в останній версії програми ncбільше немає -zпрапора, тоді як прямий доступ через TCP (як згідно @lornix та @slm) не працює, коли хост недоступний. Зрештою я знайшов цю сторінку , де я нарешті знайшов не один, а два робочих приклади:

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

    ( -wпрапор піклується про час очікування та </dev/nullзамінює -zпрапор)

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

    ( timeoutкоманда піклується про час очікування, а решта - від @slm)

Потім просто скористайтеся &&та / або ||(або навіть $?), щоб отримати результат. Сподіваємось, хтось знайде цю інформацію корисною.


4

Поєднуючи відповіді від @kenorb та @Azukikuru, ви можете перевірити порт, відкритий / закритий / з фаєром.

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

Ще один підхід із завиткою для досягнення будь-якого порту

curl telnet://127.0.0.1:22

3

Ось функція, яка вибере один із методів залежно від того, що встановлено у вашій системі:

# 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

2

Він не повинен бути доступний у вашій коробці, але спробуйте nmap.


4
nmapє хорошим інструментом, але недоступний у цих системах. Замість того, щоб завантажувати nmap, компілювати його, встановлювати його в домашній каталог, а потім копіювати його на всі інші системи, я сподівався знайти спосіб за допомогою існуючих інструментів, доступних у більшості установок Linux.
Стів HHH

1

Для довідок, поширюючись на відповідь @peperunas:

спосіб використання nmap для тестування:

nmap -p 22 127.0.0.1

(приклад вище використовує localhost для демонстраційних цілей)


0

Якщо ви перевіряєте більше, ніж у системі, ви можете використовувати наш тестовий інструмент dda-serverspec ( https://github.com/DomainDrivenArchitecture/dda-serverspec-crate ) для таких завдань. Ви можете визначити своє очікування

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

і протестуйте ці очікування або проти localhost, або проти віддалених хостів (підключіться ssh). Для віддалених тестів потрібно визначити ціль:

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

Ви можете запустити тест за допомогою java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Під кришкою ми використовуємо netcat як підготовлений вище ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.