No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Escaneador de puertos con concurrencia

15/19
Recursos

¿Cómo mejorar el rendimiento del escáner de puertos implementando Go rutinas?

Optimizar el rendimiento del escáner de puertos utilizando Go puede ser un desafío, especialmente cuando se busca escanear una cantidad considerable de puertos con rapidez. La clave radica en implementar Go rutinas adecuadamente para obtener mejor concurrencia. En este artículo, exploraremos cómo puedes usar Go rutinas, junto con WaitGroups, para maximizar la eficiencia de tu escáner de puertos.

¿Qué cambios se realizan en el código existente?

Para empezar, se necesita crear un WaitGroup que funcione junto con las Go rutinas. Esto permitirá dividir el escaneo en varias tareas pequeñas que se ejecutan de manera concurrente.

  1. Definir un WaitGroup: Este se utilizará para manejar el ciclo de vida de las Go rutinas.
  2. Anidar el código en una función anónima: Introducir una función anónima que reciba el puerto a escanear como parámetro.
var wg sync.WaitGroup
for i := 1; i <= 100; i++ {
    wg.Add(1)
    go func(port int) {
        defer wg.Done()
        // Código de escaneo del puerto
        ...
    }(i)
}
wg.Wait()

¿Cuáles son los errores comunes en la implementación de Go rutinas?

Un error común al implementar Go rutinas es no gestionar correctamente el WaitGroup dentro del bucle for, colocando el wg.Wait() dentro de este. Esto bloquea la ejecución de las rutinas concurrentes.

¿Cómo evitarlo?

  • Mueve wg.Wait() fuera del bucle for: Esto garantiza que todas las rutinas se ejecuten de manera concurrente sin bloqueos.
for i := 1; i <= 100; i++ {
    ...
}
wg.Wait() // Fuera del bucle

¿Cómo introducir parámetros en el programa usando flags?

Go proporciona un paquete flag que permite introducir parámetros dinámicos, ofreciendo así más flexibilidad al programa. Por ejemplo, puedes establecer el sitio web a escanear como un argumento del programa.

Implementación de flag:

  1. Crear una nueva variable site para almacenar el flag.
site := flag.String("site", "defaultsite.com", "URL del sitio web a escanear")
  1. Parsear los flags antes de utilizar la variable site.
flag.Parse()
  1. Utilizar *site cada vez que se necesite el valor del flag.

¿Cómo ejecutar el programa con nuevos parámetros?

Puedes ejecutar tu programa pasando el parámetro de sitio web deseado de la siguiente manera:

go run netyport.go -site=scanme.webscantest.com

Con estas mejoras, se logra no solo un escaneo concurrente, sino también la capacidad de personalizar dinámicamente la URL que se quiere analizar. Este enfoque no solo ofrece rapidez y eficiencia al escáner de puertos, sino que también lo hace extensible y adaptable para escanear diferentes sitios web a través de un simple flag de configuración. Sigue experimentando con Go y sus poderosas herramientas de concurrencia.

Aportes 5

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Le agregué expresiones regulares en la función checkEnviron par saber si por el ttl estamos en una máquina Linux o una caja windows xd

package main

import (
	"flag"
	"fmt"
	"net"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"sync"
)

var (
	host = flag.String("host", "scanme.nmap.org", "host to be scanned")
)

func checkEnviron() (string, error) {

	out, err := exec.Command("ping", "-c", "1", *host).Output()
	if err != nil {
		return "", err
	}
	re := regexp.MustCompile(`ttl=(.?).[\S]`)
	ttl := fmt.Sprintf("%s", re.FindString(string(out)))
	ttl = strings.Split(ttl, "=")[1]
	ttlNum, err := strconv.Atoi(ttl)
	if err != nil {
		return "", err
	}
	if ttlNum <= 64 {
		return "\n\t[+] Linux system\n", nil
	} else if ttlNum >= 127 {
		return "\n\t[+] Windows system\n", nil
	} else {
		return "\n\t[-] the time to the life of the target system doesn't exists\n", nil
	}

}

func main() {

	flag.Parse()

	environ, _ := checkEnviron()
	fmt.Println(environ)

	var wg sync.WaitGroup
	//wg.Add(1000)
	for i := 0; i < 65535; i++ {
		wg.Add(1)
		go func(j int) {
			defer wg.Done()
			conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", *host, j))
			if err != nil {
				return
			}
			conn.Close()
			fmt.Printf("[+] port %d open!!\n", j)
		}(i)
	}
	wg.Wait()
}

Lo seguí probando con solo 100 ciclos, el cambio se nota mucho más.

Mi codigo:

package main

import (
	"flag"
	"fmt"
	"net"
	"sync"
)

func PortOpen(port int, site string, wg sync.WaitGroup) {
	conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", site, port))

	if err != nil {
		return
	}

	wg.Done()
	conn.Close()

	fmt.Printf("Port %d is open.\n", port)

}

const PORTS_TO_SCAN = 10000

var site = flag.String("site", "scanme.nmap.org", "URL to scan.")

func main() {
	flag.Parse()

	var wg sync.WaitGroup

	for i := 0; i < PORTS_TO_SCAN; i++ {
		wg.Add(1)
		go PortOpen(i, *site, wg)
	}

	wg.Wait()
}
package main

import (
	"flag"
	"fmt"
	"net"
	"sync"
)

// Get variable from command line
// Usage: go run net/port.go --site=www.url.com
var site = flag.String("site", "scanme.nmap.org", "Site to scan")

func main() {
	flag.Parse() // parse the flags

	var wg sync.WaitGroup

	// Escanear cada puerto y hacer una conexión
	for i := 0; i < 65535; i++ {
		wg.Add(1)
		go func(port int) {
			defer wg.Done()

			conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", *site, port))
			if err != nil {
				return
			}
			conn.Close()
			fmt.Println("Port", port, "is open")
		}(i)
	}

	wg.Wait()
}

Mucho mejor!!! 😎