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

Probar si un puerto en un sistema remoto es alcanzable (sin telnet)

En los viejos tiempos, usábamos telnet para ver si un puerto en un host remoto estaba abierto: telnet hostname port intentaba conectarse a cualquier puerto en cualquier host y le daba acceso al flujo TCP crudo.

En estos días, los sistemas en los que trabajo no tienen telnet instalado (por razones de seguridad), y todas las conexiones salientes a todos los hosts están bloqueadas por defecto. Con el tiempo, es fácil perder la pista de qué puertos están abiertos a qué hosts.

¿Existe otra manera de probar si un puerto en un sistema remoto está abierto - usando un sistema Linux con un número limitado de paquetes instalados, y telnet no está disponible?

Respuestas (13)

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

¡Lindo y verborreico! De las páginas de manual. Un solo puerto:

nc -zv 127.0.0.1 80

Múltiples puertos:

nc -zv 127.0.0.1 22 80 8080

Rango de puertos:

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

Bash ha sido capaz de acceder a los puertos TCP y UDP por un tiempo. Desde la página del hombre:

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

Así que podrías usar algo como esto:

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

Netcat es una herramienta útil:

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

dará salida a 0 si el puerto 123 está abierto, y a 1 si está cerrado.

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

El método más simple, sin hacer uso de otra herramienta, como socat, es el que se describe en la respuesta de @lornix arriba. Esto es sólo para añadir un ejemplo real de cómo se haría uso del dispositivo psuedo /dev/tcp/... dentro de Bash si se quisiera, por ejemplo, probar si otro servidor tiene un puerto determinado accesible a través de la línea de comandos.

Ejemplos

Digamos que tengo un host en mi red llamado 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

La razón por la que quieres envolver el echo > /dev/... entre paréntesis como este, (echo > /dev/...) es porque si no lo haces, entonces con las pruebas de conexiones que están caídas, obtendrás este tipo de mensajes que aparecen.

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

Estos no pueden ser simplemente redirigidos a /dev/null ya que vienen del intento de escribir datos en el dispositivo /dev/tcp. Así que capturamos toda esa salida dentro de un subcomando, es decir (...cmds...) y redirigimos la salida del subcomando.

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

Encontré que curl puede hacer el trabajo de manera similar a telnet, e incluso curl le dirá qué protocolo espera el oyente.

Construir una URI HTTP del nombre de host y el puerto como primer argumento para curl. Si curl puede conectarse, reportará un desajuste de protocolo y saldrá (si el oyente no es un servicio web). Si curl no puede conectarse, se agotará el tiempo de espera.

Por ejemplo, el puerto 5672 en el host 10.0.0.99 está cerrado o bloqueado por un cortafuegos:

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

Sin embargo, desde un sistema diferente, el puerto 5672 en el host 10. 0.0.99 puede ser alcanzado, y parece estar ejecutando un receptor AMQP.

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

Es importante distinguir entre los diferentes mensajes: el primer fallo fue porque curl no pudo conectarse al puerto. El segundo fallo es una prueba de éxito, aunque curl esperaba un receptor HTTP en lugar de un receptor 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 esto resuelva tu problema :)

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

Aquí hay una línea:

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

usando la sintaxis de Bash explicada en @ respuesta de lornix .

Para más información, compruebe: Guía avanzada de Bash-Scripting: Capítulo 29. /dev y /proc .

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

Estuve luchando todo el día porque ninguna de estas respuestas parecía funcionar para mí. El problema es que la versión más reciente de nc ya no tiene la bandera -z, mientras que el acceso directo vía TCP (como según @lornix y @slm) falla cuando el host no está localizable. Finalmente encontré esta página , donde finalmente encontré no uno sino dos ejemplos de trabajo:

  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'

Entonces, simplemente usa && y/o || (o incluso $?) para extraer el resultado. Con suerte, alguien encontrará esta información útil.

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

Combinando las respuestas de @kenorb y @Azukikuru se podría probar el puerto abierto/cerrado/confirmado.

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

Otro enfoque con rizo para llegar a cualquier puerto

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

Aquí hay una función que elegirá uno de los métodos dependiendo de lo que esté instalado en su 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

No debería estar disponible en tu caja, pero prueba con nmap.

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

para referencia, ampliando la respuesta de @peperunas:

la forma de usar nmap para probar, es:

nmap -p 22 127.0.0.1

(el ejemplo anterior usa localhost para propósitos de demostración)

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

Si tiene que probar más que en el sistema puede usar nuestra herramienta de pruebas dda-serverspec https://github.com/DomainDrivenArchitecture/dda-serverspec-crate ) para tales tareas. Puedes definir tus expectativas

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

y probar estas expectativas contra el host local o contra hosts remotos (conectar por ssh). Para las pruebas remotas tienes que definir un objetivo:

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

Puedes ejecutar la prueba con java -jar dda-serverspec.jar --targets targets.edn serverspec.edn

Bajo el capó estamos usando netcat como se indica arriba …