294

В старые времена мы использовали telnet чтобы посмотреть, открыт ли порт на удаленном хосте: telnet hostname port будет пытаться подключиться к любому порту на любом хосте и даст вам доступ к необработанному потоку TCP.

В настоящее время в системах, над которыми я работаю, не установлен telnet (по соображениям безопасности), и все исходящие соединения со всеми хостами по умолчанию блокируются. Со временем легко потерять отслеживание того, какие порты открыты для каких хостов.

Есть ли другой способ проверить, открыт ли порт в удаленной системе - с помощью системы Linux с ограниченным числом установленных пакетов, а telnet недоступен?

12 ответов12

354

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

nc -zv 127.0.0.1 80

Несколько портов:

nc -zv 127.0.0.1 22 80 8080

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

nc -zv 127.0.0.1 20-30
247

Некоторое время 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

Таа Даа!

98

Netcat - полезный инструмент:

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

Выводит 0 если порт 123 открыт, и 1 если он закрыт.

55

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

40

Я обнаружил, что curl может выполнить работу аналогично telnet , и curl даже скажет вам, какой протокол ожидает слушатель.

Создайте HTTP URI из имени хоста и порта в качестве первого аргумента для 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.

9

Вот одна строка:

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

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

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

9
[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!

Надеюсь, это решит вашу проблему :)

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)

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

2

Он не должен быть доступен на вашей коробке, но попробуйте с nmap .

1

Вот функция, которая выберет один из методов в зависимости от того, что установлено в вашей системе:

# 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
0

Комбинируя ответы @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
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, как описано выше ...

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .