Проверьте, доступен ли порт в удаленной системе (без 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

Таа Даа!

lornix
источник
Это также, кажется, работает в 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
@Alexandr ... на самом деле "зависает без результата" - довольно ожидаемое поведение. кот ждет ввода. У nc есть дополнительные смарты, которые позволяют ему ожидать отсутствия данных и прекращают попытки. кошка не совсем такой умный. Попробуйте cat < /dev/tcp/localhost/22, вы должны получить свой заголовок sshd. Очевидно, что ваш процесс на порту 18080 ждет чего-то, прежде чем что-то отправлять. Порт 22 ( SSH ) приветствует вас с его версией и еще много чего. Попробуйте!
Lornix
1
@ lornix, большое спасибо за объяснение! Теперь ограничение ясно. Я думаю, что использование nc должно быть предпочтительным способом проверки портов.
Александр
2
Это было невероятно полезно при работе с док-контейнером, на котором ничего не было установлено. Был в состоянии быстро проверить, что контейнер имел доступ к неконтейнерной БД через DNS. Пример: cat </ dev / tcp / hostname / 5432
Майкл Хоббс,
404

Красиво и многословно! Из справочных страниц.
Один порт:

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 не распознается. Мне удалось обойтись без з
смишра
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если он закрыт.

thnee
источник
Это гораздо более элегантный и письменный ответ, чем мой собственный. Мне жаль, что сисадмины, которые заботятся о безопасности, telnetтакже отказались nc(хотя, как ни странно, нет curlили нет wget).
Стив ХХХ,
Да, это совершенно произвольно и глупо.
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...)и перенаправляем выходные данные подкоманды.

ОДС
источник
Это отлично. Хотелось бы, чтобы за него проголосовали до самого верха. Я только прочитал это далеко вниз по странице, потому что я случайно прокрутил перед закрытием.
Still.Tony
@ 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
Если curl недоступен, может быть 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

используя синтаксис Bash, объясненный в ответе @lornix .

Для получения дополнительной информации проверьте: Расширенное руководство по написанию сценариев Bash: Глава 29. /devи/proc .

kenorb
источник
какое время ожидания для закрытых портов?
Тило
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)

Затем просто используйте &&и / или ||(или даже $?), чтобы извлечь результат. Надеюсь, кто-нибудь найдет эту информацию полезной.

Azukikuru
источник
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 для достижения любого порта

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.

peperunas
источник
4
nmapхороший инструмент, но не доступен в этих системах. Вместо того, чтобы скачать nmap, скомпилировать его, установить в мой домашний каталог, а затем скопировать его на все другие системы, я надеялся найти способ, используя существующие инструменты, доступные в большинстве установок Linux.
Стив ХХХ,
1

для справки, расширив ответ @peperunas:

способ использовать Nmap для тестирования, это:

nmap -p 22 127.0.0.1

(пример выше использует localhost для демонстрационных целей)

user138278
источник
0

Если вам нужно тестировать больше, чем в системе, вы можете использовать наш инструмент тестирования dda-serverpec ( 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"}]}

и протестируйте эти ожидания как против локального хоста, так и против удаленного хоста (подключитесь по 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, как описано выше ...

Джергер
источник