saber - Probar desde el script de shell si el puerto TCP remoto está abierto
ver puertos abiertos linux netstat (16)
comprobar puertos utilizando bash
Ejemplo
$ ./test_port_bash.sh 192.168.7.7 22
el puerto 22 esta abierto
Código
HOST=$1
PORT=$2
exec 3> /dev/tcp/${HOST}/${PORT}
if [ $? -eq 0 ];then echo "the port $2 is open";else echo "the port $2 is closed";fi
Estoy buscando un método rápido y sencillo para probar correctamente si un puerto TCP determinado está abierto en un servidor remoto, desde un script de Shell.
Me las arreglé para hacerlo con el comando telnet, y funciona bien cuando se abre el puerto, pero parece que no se agota cuando no lo está y simplemente se cuelga allí ...
Aquí hay una muestra:
l_TELNET=`echo "quit" | telnet $SERVER $PORT | grep "Escape character is"`
if [ "$?" -ne 0 ]; then
echo "Connection to $SERVER on port $PORT failed"
exit 1
else
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
fi
O bien necesito una forma mejor, o una forma de forzar el tiempo de espera de telnet si no se conecta en menos de 8 segundos, por ejemplo, y devolver algo que pueda detectar en Shell (código de retorno o cadena en la salida estándar).
Conozco el método Perl, que utiliza el módulo IO :: Socket :: INET y escribió un script exitoso que prueba un puerto, pero preferiría evitar usar Perl si es posible.
Nota: Esto es lo que mi servidor está ejecutando (desde donde necesito ejecutar esto)
SunOS 5.10 Generic_139556-08 i86pc i386 i86pc
nmap-ncat para probar el puerto local que aún no está en uso
availabletobindon() {
port="$1"
nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q ''Idle timeout expired''
return "$?"
}
TOC:
- Usando bash y
timeout
- Mando
- Ejemplos
- Utilizando
nc
- Mando
- RHEL 6 (nc-1.84)
- Instalación
- Ejemplos
- RHEL 7 (nmap-ncat-6.40)
- Instalación
- Ejemplos
- Observaciones
Usando bash y timeout
:
Tenga en cuenta que el timeout
debe estar presente con RHEL 6+, o alternativamente se encuentra en GNU coreutils 8.22. En MacOS, instálalo usando brew install coreutils
y gtimeout
como gtimeout
.
Mando:
$ timeout $TIMEOUT_SECONDS bash -c "</dev/tcp/${HOST}/${PORT}"; echo $?
Si está parametrizando el host y el puerto, asegúrese de especificarlos como ${HOST}
y ${PORT}
como se muestra arriba. No los especifique simplemente como $HOST
y $PORT
, es decir, sin llaves; No funcionará en este caso.
Ejemplo:
Éxito:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/80"; echo $?
0
Fracaso:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
124
Si debe preservar el estado de salida de bash
,
$ timeout --preserve-status 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
143
Utilizando nc
:
Tenga en cuenta que una versión incompatible con versiones anteriores de nc
se instala en RHEL 7.
Mando:
Tenga en cuenta que el siguiente comando es único, ya que es idéntico para RHEL 6 y 7. Solo la instalación y la salida son diferentes.
$ nc -w $TIMEOUT_SECONDS -v $HOST $PORT </dev/null; echo $?
RHEL 6 (nc-1.84):
Instalación:
$ sudo yum install nc
Ejemplos:
Éxito:$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
Fracaso:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
nc: connect to canyouseeme.org port 81 (tcp) timed out: Operation now in progress
1
Si el nombre de host se asigna a varias direcciones IP, el comando que falla arriba se desplazará a través de muchos o todos ellos. Por ejemplo:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
1
RHEL 7 (nmap-ncat-6.40):
Instalación:
$ sudo yum install nmap-ncat
Ejemplos:
Éxito:$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connected to 52.202.215.126:80.
Ncat: 0 bytes sent, 0 bytes received in 0.22 seconds.
0
Fracaso:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1
Si el nombre de host se asigna a varias direcciones IP, el comando que falla arriba se desplazará a través de muchos o todos ellos. Por ejemplo:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection to 104.43.195.251 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.100.122.175 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.96.52.53 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 191.239.213.197 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection timed out.
1
Observaciones:
El argumento -v
( --verbose
) y el echo $?
Los comandos son, por supuesto, sólo para ilustración.
Como señaló B. Rhodes, nc
hará el trabajo. Una forma más compacta de usarlo:
nc -z <host> <port>
De esa manera, nc
solo verificará si el puerto está abierto, saliendo con 0 en caso de éxito, 1 en caso de fallo.
Para una verificación interactiva rápida (con un tiempo de espera de 5 segundos):
nc -z -v -w5 <host> <port>
Con netcat
puedes verificar si un puerto está abierto así:
nc my.example.com 80 < /dev/null
El valor de retorno de nc
será exitoso si se abrió el puerto TCP, y falla (normalmente el código de retorno 1) si no pudo establecer la conexión TCP.
En Bash, usar archivos de pseudodispositivo para conexiones TCP / UDP es sencillo. Aquí está el guión:
#!/usr/bin/env bash
SERVER=example.com
PORT=80
</dev/tcp/$SERVER/$PORT
if [ "$?" -ne 0 ]; then
echo "Connection to $SERVER on port $PORT failed"
exit 1
else
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
fi
Pruebas:
$ ./test.sh
Connection to example.com on port 80 succeeded
Aquí hay una sola línea (sintaxis Bash):
</dev/tcp/localhost/11211 && echo Port open. || echo Port closed.
Tenga en cuenta que algunos servidores pueden estar protegidos por firewall contra los ataques de inundación SYN, por lo que puede experimentar un tiempo de espera de conexión TCP (~ 75secs). Para solucionar el problema del tiempo de espera, intente:
timeout 1 bash -c "</dev/tcp/.com/81" && echo Port open. || echo Port closed.
Consulte: ¿Cómo disminuir el tiempo de espera de las llamadas al sistema TCP ()?
En algunos casos en los que las herramientas como curl, telnet, nc o nmap no están disponibles, todavía tiene una oportunidad con wget
if [[ $(wget -q -t 1 --spider --dns-timeout 3 --connect-timeout 10 host:port; echo $?) -eq 0 ]]; then echo "OK"; else echo "FAIL"; fi
Es bastante fácil hacerlo con las opciones -z
y -w TIMEOUT
para nc
, pero no todos los sistemas tienen nc
instalado. Si tienes una versión suficientemente reciente de bash, esto funcionará:
# Connection successful:
$ timeout 1 bash -c ''cat < /dev/null > /dev/tcp/google.com/80''
$ echo $?
0
# Connection failure prior to the timeout
$ timeout 1 bash -c ''cat < /dev/null > /dev/tcp/sfsfdfdff.com/80''
bash: sfsfdfdff.com: Name or service not known
bash: /dev/tcp/sfsfdfdff.com/80: Invalid argument
$ echo $?
1
# Connection not established by the timeout
$ timeout 1 bash -c ''cat < /dev/null > /dev/tcp/google.com/81''
$ echo $?
124
Lo que sucede aquí es que el timeout
ejecutará el subcomando y lo eliminará si no sale dentro del tiempo de espera especificado (1 segundo en el ejemplo anterior). En este caso, bash
es el subcomando y usa su manejo especial / dev / tcp para intentar abrir una conexión al servidor y al puerto especificado. Si bash
puede abrir la conexión dentro del tiempo de espera, cat
cerrará inmediatamente (ya que está leyendo desde /dev/null
) y saldrá con un código de estado de 0
que se propagará a través de bash
y luego se timeout
. Si bash
obtiene una falla de conexión antes del tiempo límite especificado, bash
saldrá con un código de salida de 1, que también se devolverá. Y si bash no puede establecer una conexión y el tiempo de espera especificado caduca, el timeout
anulará a bash
y saldrá con un estado de 124.
Esto usa telnet detrás de escena y parece funcionar bien en mac / linux. No usa netcat debido a las diferencias entre las versiones en linux / mac, y esto funciona con una instalación mac predeterminada.
Ejemplo:
$ is_port_open.sh 80 google.com
OPEN
$ is_port_open.sh 8080 google.com
CLOSED
is_port_open.sh
PORT=$1
HOST=$2
TIMEOUT_IN_SEC=${3:-1}
VALUE_IF_OPEN=${4:-"OPEN"}
VALUE_IF_CLOSED=${5:-"CLOSED"}
function eztern()
{
if [ "$1" == "$2" ]
then
echo $3
else
echo $4
fi
}
# cross platform timeout util to support mac mostly
# https://gist.github.com/jaytaylor/6527607
function eztimeout() { perl -e ''alarm shift; exec @ARGV'' "$@"; }
function testPort()
{
OPTS=""
# find out if port is open using telnet
# by saving telnet output to temporary file
# and looking for "Escape character" response
# from telnet
FILENAME="/tmp/__port_check_$(uuidgen)"
RESULT=$(eztimeout $TIMEOUT_IN_SEC telnet $HOST $PORT &> $FILENAME; cat $FILENAME | tail -n1)
rm -f $FILENAME;
SUCCESS=$(eztern "$RESULT" "Escape character is ''^]''." "$VALUE_IF_OPEN" "$VALUE_IF_CLOSED")
echo "$SUCCESS"
}
testPort
Necesitaba un script corto que se ejecutó en cron y no tiene salida. Resuelvo mis problemas usando nmap
open=`nmap -p $PORT $SERVER | grep "$PORT" | grep open`
if [ -z "$open" ]; then
echo "Connection to $SERVER on port $PORT failed"
exit 1
else
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
fi
Para ejecutarlo, debe instalar nmap porque no es un paquete instalado por defecto.
Necesitaba una solución más flexible para trabajar en múltiples repositorios de git, por lo que escribí el siguiente código sh basado en 1 y 2 . Puede usar la dirección de su servidor en lugar de gitlab.com y su puerto en lugar de 22.
SERVER=gitlab.com
PORT=22
nc -z -v -w5 $SERVER $PORT
result1=$?
#Do whatever you want
if [ "$result1" != 0 ]; then
echo ''port 22 is closed''
else
echo ''port 22 is open''
fi
Si bien era una pregunta antigua, acabo de abordar una variante, pero ninguna de las soluciones aquí eran aplicables, así que encontré otra, y la estoy agregando para la posteridad. Sí, ya sé que el OP dijo que estaban al tanto de esta opción y que no les convenía, pero para cualquiera que los siga después podría ser útil.
En mi caso, quiero probar la disponibilidad de un servicio local apt-cacher-ng
de una compilación de docker
. Eso significa que no se puede instalar absolutamente nada antes de la prueba. No nc
, nmap
, expect
, telnet
o python
. Sin embargo, perl
está presente, junto con las bibliotecas principales, así que usé esto:
perl -MIO::Socket::INET -e ''exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))''
Si desea usar nc
pero no tiene una versión que admita -z
, intente usar --send-only
:
nc --send-only <IP> <PORT> </dev/null
y con timeout:
nc -w 1 --send-only <IP> <PORT> </dev/null
y sin búsqueda de DNS si es una IP:
nc -n -w 1 --send-only <IP> <PORT> </dev/null
Devuelve los códigos como el -z
función de si puede conectarse o no.
Si está utilizando ksh o bash , ambos admiten la redirección de E / S a / desde un socket mediante la construcción / dev / tcp / IP / PORT . En este ejemplo de shell Korn estoy redireccionando st-in de no-op (:) desde un socket:
W$ python -m SimpleHTTPServer &
[1] 16833
Serving HTTP on 0.0.0.0 port 8000 ...
W$ : </dev/tcp/127.0.0.1/8000
El shell imprime un error si el socket no está abierto:
W$ : </dev/tcp/127.0.0.1/8001
ksh: /dev/tcp/127.0.0.1/8001: cannot open [Connection refused]
Por lo tanto, puede usar esto como prueba en una condición if :
SERVER=127.0.0.1 PORT=8000
if (: < /dev/tcp/$SERVER/$PORT) 2>/dev/null
then
print succeeded
else
print failed
fi
El no-op está en una subshell, así que puedo tirar std-err si la redirección std-in falla.
A menudo utilizo / dev / tcp para verificar la disponibilidad de un recurso a través de HTTP:
W$ print arghhh > grr.html
W$ python -m SimpleHTTPServer &
[1] 16863
Serving HTTP on 0.0.0.0 port 8000 ...
W$ (print -u9 ''GET /grr.html HTTP/1.0/n'';cat <&9) 9<>/dev/tcp/127.0.0.1/8000
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.6.1
Date: Thu, 14 Feb 2013 12:56:29 GMT
Content-type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Feb 2013 12:55:44 GMT
arghhh
W$
Este one-liner abre el descriptor de archivos 9 para leer y escribir en el socket, imprime el HTTP GET en el socket y usa cat
para leer desde el socket.
Sobre la base de la respuesta más votada, aquí está una función para esperar a que se abran dos puertos, con un tiempo de espera también. Tenga en cuenta los dos puertos que deben estar abiertos, 8890 y 1111, así como los max_attempts (1 por segundo).
function wait_for_server_to_boot()
{
echo "Waiting for server to boot up..."
attempts=0
max_attempts=30
while ( nc 127.0.0.1 8890 < /dev/null || nc 127.0.0.1 1111 < /dev/null ) && [[ $attempts < $max_attempts ]] ; do
attempts=$((attempts+1))
sleep 1;
echo "waiting... (${attempts}/${max_attempts})"
done
}
Supongo que es demasiado tarde para una respuesta, y puede que esta no sea una buena, pero aquí tienes ...
¿Qué hay de ponerlo dentro de un bucle while con un temporizador de algún tipo? Soy más un tipo de Perl que Solaris, pero dependiendo del shell que estés usando, deberías poder hacer algo como:
TIME = ''date +%s'' + 15
while TIME != `date +%s''
do whatever
Y luego simplemente agregue una bandera en el bucle while, de modo que si se agota antes de completar, puede citar el tiempo de espera como motivo del error.
Sospecho que el telnet también tiene un interruptor de tiempo de espera, pero justo en la parte superior de mi cabeza, creo que lo anterior funcionará.