Testar com eficiência se uma porta está aberta no Linux?


197

Em um script bash, como posso descobrir rapidamente se uma porta 445 está aberta / escutando em um servidor.

Eu tentei algumas opções, mas quero algo rápido:
1. lsof -i :445 (Leva segundos)
2. netstat -an |grep 445 |grep LISTEN(Leva segundos)
3. telnet(não retorna)
4. nmap, netcatnão está disponível no servidor

Será bom saber de uma maneira que não enumere primeiro e depois cumpra.


1
O netcat está disponível? Possui um caminho de falha rápido IIRC. netcat.sourceforge.net
JimR

5
netstat -lnt(com -te sem -a) limitará a saída apenas às conexões TCP. Pode acelerar um pouco. Você pode adicionar -4para o IPv4 apenas se não precisar do IPv6.
Bartosz Moczulski

lsof -i é um favorito pessoal.
Matt Joyce

14
netstat -an | grep PORTNUMBER | grep -i listenSe a saída estiver vazia, a porta não está em uso.
Automatix

Não sei por que lsofé lento para você, mas normalmente é a melhor das soluções que você listou. Sua netstatsolução não é muito confiável (você pode adivinhar sempre que usar grep; de qualquer maneira, ela retornará verdadeira se alguém estiver ouvindo, por exemplo, 4450). telnete netcattente criar uma conexão, que nem sempre é o que você deseja.
Peterohn

Respostas:


155

Uma surpresa que descobri recentemente é que o Bash suporta nativamente conexões tcp como descritores de arquivos . Usar:

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

Estou usando 6 como o descritor de arquivo porque 0,1,2 são stdin, stdout e stderr. Às vezes, 5 é usado pelo Bash para processos filho ; portanto, 3,4,6,7,8 e 9 devem ser seguros.

Conforme o comentário abaixo, para testar a escuta em um servidor local em um script:

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

Para determinar se alguém está ouvindo, tente conectar-se por loopback. Se falhar, a porta está fechada ou não temos acesso permitido. Depois, feche a conexão.

Modifique isso para seu caso de uso, como enviar um email, sair do script com falha ou iniciar o serviço necessário.


2
Isso só foi enforcado para mim.
Aman Jain

O gato @AmanJain aguarda o encerramento do EOF ou Ctrl-C. Você precisará ajustar isso para o seu protocolo. BTW, você está executando isso em um servidor remoto?
Spencer Rathbun

Eu quero inserir a porta a verificação de código em um script no servidor, sob /etc/init.d/
Aman Jain

@AmanJain Atualizei-o para um sistema local. Você só quer verificar se está ouvindo correto? Não há nenhuma verificação de protocolo, como solicitar uma página via http?
Spencer Rathbun #

1
Este não é um método confiável, já que nem todos OS (ex ubuntu 16 como eu descobri hoje) são enviados com o bash compilado para a construção da /dev/tcp/IP/PORTárvore
dyasny

107

Há uma breve resposta "rápida" aqui: Como testar se a porta TCP remota é aberta no script do Shell?

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

Eu o uso com 127.0.0.1 como endereço "remoto".

isso retorna "0" se a porta estiver aberta e "1" se a porta estiver fechada

por exemplo

nc -z 127.0.0.1 80; echo $?

-z Especifica que nc deve apenas procurar daemons que estão escutando, sem enviar nenhum dado a eles. É um erro usar esta opção em conjunto com a opção -l.


2
Essa parece ser a maneira mais fácil, obrigado. O link do script de exemplo não está mais funcionando, no entanto, é bastante autoexplicativo.
DerFunk # 14/15

Agradável! Isso é muito mais rápido do que as outras respostas em um servidor com muitas portas abertas. Retorna em <0,01 segundos para mim, enquanto o netstat / lsof leva 1s +
Tim

2
O sinalizador -z não está disponível no nmap baseado em nmap, com o qual as distribuições mais recentes são fornecidas: Fedora, Centos, etc. (nmap-ncat-6.01-9.fc18.x86_64)
Zack

9
Contra-intuitivamente, isso retorna "0" se a porta estiver aberta e "1" se a porta estiver fechada.
Sean

3
Os comandos do @Sean unix geralmente retornam '0' para indicar sucesso e diferente de zero para falha. Portanto, '0' indica que ele foi conectado com sucesso e diferente de zero que não foi conectado por algum motivo. Observe, no entanto, que algumas versões do 'nc' não suportam o argumento '-z', portanto, stackoverflow.com/a/25793128/6773916 é sem dúvida uma solução melhor.
precisa saber é o seguinte

89

Você pode usar o netstat dessa maneira para obter resultados muito mais rápidos:

No Linux:

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

No Mac:

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

Isso produzirá uma lista de processos atendendo na porta (445 neste exemplo) ou não produzirá nada se a porta estiver livre.


1
sua sintaxe netstat está incorreta. netstat -ln --tcp funciona, mas ainda lento
Aman Jain

6
Na verdade, é a sintaxe correta, mas provavelmente você está usando Linux e eu estou no Mac. Para Linux usar este:netstat -lnt | awk '$6 == "LISTEN" && $4 ~ ".445"'
anubhava

21
isso não produziu nada.
Jürgen Paul

1
A questão era sobre o Linux, então talvez o comentário deva estar na resposta.
UpTheCreek 23/09

1
Para verificar a porta 80, eu precisava usar awk '$6 == "LISTEN" && $4 ~ "80$"'. Em vez de procurar o ponto antes do número da porta \.80, usei 80$. Caso contrário, isso também combinava endereços IP que contêm .80e portas começando com 80tais como 8000.
Patrick Oscity

37

Você pode usar o netcat para isso.

nc ip port < /dev/null

conecta ao servidor e fecha a conexão diretamente novamente. Se o netcat não conseguir se conectar, ele retornará um código de saída diferente de zero. O código de saída é armazenado na variável $ ?. Como um exemplo,

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

retornará 0 se e somente se o netcat puder se conectar com êxito à porta.


1
Esta resposta precisa de mais votos. nc funciona perfeitamente para este caso. o truque / dev / tcp é inteligente, mas parece difícil implementar um script com interrupções de sinal.
Avindra Goolcharan

5
nctem o -zsinalizador para esse fim, o que não exige a entrada de /dev/null. Já existe uma resposta usando a -zbandeira acima.
precisa

2
@AbeVoelker Nem todas as versões do nc suportam o sinalizador -z. Estou no CentOS 7 e achei a solução de Tony o que eu precisava.
Shadoninja

@ Shadoninja É bom saber! Se eu pudesse editar a irreverência do meu comentário de 2014, eu o faria.
Abe Voelker

'nc' não suporta mais '-z' e, portanto, essa resposta parece ser a melhor solução.
Ricos Sedman

18

Com base na resposta de Spencer Rathbun, usando o bash:

true &>/dev/null </dev/tcp/127.0.0.1/$PORT && echo open || echo closed

Bom, suprimirá a mensagem "Conexão recusada". Sai automaticamente se o serviço aceitar a conexão sem esperar uma eternidade.
Seff

A melhor solução para serviços que não enviam dados após uma nova conexão. Cerca de 20 vezes mais rápido do que chamar netcat. Pode ser reduzido para: &>/dev/null </dev/tcp/127.0.0.1/$PORT
ens

16

eles estão listados em / proc / net / tcp.

é a segunda coluna, após o ":", em hexadecimal:

> 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  

então eu acho que um daqueles :50na terceira coluna deve ser stackoverflow: o)

procure man 5 procmais detalhes. e escolher isso além do sed etc é deixado como um exercício para o leitor gentil ...


10
ss -tl4 '( sport = :22 )'

2ms é rápido o suficiente?

Adicione os dois pontos e isso funciona no Linux


2
Ótimo, ssé ainda mais rápido que nc. lé para ouvir , 4é para IPv4; sportsignifica (claro) porta de origem . O comando acima está assumindo uma porta TCP de escuta ( topção): use uoption para UDPs ou nenhuma delas para os dois protocolos. Mais informações sobre sscomo sempre no Nixcraft . OBSERVAÇÃO: os ssfiltros não estão funcionando aqui, não sei por que (o bash 4.3.11, utilitário ss, iproute2-ss131122), precisa seguir o grep .
Campa

Pena que o sscomando não retorna um código de saída que reflete sua descoberta; sempre retorna 0 código de saída.
John Greene

| grep LISTEN?
Leucos

Eu recebo State Recv-Q Send-Q Local Address:Port Peer Address:Porte agora? O que isto significa?
Preto

6

Aqui está um que funciona para Mac e Linux:

netstat -aln | awk '$6 == "LISTEN" && $4 ~ "[\\.\:]445$"'

Eu acho que você pode remover com segurança o [\\.\:].
Patrick Oscity

6
nc -l 8000

Onde 8000 é o número da porta. Se a porta estiver livre, iniciará um servidor que você pode fechar facilmente. Se não for, lançará um erro:

nc: Address already in use

5

Eu queria verificar se uma porta está aberta em um dos nossos servidores de teste Linux. Consegui fazer isso tentando me conectar ao telnet da minha máquina de desenvolvimento ao servidor de teste. Na sua máquina dev, tente executar:

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

Neste exemplo, quero verificar se a porta 8080 está aberta no host test2.host.com


1

O tcping é uma ótima ferramenta com uma sobrecarga muito baixa. Também possui um argumento de tempo limite para torná-lo mais rápido:

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

1
Não tenho certeza se vale a pena instalar o tcping quando a solução da Spencer não requer instalações extras, mas essa é a solução mais limpa e legível para humanos.
Bdombro 16/05

1

Você também pode usar o comando netcat

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

ou

nc -zv [ip] [port]

-z - configura o nc para simplesmente procurar daemons que estão escutando, sem enviar dados para eles.
-v - ativa o modo detalhado.


-2

nmapé a ferramenta certa. Basta usarnmap example.com -p 80

Você pode usá-lo no servidor local ou remoto. Também ajuda a identificar se um firewall está bloqueando o acesso.


-4

Se você estiver usando o iptables, tente:

iptables -nL

ou

iptables -nL | grep 445

que apenas lista as regras do iptables ... que podem não ter correlação com as portas abertas.
David Goodwin
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.