overview
Enfoque
Un escáner TCP connect en Python. Sin Nmap ni Scapy. Usa la biblioteca estándar (socket, threading, queue y selectors) más colorama para el color.
El motor por defecto, threads, hace que cada hilo de trabajo saque un puerto de una queue.Queue y haga un connect_ex() bloqueante. Con --engine select, las conexiones son no bloqueantes y se multiplexan con selectors.
El objetivo puede ser un nombre de host, una dirección IPv4 o una IPv6. Un nombre de host se resuelve una sola vez, antes de escanear, y primero a IPv4. --ipv6 fuerza IPv6 para los nombres de host. Una conexión del escáner consigo mismo no se cuenta como abierta.
Si no pasas --no-banner, intenta leer un banner de cada puerto abierto:
- Los puertos 80, 8000, 8008, 8080 y 8888 reciben
HEAD / HTTP/1.0. - Los puertos TLS (443 y 8443) no se sondean.
- Los puertos 21, 22 y 25 se anuncian solos, así que solo escucha, hasta
--timeout. - Cualquier otro puerto abierto se escucha como máximo 0,5 s.
La respuesta se reduce a ASCII imprimible, las rachas de espacios en blanco pasan a ser un solo espacio y se corta a 200 caracteres, así que los datos binarios no pueden romper la salida. Da nombre a 39 puertos conocidos, según el número de puerto y no según el tráfico.
Solo se toma un lock cuando un puerto resulta estar abierto, para añadir el resultado e imprimirlo. Los puertos abiertos se imprimen en vivo y al final se vuelve a imprimir la lista ordenada por puerto.
En Windows, los puertos cerrados en direcciones de loopback se rechazan tras unos 2 s salvo que la opción de retransmisión de SYN esté desactivada. El escáner la desactiva solo para objetivos de loopback (SIO_TCP_INITIAL_RTO mediante ctypes), y nunca para ninguna otra dirección.
Límites: es solo un escaneo TCP connect. El handshake completo se produce, así que aparece en los registros del objetivo. Un puerto filtrado y uno cerrado se muestran igual, como "no abierto". No envía nada a servicios que no sean HTTP.
Los tests se ejecutan con python -m unittest. Cubren el análisis de puertos, la limpieza de banners, los dos motores en IPv4 e IPv6, la ruta del HEAD, la autoconexión, el JSON, Ctrl+C y los errores de la CLI. Solo se conectan a 127.0.0.1 y ::1. Un workflow de GitHub Actions los ejecuta en Ubuntu y Windows, con Python 3.10 y 3.13. Lo desarrollé y probé con Python 3.13 en Windows 10.
Uso
pip install -r requirements.txt
El único requisito es colorama.
python portscanner.py <objetivo> [--ports 1-1024] [--threads 500] [--output archivo.txt] [--no-banner] [--timeout 1.0] [--engine threads|select] [--ipv6] [--json] [--version]
# rango por defecto, 1-1024
python portscanner.py <objetivo>
# puertos concretos y un rango, guardados en un archivo
python portscanner.py <objetivo> --ports 22,80,8000-8100 --output informe.txt
# sin banners, motor select
python portscanner.py <objetivo> --no-banner --engine select
# JSON por la salida estándar, y también guardado en un archivo
python portscanner.py <objetivo> --json --output informe.json
--portsacepta un rango (1-1024), una lista (22,80,443) o ambas cosas (22,80,8000-8100). Los puertos válidos van del 1 al 65535. Una entrada incorrecta se rechaza con un mensaje que nombra la parte errónea.--threadsvale 500 por defecto, va de 1 a 1000 y nunca es mayor que el número de puertos. Con--engine selectes el número de conexiones en vuelo, de 1 a 4096.--timeoutvale 1,0 s por defecto. Se aplica a cada conexión y a un banner de saludo.--output ARCHIVOguarda un informe en texto plano ordenado por puerto. Con--jsonel informe es JSON.--jsontambién imprime JSON por la salida estándar en lugar de la tabla, y los avisos van a stderr.
Ctrl+C detiene el escaneo tras los puertos en curso, imprime y guarda lo que ha encontrado, y marca el informe como "interrupted".
Códigos de salida:
0: el escaneo terminó.1: error en ejecución, como un host que no se resuelve o un archivo de salida que no se puede escribir.2: argumentos no válidos.130: interrumpido.
El grupo de descargas tiene portscanner.py, README.md, requirements.txt, LICENSE, .gitignore, benchmark.py, los tests y el workflow de GitHub Actions. La licencia es GPL v3.
Stack
Python, con socket, threading, queue y selectors de la biblioteca estándar, más colorama.
Uso responsable
Escanea solo equipos que sean tuyos o para los que tengas permiso. Escanear sin autorización puede ser ilegal según dónde estés. El escáner imprime este recordatorio en cada ejecución.