2013-07-19 16:54:10 +0000 2013-07-19 16:54:10 +0000
369
369

Teste se uma porta num sistema remoto é alcançável (sem telnet)

Nos velhos tempos, usávamos o telnet para ver se uma porta num host remoto estava aberta: o telnet hostname port tentava ligar-se a qualquer porta em qualquer host e dava-lhe acesso ao fluxo TCP bruto.

Hoje em dia, os sistemas em que trabalho não têm telnet instalado (por razões de segurança), e todas as ligações de saída para todos os hosts estão bloqueadas por defeito. Com o tempo, é fácil perder de vista quais as portas abertas para quais hosts.

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

Respuestas (13)

418
418
418
2013-12-03 21:34:41 +0000

Bom e verboso! Das páginas de homem. Porto único:

nc -zv 127.0.0.1 80

Portos múltiplos:

nc -zv 127.0.0.1 22 80 8080

Gama de portos:

nc -zv 127.0.0.1 20-30
297
297
297
2013-07-22 10:37:11 +0000

A Bash tem conseguido aceder às portas TCP e UDP durante algum tempo. A partir da página de 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.

Por isso 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!

104
104
104
2013-07-19 18:07:26 +0000

O Netcat é uma ferramenta útil:

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

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

61
61
61
2014-09-02 17:59:36 +0000

O método mais simples, sem recorrer a outra ferramenta, como socat, é o descrito na resposta de @lornix acima. Isto é apenas para adicionar um exemplo real de como se faria uso do psuedo-device /dev/tcp/... dentro do Bash se se quisesse, digamos, testar se outro servidor tinha uma dada porta acessível através da linha de comandos.

Exemplos

Digamos que tenho 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

A razão pela qual quer embrulhar o echo > /dev/... entre parênteses como este, (echo > /dev/...) é porque se não o fizer, então com testes de ligações que estão em baixo, verá aparecer este tipo de mensagens.

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

Estas não podem ser simplesmente redireccionadas para /dev/null uma vez que vêm da tentativa de escrever dados para o dispositivo /dev/tcp. Assim, captamos toda essa saída dentro de um sub-comando, ou seja, (...cmds...) e redireccionamos a saída do sub-comando.

48
48
48
2013-07-19 17:05:30 +0000

Descobri que o curl pode fazer o trabalho de forma semelhante ao telnet, e o curl irá mesmo dizer-lhe qual o protocolo que o ouvinte espera.

Constrói um URI HTTP a partir do nome da máquina e da porta como primeiro argumento para o curl. Se o curl conseguir ligar-se, irá reportar um desajuste de protocolo e sair (se o ouvinte não for um serviço web). Se o curl não conseguir conectar-se, ele irá desconectar-se.

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

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

Contudo, a partir de um sistema diferente, a porta 5672 no host 10. 0.0.99 pode ser alcançado, e parece estar a correr 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 foi porque o curl não conseguiu ligar-se à porta. A segunda falha é um teste de sucesso, embora curl esperasse um ouvinte HTTP em vez de um ouvinte AMQP.

13
13
13
2015-06-02 06:27:59 +0000
[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 :)

11
11
11
2016-03-16 11:21:40 +0000

Aqui está uma linha:

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

usando a sintaxe Bash explicada em @lornix answer .

Para mais informações, verifique: Guia avançado de Bash-Scripting: Capítulo 29. /dev e /proc .

8
8
8
2017-05-31 08:45:09 +0000

Lutei durante um dia inteiro porque nenhuma destas respostas parecia funcionar para mim. O problema é que a versão mais recente do nc já não tem a bandeira -z, enquanto o acesso directo via TCP (como de acordo com @lornix e @slm) falha quando o anfitrião não é alcançável. Acabei por encontrar esta página , onde finalmente encontrei não um mas dois exemplos de trabalho:

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

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

Depois, use simplesmente && e/ou || (ou mesmo $?) para extrair o resultado. Esperemos que alguém considere esta informação útil.

6
6
6
2018-08-10 12:20:04 +0000

Combinando as respostas de @kenorb e @Azukikuru você poderia testar porta aberta/fechada/escavada.

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 ondulação para chegar a qualquer porta

curl telnet://127.0.0.1:22
4
4
4
2019-02-12 20:21:11 +0000

Aqui está uma função que irá escolher um dos métodos dependendo do que está 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
2
2
2
2013-07-19 17:01:16 +0000

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

1
1
1
2019-08-07 23:17:13 +0000

para referência, expandindo na resposta de @peperunas:

a forma de utilizar nmap para testar, é:

nmap -p 22 127.0.0.1

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

0
0
0
2018-10-26 13:49:54 +0000

Se tiver de testar mais do que no sistema pode utilizar a nossa ferramenta de teste dda-serverspec https://github.com/DomainDrivenArchitecture/dda-serverspec-crate ) para tais tarefas. Pode definir as suas expectativas

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

e testar estas expectativas contra hosts locais ou contra hosts remotos (connect by ssh). Para testes remotos tem de definir um alvo:

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

Pode fazer o teste com java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Sob o capô usamos netcat como proprosed acima …