¿Prueba eficientemente si un puerto está abierto en Linux?

197

A partir de un script bash, ¿cómo puedo averiguar rápidamente si un puerto 445está abierto / escuchando en un servidor?

He probado un par de opciones, pero quiero algo rápido:
1. lsof -i :445 (Toma segundos)
2. netstat -an |grep 445 |grep LISTEN(Toma segundos)
3. telnet(no regresa)
4. nmap, netcatno están disponibles en el servidor

Será bueno saber de una manera que no enumere primero y greps después de eso.

Aman Jain
fuente
1
¿Netcat está disponible? Tiene una ruta de falla rápida IIRC. netcat.sourceforge.net
JimR
55
netstat -lnt(con -ty sin -a) limitará la salida a escuchar solo conexiones TCP. Puede acelerarse un poco. Puede agregar -4para IPv4 solo si no necesita IPv6.
Bartosz Moczulski
lsof -i es un favorito personal.
Matt Joyce
14
netstat -an | grep PORTNUMBER | grep -i listenSi la salida está vacía, el puerto no está en uso.
Automatix
No sé por qué lsofes lento para usted, pero normalmente es la mejor de las soluciones que enumeró. Su netstatsolución no es muy confiable (puede adivinarla siempre que la use grep; de todos modos, devuelve verdadero si alguien está escuchando, por ejemplo, 4450). telnete netcatintenta crear una conexión, que no siempre es lo que quieres.
petersohn

Respuestas:

155

Una sorpresa que descubrí recientemente es que Bash admite de forma nativa conexiones tcp como descriptores de archivos . Usar:

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

Estoy usando 6 como descriptor de archivo porque 0,1,2 son stdin, stdout y stderr. Bash a veces usa 5 para procesos secundarios , por lo que 3,4,6,7,8 y 9 deberían ser seguros.

Según el comentario a continuación, para probar la escucha en un servidor local en un 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 si alguien está escuchando, intente conectarse mediante loopback. Si falla, entonces el puerto está cerrado o no se nos permite el acceso. Luego, cierre la conexión.

Modifique esto para su caso de uso, como enviar un correo electrónico, salir del script en caso de error o iniciar el servicio requerido.

Spencer Rathbun
fuente
2
Esto solo me ahorcó.
Aman Jain
@AmanJain cat espera a que se cierre EOF o Ctrl-C. Tendrá que ajustar esto para su protocolo. Por cierto, ¿estás ejecutando esto en un servidor remoto?
Spencer Rathbun
Quiero incrustar el código de comprobación de puerto en un script en el servidor, en /etc/init.d/
Aman Jain
@AmanJain Lo he actualizado para un sistema local. ¿Solo quieres comprobar si está escuchando correctamente? ¿No hay ninguna verificación de protocolo, como solicitar una página a través de http?
Spencer Rathbun
1
Este no es un método confiable, ya que no todos los sistemas operativos (por ejemplo, ubuntu 16 como descubrí hoy) se envían con bash compilado para construir el /dev/tcp/IP/PORTárbol
dyasny
107

Aquí hay una muy corta con "respuesta rápida": ¿Cómo probar si el puerto TCP remoto se abre desde el script de Shell?

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

Lo uso con 127.0.0.1 como dirección "remota".

esto devuelve "0" si el puerto está abierto y "1" si el puerto está cerrado

p.ej

nc -z 127.0.0.1 80; echo $?

-z Especifica que nc solo debe escanear para escuchar demonios, sin enviarles ningún dato. Es un error usar esta opción junto con la opción -l.

Negro
fuente
2
Esa parece ser la forma más fácil, gracias. Sin embargo, el enlace del script de muestra ya no funciona, pero de todos modos se explica por sí mismo.
derFunk
¡Agradable! Esto es mucho más rápido que las otras respuestas en un servidor con muchos puertos abiertos. Regresa en <0.01 segundos para mí mientras netstat / lsof toma 1s +
Tim
2
El distintivo -z no está disponible en el ncat basado en nmap con el que se distribuyen las distribuciones más recientes: Fedora, Centos, etc. (nmap-ncat-6.01-9.fc18.x86_64)
Zack
9
Contra-intuitivamente, esto devuelve "0" si el puerto está abierto y "1" si el puerto está cerrado.
Sean
3
Los comandos de @Sean unix generalmente devuelven '0' para indicar éxito y no cero para falla. Entonces '0' indica que se conectó con éxito y no es cero que no se conectó por alguna razón. Sin embargo, tenga en cuenta que algunas versiones de 'nc' no admiten el argumento '-z', por lo que stackoverflow.com/a/25793128/6773916 es posiblemente una mejor solución.
Rich Sedman el
89

Puede usar netstat de esta manera para obtener resultados mucho más rápidos:

En Linux:

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

En Mac:

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

Esto generará una lista de procesos que escuchan en el puerto (445 en este ejemplo) o no generará nada si el puerto está libre.

anubhava
fuente
1
Su sintaxis netstat es incorrecta. netstat -ln --tcp funciona, pero sigue siendo lento
Aman Jain
66
En realidad, es la sintaxis correcta, pero probablemente estés usando Linux y yo estoy en Mac. Para Linux use esto:netstat -lnt | awk '$6 == "LISTEN" && $4 ~ ".445"'
anubhava
21
esto no produjo nada.
Jürgen Paul
1
Sin embargo, la pregunta era sobre Linux, por lo que quizás el comentario debería estar en la respuesta.
UpTheCreek
1
Para verificar el puerto 80 que necesitaba usar awk '$6 == "LISTEN" && $4 ~ "80$"'. En lugar de verificar el punto antes del número de puerto con \.80, solía 80$. De lo contrario, esto también coincide con las direcciones IP que contienen .80y los puertos que comienzan con 80, por ejemplo 8000,.
Patrick Oscity
37

Puedes usar netcat para esto.

nc ip port < /dev/null

se conecta al servidor y cierra la conexión directamente nuevamente. Si netcat no puede conectarse, devuelve un código de salida distinto de cero. El código de salida se almacena en la variable $ ?. Como ejemplo,

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

devolverá 0 si y solo si netcat podría conectarse con éxito al puerto.

Tony
fuente
1
Esta respuesta necesita más votos a favor. nc funciona perfectamente para este caso. El truco / dev / tcp es inteligente, pero parece difícil implementar un script con interrupciones de señal.
Avindra Goolcharan
55
nctiene la -zbandera para este propósito, que no requiere tomar entrada de /dev/null. Ya hay una respuesta usando la -zbandera de arriba.
Abe Voelker
2
@AbeVoelker No todas las versiones de nc admiten la bandera -z. Estoy en CentOS 7 y descubrí que la solución de Tony era lo que necesitaba.
Shadoninja el
@Shadoninja ¡Es bueno saberlo! Si pudiera editar la frivolidad de mi comentario de 2014, lo haría.
Abe Voelker
'nc' ya no admite '-z', por lo que esta respuesta parece ser la mejor solución.
Rich Sedman el
18

Basado en la respuesta de Spencer Rathbun, usando bash:

true &>/dev/null </dev/tcp/127.0.0.1/$PORT && echo open || echo closed
usuario1338062
fuente
Bien, suprimirá el mensaje "Conexión rechazada". Salidas automáticas si el servicio acepta la conexión sin esperar para siempre.
Seff
La mejor solución para servicios que no envían datos después de una nueva conexión. Aproximadamente 20 veces más rápido que llamar a netcat. Se puede acortar a: &>/dev/null </dev/tcp/127.0.0.1/$PORT
ens
16

están listados en / proc / net / tcp.

es la segunda columna, después de ":", en 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  

así que supongo que uno de los :50de la tercera columna debe ser stackoverflow: o)

mira man 5 procpara más detalles. y elegir eso aparte con sed, etc. se deja como un ejercicio para el lector amable ...

Andrew Cooke
fuente
10
ss -tl4 '( sport = :22 )'

¿2 ms es lo suficientemente rápido?

Agregue los dos puntos y esto funciona en Linux

leucos
fuente
2
Genial, sses incluso un poco más rápido que nc. les para escuchar , 4es para IPv4; sportsignifica (por supuesto) el puerto de origen . El comando anterior supone un puerto TCP de escucha ( topción): use la uopción para UDP, o ninguno de ellos para ambos protocolos. Más información sobre sscomo siempre en Nixcraft . NOTA: los ssfiltros no funcionan aquí, no sé por qué (bash 4.3.11, ss utility, iproute2-ss131122), tienen que ir con grep .
Campa
Lástima que ese sscomando no devuelva un código de salida que refleje su hallazgo; siempre devuelve 0 código de salida.
John Greene
| grep LISTEN?
leucos
Lo consigo State Recv-Q Send-Q Local Address:Port Peer Address:Porty ahora? ¿Qué significa esto?
Black
6

Aquí hay uno que funciona tanto para Mac como para Linux:

netstat -aln | awk '$6 == "LISTEN" && $4 ~ "[\\.\:]445$"'
Artur Bodera
fuente
Creo que puedes eliminarlo con seguridad [\\.\:].
Patrick Oscity
6
nc -l 8000

Donde 8000 es el número de puerto. Si el puerto está libre, iniciará un servidor que puede cerrar fácilmente. Si no es así, arrojará un error:

nc: Address already in use
Jose enrique
fuente
5

Quería verificar si un puerto está abierto en uno de nuestros servidores de prueba de Linux. Pude hacerlo intentando conectarme con telnet desde mi máquina de desarrollo al servidor de prueba. En su máquina de desarrollo, intente ejecutar:

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

En este ejemplo, quiero verificar si el puerto 8080 está abierto en el host test2.host.com

razvang
fuente
1

tcping es una gran herramienta con una sobrecarga muy baja. También tiene un argumento de tiempo de espera para hacerlo más 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.
Payam
fuente
1
No estoy seguro de que valga la pena instalar tcping cuando la solución de Spencer no requiere instalaciones adicionales, pero esta es definitivamente la solución más limpia y legible para los humanos.
bdombro
1

También puedes usar el comando netcat

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

o

nc -zv [ip] [port]

-z: establece nc para simplemente escanear en busca de demonios, sin enviarles ningún dato.
-v: habilita el modo detallado.

Saurabh
fuente
-2

nmapes la herramienta correcta Simplemente usenmap example.com -p 80

Puede usarlo desde un servidor local o remoto. También le ayuda a identificar si un firewall está bloqueando el acceso.

zainengineer
fuente
-4

Si estás usando iptables prueba:

iptables -nL

o

iptables -nL | grep 445
Noz
fuente
que solo enumera las reglas de iptables ... que pueden no tener correlación con los puertos abiertos.
David Goodwin