Teste se uma porta em um sistema remoto está acessível (sem telnet)

353

Antigamente, costumávamos telnetver se uma porta em um host remoto estava aberta: telnet hostname porttentaria conectar-se a qualquer porta em qualquer host e fornecer acesso ao fluxo TCP bruto.

Atualmente, os sistemas nos quais trabalho não têm o telnet instalado (por razões de segurança) e todas as conexões de saída com todos os hosts são bloqueadas por padrão. Com o tempo, é fácil perder o controle de quais portas estão abertas para quais hosts.

Existe outra maneira de testar se uma porta em um sistema remoto está aberta - usando um sistema Linux com um número limitado de pacotes instalados e telnetnão está disponível?

Steve HHH
fonte
Eu estava tendo esse mesmo problema. A resposta de @Subhranath Chunder abaixo ajudou. No entanto, descobri que instalar o Telnet era uma pequena questão de execução brew install telnet. Então, espero que os usuários do Linux possam fazer o mesmo com yume apt-get.
Mig82 26/09

Respostas:

277

O Bash conseguiu acessar as portas TCP e UDP por um tempo. Na página do manual:

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

Então você pode usar algo como isto:

xenon-lornix:~> cat < /dev/tcp/127.0.0.1/22
SSH-2.0-OpenSSH_6.2p2 Debian-6
^C pressed here

Taa Daa!

lornix
fonte
Isso também parece funcionar no MinGW . Por exemplo, um servidor VNC remoto em 192.168.2.100 responde com "RFB 003.008" usando "cat </dev/tcp/192.168.2.100/5900".
Peter Mortensen
1
@lornix, ok, mas neste caso eu tenho que obter o mesmo resultado com o uso nc sem a opção -z, mas ainda não funciona: # nc -v -w5 127.0.0.1 18080 Conexão à porta 180.0 127.0.0.1 [tcp / *] conseguiu! # cat </dev/tcp/127.0.0.1/18080 Apenas trava sem nenhum resultado. Só quero entender quando eu posso usar "/ dev / tcp / host / porta" opção
Alexandr
5
@ Alexandr ... na verdade, "trava sem nenhum resultado" é o comportamento esperado. gato está aguardando entrada. O nc possui inteligência extra para permitir que não haja dados pendentes e pare de tentar. gato não é tão inteligente. Tente cat < /dev/tcp/localhost/22, você deve obter seu cabeçalho sshd. Evidentemente, seu processo na porta 18080 aguarda a entrada de algo antes de enviar qualquer coisa. A porta 22 ( ssh ) recebe você com sua versão e outros enfeites. Experimente!
Lornix
1
@ Lornix, muito obrigado pela explicação! Agora a restrição está clara. Eu acho que usar nc deve ser a maneira preferida de verificar portas.
Alexandr
2
Isso foi incrivelmente útil ao trabalhar com um contêiner de docker que não tinha nada instalado. Conseguiu verificar rapidamente se o contêiner tinha acesso ao banco de dados não contêiner via DNS. Exemplo: cat </ dev / tcp / hostname / 5432
Michael Hobbs
404

Bom e detalhado! Nas páginas do manual.
Porta única:

nc -zv 127.0.0.1 80

Várias portas:

nc -zv 127.0.0.1 22 80 8080

Gama de portas:

nc -zv 127.0.0.1 20-30
Subhranath Chunder
fonte
6
Parece ser a melhor resposta, obrigado. ;-)
lpapp
6
Isso travou quando tentado no Ubuntu 14.04 (Trusty Tahr) para um servidor remoto (a mesma LAN) para portas fechadas (atingiu o tempo limite após 127 segundos) - portanto, não é muito adequado para scripts. No entanto, funcionou para um serviço que tinha uma porta aberta. Usar a opção "-w2" pode ser a solução.
Peter Mortensen
6
Use a opção -u para portas UDP.
Efren
8
Na versão 6.4 do ncat -z não é reconhecido. Eu era capaz de fazer sem z
smishra
5
Você pode verificar vários intervalos com: nc -zv 127.0.0.1 22,80,8080,20-30,443-446(versão nc: 1.107-4).
bobbel
102

O Netcat é uma ferramenta útil:

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

Produzirá 0se a porta 123 estiver aberta e 1se estiver fechada.

thnee
fonte
Essa é uma resposta muito mais elegante e com script do que a minha. É lamentável para mim que os administradores de sistemas preocupados com a segurança que retiveram telnettambém retiram nc(embora - estranhamente - não curlou wget).
21113 Steve HHH
Sim, isso é completamente arbitrário e bobo.
19593 thnee
3
Que FORcomecem as declarações!
Chad Harrison
1
Isso travou quando tentado no Ubuntu 14.04 (Trusty Tahr) para um servidor remoto (a mesma LAN) para portas fechadas (atingiu o tempo limite após 127 segundos) - portanto, não é muito adequado para scripts. No entanto, funcionou para um serviço que tinha uma porta aberta, retornando 0. Usar a opção "-w2" poderia ser a solução.
Peter Mortensen
1
Eu acho que -G 2seria mais apropriado para o tempo limite de TCP
AB
58

O método mais simples, sem fazer uso de outra ferramenta, como socat, é o descrito na resposta do @ lornix acima. Isso é apenas para adicionar um exemplo real de como alguém usaria o dispositivo psuedo /dev/tcp/...no Bash se você quisesse, por exemplo, testar se outro servidor tinha uma determinada porta acessível através da linha de comando.

Exemplos

Digamos que eu tenha um host na minha rede chamado 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

O motivo pelo qual você deseja agrupar os echo > /dev/...parênteses dessa maneira (echo > /dev/...)é porque, se não o fizer, com testes de conexões inativos, você verá esses tipos de mensagens.

$ (echo > /dev/tcp/skinner/223) && echo hi
bash: connect: Connection refused
bash: /dev/tcp/skinner/223: Connection refused

Eles não podem simplesmente ser redirecionados, /dev/nullpois vêm da tentativa de gravar dados no dispositivo /dev/tcp. Então, capturamos toda essa saída dentro de um subcomando, ou seja, (...cmds...)redirecionamos a saída do subcomando.

slm
fonte
Isto e excelente. Gostaria que fosse votado até o topo. Eu só li isso na parte inferior da página porque rolei acidentalmente antes de fechá-la.
Still.Tony
@ Okuma.Tony - sim, é sempre um problema com os Qs que têm muitas respostas 8-). Obrigado pelo feedback, porém, é apreciado.
Slm
46

Descobri que curlo trabalho pode ser feito de maneira semelhante telnete curlaté lhe dirá qual protocolo o ouvinte espera.

Construa um URI HTTP a partir do nome do host e da porta como o primeiro argumento para curl. Se curlpuder se conectar, ele reportará uma incompatibilidade de protocolo e sairá (se o ouvinte não for um serviço da web). Se curlnão conseguir se conectar, o tempo limite será excedido.

Por exemplo, a porta 5672 no host 10.0.0.99 está fechada ou bloqueada por um firewall:

$ curl http://10.0.0.99:5672
curl: (7) couldn't connect to host

No entanto, a partir de um sistema diferente, a porta 5672 no host 10.0.0.99 pode ser alcançada e parece estar executando um ouvinte AMQP.

$ curl http://10.0.0.99:5672
curl: (56) Failure when receiving data from the peer
AMQP

É importante distinguir entre as diferentes mensagens: a primeira falha ocorreu porque curlnão foi possível conectar à porta. A segunda falha é um teste de sucesso, embora seja curlesperado um ouvinte HTTP em vez de um ouvinte AMQP.

Steve HHH
fonte
5
Se a curvatura não estiver disponível, o wget poderá estar. wget -qS -O- http://ip.add.re.ss:portefetivamente deve fazer a mesma coisa.
um CVn
4
Isso funciona mesmo com um nome de host, ex. curl myhost:22.
에이 바
Isso pode estar incorreto. Estou tendo um serviço tomcat em execução, mas obtendo um erro 404. # curl -k 192.168.194.4:6443 <html><head> <title> Apache Tomcat / 7.0.34 - Relatório de erros </title> <style> <! - H1 --- HR {color: # 525D76;} -> </style> </head><body> <h1> Status HTTP 404 - / </h1> <HR size = "1" noshade = "noshade"> <p> <b> tipo </b> Relatório de status </p> <p> <b> mensagem </b> <u>/</u></p><p> <b> descrição </b> <u> O recurso solicitado não está disponível. </u> </p> <HR size = "1" noshade = "noshade"> <h3> Apache Tomcat / 7.0.34 </h3> </body> </html>
Veja meu post com abordagem semelhante.
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!

Espero que resolva o seu problema :)

Mohammad Shahid Siddiqui
fonte
1
Sim, isso é melhor - atingir o tempo limite quase imediatamente para portas fechadas.
22615 Peter Mortensen
1
Isso sempre usa TCP ou existe uma maneira de fazer com que ele verifique UDP?
kmoe
6

Eu estava lutando por um dia inteiro porque nenhuma dessas respostas parecia funcionar para mim. O problema é que a versão mais recente do ncnão possui mais o -zsinalizador, enquanto o acesso direto via TCP (conforme @lornix e @slm) falha quando o host não está acessível. Acabei encontrando esta página , onde finalmente encontrei não um, mas dois exemplos de trabalho:

  1. nc -w1 127.0.0.1 22 </dev/null

    (a -wbandeira cuida do tempo limite e a </dev/nullsubstitui -z)

  2. timeout 1 bash -c '(echo > /dev/tcp/127.0.0.1/22) >/dev/null 2>&1'

    (o timeoutcomando cuida do tempo limite e o restante é de @slm)

Em seguida, basta usar &&e / ou ||(ou até $?) para extrair o resultado. Felizmente, alguém encontrará essa informação útil.

Azukikuru
fonte
4

Combinando as respostas de @kenorb e @Azukikuru, você pode testar a porta aberta / fechada / com firewall.

timeout 1 bash -c '</dev/tcp/127.0.0.1/22 && echo Port is open || echo Port is closed' || echo Connection timeout

Outra abordagem com curl para alcançar qualquer porta

curl telnet://127.0.0.1:22
Miguel Ferreira
fonte
3

Aqui está uma função que escolherá um dos métodos, dependendo do que estiver instalado no seu sistema:

# 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
Robert Boyd
fonte
2

Não deve estar disponível na sua caixa, mas tente com nmap.

peperunas
fonte
4
nmapé uma boa ferramenta, mas não está disponível nesses sistemas. Em vez de fazer o download nmap, compilá-lo, instalá-lo no meu diretório pessoal e copiá-lo para todos os outros sistemas, eu esperava encontrar uma maneira de usar as ferramentas existentes disponíveis na maioria das instalações do Linux.
21113 Steve HHH
1

para referência, expandindo a resposta @peperunas ':

A maneira de usar o nmap para testar é:

nmap -p 22 127.0.0.1

(o exemplo acima usa localhost para fins de demonstração)

user138278
fonte
0

Se você precisar testar mais do que no sistema, poderá usar nossa ferramenta de teste dda-serverspec ( https://github.com/DomainDrivenArchitecture/dda-serverspec-crate ) para essas tarefas. Você pode definir sua expectativa

{:netcat [{:host "mywebserver.com" :port "443"}
          {:host "telnet mywebserver.com" :port "80"}
          {:host "telnet mywebserver.com" :port "8443"}]}

e teste essas expectativas no host local ou nos hosts remotos (conecte pelo ssh). Para testes remotos, você deve definir um destino:

{: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"}}

Você pode executar o teste com java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Sob o capô, estamos usando o netcat como proprosed acima ...

jerger
fonte