Эффективно проверить, открыт ли порт в Linux?

197

Из скрипта bash как быстро узнать, есть ли порт 445 / прослушивается на сервере.

Я попробовал несколько вариантов, но я хочу что-то быстрое:
1. lsof -i :445 (занимает секунды)
2. netstat -an |grep 445 |grep LISTEN(занимает секунды)
3. telnet(не возвращается)
4. nmap, netcatнедоступны на сервере

Было бы хорошо узнать способ, который не перечисляет сначала и greps после этого.

Аман Джайн
источник
1
Доступен ли netcat? У него есть быстрый путь отказа IIRC. netcat.sourceforge.net
JimR
5
netstat -lnt-tи без -a) ограничит вывод только прослушиванием TCP-соединений. Это может немного ускорить. Вы можете добавить -4IPv4, только если вам не нужен IPv6.
Бартош Мочульски
lsof -i - личный фаворит.
Мэтт Джойс
14
netstat -an | grep PORTNUMBER | grep -i listenЕсли вывод пуст, порт не используется.
automatix
Я не знаю, почему lsofэто медленно для вас, но обычно это лучшее из перечисленных вами решений. Ваше netstatрешение не очень надежно (вы можете угадать его всякий раз, когда используете grep; в любом случае оно возвращает true, если кто-то слушает, например, 4450). telnetи на netcatсамом деле попытаться создать соединение, которое не всегда может быть тем, что вы хотите.
Петерсон

Ответы:

155

Удивление, которое я недавно узнал, заключается в том, что Bash изначально поддерживает tcp-соединения в качестве дескрипторов файлов . Использовать:

exec 6<>/dev/tcp/ip.addr.of.server/445
echo -e "GET / HTTP/1.0\n" >&6
cat <&6

Я использую 6 в качестве дескриптора файла, потому что 0,1,2 - это stdin, stdout и stderr. 5 иногда используется Bash для дочерних процессов , поэтому 3,4,6,7,8 и 9 должны быть безопасными.

В соответствии с комментарием ниже, чтобы проверить прослушивание на локальном сервере в сценарии:

exec 6<>/dev/tcp/127.0.0.1/445 || echo "No one is listening!"
exec 6>&- # close output connection
exec 6<&- # close input connection

Чтобы определить, слушает ли кто-то, попытайтесь подключиться с помощью обратной связи. Если это не удается, то порт закрыт или нам не разрешен доступ. После этого закройте соединение.

Измените это в своем случае, например, отправив электронное письмо, выйдя из сценария при сбое или запустив необходимую службу.

Спенсер Рэтбун
источник
2
Это просто повешено для меня.
Аман Джайн
@AmanJain cat ждет выхода EOF или Ctrl-C. Вам нужно будет настроить это для вашего протокола. Кстати вы запускаете это на удаленный сервер?
Спенсер Ратбун,
Я хочу встроить код проверки порта в скрипт на сервере, в /etc/init.d/
Aman Jain
@ AmanJain Я обновил его для локальной системы. Вы просто хотите проверить правильность прослушивания? Нет проверки протокола, например, запросить страницу через http?
Спенсер Рэтбун,
1
Это не надежный метод, так как не все ОС (например, Ubuntu 16, как я обнаружил сегодня) поставляются с bash, скомпилированным для построения /dev/tcp/IP/PORTдерева
dyasny
107

Здесь есть очень короткий термин «быстрый ответ»: как проверить, открыт ли удаленный порт TCP из сценария Shell?

nc -z <host> <port>; echo $?

Я использую его с 127.0.0.1 в качестве «удаленного» адреса.

возвращает «0», если порт открыт, и «1», если порт закрыт.

например

nc -z 127.0.0.1 80; echo $?

-z Указывает, что nc должен просто сканировать прослушивающие демоны, не отправляя им никаких данных. Ошибочно использовать эту опцию в сочетании с опцией -l.

черный
источник
2
Кажется, это самый простой способ, спасибо. Ссылка на образец скрипта больше не работает, но все же довольно самоочевидна.
derFunk
Ницца! Это намного быстрее, чем другие ответы на сервере с множеством открытых портов. Возврат за <0,01 секунды для меня, в то время как netstat / lsof займет 1 с +
Тим
2
Флаг -z недоступен в ncat на основе nmap, с которым поставляются самые последние дистрибутивы: Fedora, Centos и т. Д. (Nmap-ncat-6.01-9.fc18.x86_64)
Зак
9
Необычно, это возвращает «0», если порт открыт, и «1», если порт закрыт.
Шон
3
Команды @Sean unix обычно возвращают «0» для обозначения успеха и ненулевое значение для сбоя. Таким образом, «0» указывает, что он успешно подключен и ненулевой, что он не подключился по какой-то причине. Обратите внимание, однако, что некоторые версии 'nc' не поддерживают аргумент '-z', поэтому stackoverflow.com/a/25793128/6773916 , возможно, является лучшим решением.
Рич Седман,
89

Вы можете использовать netstat таким образом для более быстрых результатов:

В Linux:

netstat -lnt | awk '$6 == "LISTEN" && $4 ~ /\.445$/'

На Mac:

netstat -anp tcp | awk '$6 == "LISTEN" && $4 ~ /\.445$/'

Это выведет список процессов, прослушивающих порт (445 в этом примере), или ничего не выведет, если порт свободен.

анубхава
источник
1
Ваш синтаксис netstat неверен. netstat -ln --tcp работает, но все еще медленно
Аман Джайн
6
На самом деле это правильный синтаксис, но, вероятно, вы используете Linux, а я на Mac. Для Linux используйте это:netstat -lnt | awk '$6 == "LISTEN" && $4 ~ ".445"'
anubhava
21
это ничего не выводило.
Юрген Павел
1
Вопрос был о Linux, хотя, возможно, комментарий должен быть в ответе.
UpTheCreek,
1
Для проверки на порт 80 мне нужно было использовать awk '$6 == "LISTEN" && $4 ~ "80$"'. Вместо проверки точки перед номером порта с помощью \.80я использовал 80$. В противном случае это также соответствует IP-адресам, содержащим .80и порты, начинающиеся с 80таких как 8000.
Патрик Осци
37

Вы можете использовать Netcat для этого.

nc ip port < /dev/null

подключается к серверу и снова напрямую закрывает соединение. Если netcat не может подключиться, он возвращает ненулевой код завершения. Код выхода хранится в переменной $ ?. Например,

nc ip port < /dev/null; echo $?

вернет 0, если и только если netcat может успешно подключиться к порту.

Тони
источник
1
Этот ответ нуждается в большем количестве голосов. nc отлично работает в этом случае. трюк / dev / tcp умный, но кажется сложным реализовать скрипт с прерываниями сигнала.
Авиндра Гулчаран
5
ncимеет -zфлаг для этой цели, который не требует ввода от /dev/null. Там уже ответ, используя -zфлаг выше.
Абе Воелкер,
2
@AbeVoelker Не все версии nc поддерживают флаг -z. Я нахожусь на CentOS 7 и нашел решение Тони, что мне нужно.
Шадониня,
@Shadoninja Хорошо знать! Если бы я мог изменить легкомысленность из моего комментария от 2014 года, я бы сделал.
Абе Воелкер,
«nc» больше не поддерживает «-z», поэтому этот ответ кажется лучшим решением.
Рич Седман,
18

Основываясь на ответе Спенсера Рэтбуна, используя bash:

true &>/dev/null </dev/tcp/127.0.0.1/$PORT && echo open || echo closed
user1338062
источник
Хорошо, это подавит сообщение «Соединение отказано». Автоматический выход, если служба принимает соединение без ожидания навсегда.
Seff
Лучшее решение для служб, которые не отправляют данные после нового подключения. Примерно в 20 раз быстрее, чем вызов netcat. Может быть сокращен до: &>/dev/null </dev/tcp/127.0.0.1/$PORT
Энс
16

они перечислены в / proc / net / tcp.

это второй столбец после ":" в шестнадцатеричном виде:

> cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 10863 1 ffff88020c785400 99 0 0 10 -1                     
   1: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7983 1 ffff88020eb7b3c0 99 0 0 10 -1                      
   2: 0500010A:948F 0900010A:2328 01 00000000:00000000 02:00000576 00000000  1000        0 10562454 2 ffff88010040f7c0 22 3 30 5 3                   
   3: 0500010A:E077 5F2F7D4A:0050 01 00000000:00000000 02:00000176 00000000  1000        0 10701021 2 ffff880100474080 41 3 22 10 -1                 
   4: 0500010A:8773 16EC97D1:0050 01 00000000:00000000 02:00000BDC 00000000  1000        0 10700849 2 ffff880104335440 57 3 18 10 -1                 
   5: 0500010A:8772 16EC97D1:0050 01 00000000:00000000 02:00000BF5 00000000  1000        0 10698952 2 ffff88010040e440 46 3 0 10 -1                  
   6: 0500010A:DD2C 0900010A:0016 01 00000000:00000000 02:0006E764 00000000  1000        0 9562907 2 ffff880104334740 22 3 30 5 4                    
   7: 0500010A:AAA4 6A717D4A:0050 08 00000000:00000001 02:00000929 00000000  1000        0 10696677 2 ffff880106cc77c0 45 3 0 10 -1  

так что я предполагаю, что один из них :50в третьем столбце должен быть stackoverflow: o)

искать man 5 procболее подробную информацию. и выбор этого вместе с sed и т. д. оставлен как упражнение для нежного читателя ...

Эндрю Кук
источник
10
ss -tl4 '( sport = :22 )'

2 мс достаточно быстро?

Добавьте двоеточие, и это работает на Linux

LEUCOS
источник
2
Великий, ssдаже немного быстрее, чем nc. lдля прослушивания , 4для IPv4; sportобозначает (конечно) исходный порт . Приведенная выше команда предполагает наличие прослушиваемого TCP-порта ( tопция): использовать uопцию для UDP или ни один из них для обоих протоколов. Больше информации ssкак всегда на Nixcraft . ПРИМЕЧАНИЕ: ssфильтры здесь не работают, не знаю почему (bash 4.3.11, утилита ss, iproute2-ss131122), должны идти с grep .
Кампа
Жаль, что ssкоманда не возвращает код завершения, отражающий ее нахождение; он всегда возвращает 0 код выхода.
Джон Грин
| grep LISTEN?
leucos
Я получаю State Recv-Q Send-Q Local Address:Port Peer Address:Portи сейчас? Что это значит?
Черный
6

Вот тот, который работает для Mac и Linux:

netstat -aln | awk '$6 == "LISTEN" && $4 ~ "[\\.\:]445$"'
Артур Бодера
источник
Я думаю, что вы можете безопасно удалить [\\.\:].
Патрик Осцити
6
nc -l 8000

Где 8000 - номер порта. Если порт свободен, он запустит сервер, который вы можете легко закрыть. Если это не так, он выдаст ошибку:

nc: Address already in use
Хосе Энрике
источник
5

Я хотел проверить, открыт ли порт на одном из наших тестовых серверов Linux. Я смог сделать это, пытаясь соединиться с telnet с моей машины разработчика на тестовый сервер. На твоей девайс машине попробуй запустить:

$ telnet test2.host.com 8080
Trying 05.066.137.184...
Connected to test2.host.com

В этом примере я хочу проверить, открыт ли порт 8080 на хосте test2.host.com

razvang
источник
1

tcping - отличный инструмент с очень низкими издержками. У него также есть аргумент тайм-аута, чтобы ускорить его:

[root@centos_f831dfb3 ~]# tcping 10.86.151.175 22 -t 1
10.86.151.175 port 22 open.
[root@centos_f831dfb3 ~]# tcping 10.86.150.194 22 -t 1
10.86.150.194 port 22 user timeout.
[root@centos_f831dfb3 ~]# tcping 1.1.1.1 22 -t 1
1.1.1.1 port 22 closed.
Payam
источник
1
Не уверен, что tcping стоит устанавливать, когда решение Spencer не требует дополнительных установок, но это определенно самое чистое и удобочитаемое решение.
bdombro
1

Вы также можете использовать команду netcat

[location of netcat]/netcat -zv [ip] [port]

или

nc -zv [ip] [port]

-z - устанавливает nc для простого сканирования на предмет прослушивания демонов, без фактической отправки им данных.
-v - включает подробный режим.

Саурабх
источник
-2

nmapэто правильный инструмент. Просто используйтеnmap example.com -p 80

Вы можете использовать его с локального или удаленного сервера. Это также поможет вам определить, блокирует ли доступ брандмауэр.

zainengineer
источник
-4

Если вы используете iptables, попробуйте:

iptables -nL

или

iptables -nL | grep 445
Noz
источник
это просто перечисляет правила iptables ... которые могут не иметь отношения к открытым портам.
Дэвид Гудвин