Automatizar  Telnet. Bash.⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

Aunque la utilidad telnet ha caído en desgracia y prácticamente no tiene uso, se suele utilizar como una forma rápida de verificar la disponibilidad de un servidor y/o servicio remotos.
Automatizaremos en este uso a telnet, de forma que podamos usarlo en un script Bash.

Uso descrito

$ # Si no dispones de un servidor telnet local...
$ telnet localhost
Trying ::1...
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
$
$ # Suponiendo que dispones de un servidor web local...
$ telnet localhost 80
Trying ::1...
Connected to localhost.
Escape character is '^]'.
Si no es posible realizar la conexión al servidor:puerto especificado obtenemos un error y en caso contrario nos encontramos en la consola de comando de telnet, de la que hemos de salir de forma manual. Con esta interfaz, es complejo automatizar este caso de uso, ya que hemos de recurrir a utilizar 'here document' y analizar la respuesta de telnet o bien utilizar utilidades del tipo expect, o quizás no...

Morir matando

El funcionamiento básico de telnet se basa en el uso de un pseudoterminal para redirigir al usuario hasta el servidor, vale y...

Qué pasaría si se incluyese al comando telnet en una pipe,

$ telnet localhost | echo 'pipe end'
pipe end
telnet: Unable to connect to remote host: Connection refused
$
$ telnet localhost 80 | echo 'pipe end'
pipe end
$
En el caso que no se pueda realizar la conexión tenemos un mensaje de error, pero lo interesante es lo que ocurre si la conexión tiene éxito; inmediatamente telnet cierra la pipe para sustituirla por su pseudoterminal y al hacer esto la shell finaliza el proceso telnet, ya que se encuentra en una pipe que ha sido cerrada; ya es posible distinguir entre conexión fallida y exitosa, sólo es necesario verificar si hay mensaje o no de error.

Puliendo el tema

En una pipe es necesario que existan al menos dos procesos que quieran comunicarse; necesitamos de un comando que no tenga efectos colaterales, vamos que no haga nada, :, null command; en Bash equivale a la no operación, evaluándose como el valor true en caso de que sea necesario.
$ telnet localhost | :
telnet: Unable to connect to remote host: Connection refused
$
$ telnet localhost 80 | :
$

Una función

Tras varias iteraciones, he acabado definiendo la función Bash siguiente,
##
# telnet_scan [server] [port] [timeout]
#   Try to connect at server:port with timeout 
# Defaults,
#  server, localhost
#  port, telnet port (23)
#  timeout, 3"
# Returns,
#   0, connection made
#        port open
#   1, connection refused
#        network error or port closed
# 129, timeout
#        port filtered or server error
#
# (c) 2017, xae. Juan José Eraso Escalona
# 20170516
##
function telnet_scan {

local server=${1:-localhost}
local port=${2:-23}
local timeout=${3:-3}
local result

result=$(
(telnet "$server" "$port" | : )
2> >( read -t $timeout status;
[ $? -gt 128 ] &&
{ printf "timeout"; killall telnet; exit; };
[ -z "$status" ] && printf "open"
|| printf "closed"
))

case $result in
open) return 0 ;;
timeout) return 129 ;;
*) return 1
esac

}

A modo de ejemplo,

# Acepta pares servidor puerto
# Finaliza al final de fichero o con entrada nula

while read server port
do

[ -z "$server" ] ||
[ -z "$port" ] && break;

printf "$server:$port\t"

telnet_scan "$server" "$port"
case $? in
0) printf "abierto\n" ;;
1) printf "cerrado\n" ;;
*) printf "filtrado\n"
esac

done

Concluyendo

Sí, existen maneras más sencillas de hacer esto y sí, existen multitud de herramientas específicas disponibles para esta tarea; pero esos temas no son relevantes en esta entrada, aquí se trataba de domesticar a telnet...

 


Media Free Software Foundation, FAL, via Wikimedia Commons
H2
H3
H4
3 columns
2 columns
1 column
1 Comment