Проверьте, открыт ли удаленный порт TCP из сценария оболочки - PullRequest
279 голосов
/ 07 февраля 2011

Я ищу быстрый и простой способ для правильного тестирования, если данный порт TCP открыт на удаленном сервере, внутри скрипта Shell.

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

Вот пример:

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

Мне нужен либо лучший способ, либо способ принудительно установить время ожидания telnet, если он не подключается менее чем за 8 секунд, например, и вернуть что-то, что я могу поймать в Shell (код возврата или строку в stdout).

Мне известен метод Perl, который использует модуль IO :: Socket :: INET и написал успешный скрипт, который тестирует порт, но хотел бы по возможности избегать использования Perl.

Примечание: это то, что мой сервер работает (откуда я должен запустить это)

SunOS 5.10 Generic_139556-08 i86pc i386 i86pc

Ответы [ 16 ]

422 голосов
/ 27 февраля 2012

Как указал Б. Роудс, nc выполнит эту работу.Более компактный способ его использования:

nc -z <host> <port>

Таким образом nc будет проверять только, открыт ли порт, выход с 0 при успехе, 1 при ошибке.

Для быстрогоинтерактивная проверка (с таймаутом 5 секунд):

nc -z -v -w5 <host> <port>
131 голосов
/ 08 ноября 2013

Это достаточно легко сделать с опциями -z и -w TIMEOUT для nc, но не во всех системах установлена ​​nc.Если у вас достаточно свежая версия bash, это будет работать:

# 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

Здесь происходит то, что timeout запустит подкоманду и уничтожит ее, если она не завершится в течение указанного времени ожидания (1второй в приведенном выше примере).В этом случае bash является подкомандой и использует специальную обработку / dev / tcp , чтобы попытаться открыть соединение с указанным сервером и портом.Если bash может открыть соединение в течение тайм-аута, cat просто немедленно закроет его (так как оно читает с /dev/null) и выйдет с кодом состояния 0, который пройдет через bash, а затем timeout.Если bash получает сбой соединения до истечения указанного времени ожидания, то bash завершится с кодом выхода 1, который также будет возвращен timeout.И если bash не может установить соединение и истекает указанное время ожидания, timeout уничтожит bash и выйдет со статусом 124.

97 голосов
/ 05 февраля 2013

TOC:

  • Использование bash и timeout
    • Команда
    • Примеры
  • Использование nc
    • Команда
    • RHEL 6 (nc-1.84)
      • Установка
      • Примеры
    • RHEL 7 (nmap-ncat-6.40)
      • Установка
      • Примеры
  • Замечания

Использование bash иtimeout:

Обратите внимание, что timeout должен присутствовать с RHEL 6+ или альтернативно находится в GNU coreutils 8.22.В MacOS установите его с помощью brew install coreutils и используйте его как gtimeout.

Команда:

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

При параметризации хоста и порта обязательно укажите их как ${HOST}и ${PORT} как указано выше.Не указывайте их просто как $HOST и $PORT, то есть без скобок;в этом случае это не сработает.

Пример:

Успех:

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

Ошибка:

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

Если необходимо сохранитьсостояние выхода bash,

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

Использование nc:

Обратите внимание, что на RHEL 7 установлена ​​обратная несовместимая версия nc.

Команда:

Обратите внимание, что приведенная ниже команда является уникальной в том смысле, что она идентична для RHEL 6 и 7. Отличаются только установка и вывод.

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

RHEL 6 (nc-1.84):

Установка:

$ sudo yum install nc

Примеры:

Успех:
$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
Сбой:
$ 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

Если имя хоста сопоставляется с несколькими IP-адресами, вышеприведенная команда с ошибкойбудет циклически проходить через многие или все из них.Например:

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

Установка:

$ sudo yum install nmap-ncat

Примеры:

Успех:
$ 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
Сбой:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1

Если имя хоста сопоставляется с несколькими IP-адресами, вышеприведенная неудачная команда будет циклически проходить через многие или все из них.Например:

$ 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

Примечания:

Аргумент -v (--verbose) и команда echo $?, конечно, только для иллюстрации.

50 голосов
/ 20 апреля 2011

С помощью netcat вы можете проверить, открыт ли порт следующим образом:

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

Возвращаемое значение nc будет успешным, если был открыт порт TCP, и сбоем (обычно это возвраткод 1) если он не может установить TCP-соединение.

Некоторые версии nc будут зависать при попытке этого, потому что они не закрывают отправляющую половину своего сокета даже после получения окончанияфайл из /dev/null.На моем собственном ноутбуке с Ubuntu (18.04) установленная мной версия netcat-openbsd netcat предлагает обходной путь: для получения немедленного результата необходима опция -N:

nc -N my.example.com 80 < /dev/null
26 голосов
/ 11 февраля 2016

В Bash использование файлов псевдоустройств для соединений TCP / UDP просто.Вот скрипт:

#!/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.sh 
Connection to example.com on port 80 succeeded

Вот однострочный (синтаксис Bash):

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

Обратите внимание, что некоторые серверы могут быть защищены брандмауэром от SYN-атак, поэтому может возникнуть тайм-аут соединения TCP (~ 75 сек).Чтобы обойти проблему тайм-аута, попробуйте:

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

См .: Как уменьшить время ожидания системного вызова TCP connect ()?

11 голосов
/ 27 мая 2016

Мне нужно было более гибкое решение для работы с несколькими git-репозиториями, поэтому я написал следующий код sh на основе 1 и 2 . Вы можете использовать свой адрес сервера вместо gitlab.com и ваш порт вместо 22.

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
10 голосов
/ 14 февраля 2013

Если вы используете ksh или bash , они оба поддерживают перенаправление ввода-вывода в / из сокета с использованием конструкции / dev / tcp / IP / PORT, В этом примере Korn shell я перенаправляю ввод no-op (: ) из сокета:

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

Оболочка печатает сообщение об ошибке, если сокет не открыт:

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

Поэтому вы можете использовать это как тест в , если условие:

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

Нет операции находится в подоболочке, поэтому я могу выбросить std-err в случае сбоя перенаправления std-in.

Я часто использую / dev / tcp для проверки доступности ресурса по HTTP:

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$ 

Этот однострочный открывает дескриптор файла 9 для чтения и записи в сокет, печатает HTTP GET в сокет и использует cat читать из сокета.

9 голосов
/ 04 мая 2015

Хотя старый вопрос, я только что рассмотрел его вариант, но ни одно из решений здесь не применимо, поэтому я нашел другое и добавляю его для потомков.Да, я знаю, что ОП сказал, что они знали об этой опции, и она им не подошла, но для любого последующего впоследствии это может оказаться полезным.

В моем случае я хочу проверить наличиелокальный apt-cacher-ng сервис из docker билда.Это означает, что абсолютно ничего нельзя установить до теста.Нет nc, nmap, expect, telnet или python.perl, однако, присутствует вместе с основными библиотеками, поэтому я использовал это:

perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))'
6 голосов
/ 22 июля 2016

В некоторых случаях, когда такие инструменты, как curl, telnet, nc o nmap недоступны, у вас все еще есть шанс с помощью wget

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 голосов
/ 02 июля 2017

проверить порты используя bash

Пример

$ ./test_port_bash.sh 192.168.7.7 22

порт 22 открыт

код

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