Python: Network Scanner

Premessa: si tratta di un esercizio per imparare il linguaggio e consente solo di fare il ping verso un range di indirizzi.

Quindi: nulla di sofisticato, volevo solo crearmi qualcosa per verificare quali IP fossero raggiungibili nella LAN e – senza usare tools già esistenti e fatti sicuramente meglio – ho semplicemente voluto farmi qualcosa in casa, tutto qua.

Di seguito propongo subito il codice che è possibile copiare ed incollare dentro un file che potrebbe chiamarsi “net_scan.py”:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# By UDA'Software 2020 - budus@hotmail.it
# Versione 2020-03-26 (nome in codice: Quarantena)

################################################################################
#_______________________________________________________________________________
import sys         # Per gestire i parametri a linea di comando
import re          # Per gestire le espressioni regolari

import platform    # For getting the operating system name
import subprocess  # For executing a shell command

################################################################################
#_______________________________________________________________________________
def find_pattern(pipe_output, pattern):
    lines = str(pipe_output).split()
    for line in lines:
        match = re.match(pattern, str(line))
        if match:
            return True
    
    return False

################################################################################
#_______________________________________________________________________________
def ping(host):
    if platform.system().lower() == 'windows':
        ping_response = subprocess.Popen(["ping", "-n", "1", "-w", "100", host], stdout=subprocess.PIPE).stdout.read()
        return find_pattern(ping_response, r'^byte=[0-9]{1,}$')
    
    ping_response = subprocess.Popen(["ping", "-c", "1", "-W", "100", host], stdout=subprocess.PIPE).stdout.read()
    return find_pattern(ping_response, r'^time=[0-9\.]{1,}$')

################################################################################
#_______________________________________________________________________________
def print_help():
    print("[E] Non hai specificato i parametri correttamente, usa:")
    print("    {} <ip_mask> [ip_start] [ip_end]".format(sys.argv[0]))
    print("    esempio:")
    print("    {} 192.168.0 1 254".format(sys.argv[0]))

################################################################################
#_______________________________________________________________________________
# MAIN
################################################################################
if len(sys.argv) < 2:
    print_help()

    exit (1)
else:
    ip_net_mask = str(sys.argv[1])
    match = re.match(r'^([0-9]{1,3}\.){2}[0-9]{1,3}$', ip_net_mask)
    if not match:
        print("[E] Il parametro maschera non corrisponde. (ex: 192.168.0)")
        exit(1)

    try:
        if len(sys.argv) >= 3:
            ip_start = int(sys.argv[2])
        else:
            ip_start = 1

        if len(sys.argv) >= 4:
            ip_end = int(sys.argv[3])
        else:
            ip_end = 254

        if ip_start < 1:
            ip_start = 1
            print("[A] ip_start non può essere inferiore a 1.")

        if ip_end > 254:
            ip_end = 254
            print("[A] ip_end non può essere superiore a 254.")

    except:
        print_help()

assigned_ip_list = []
for ip in range(ip_start, ip_end):
    scan_ip = ip_net_mask + "." + str(ip)
    result = ping(scan_ip)
    print(f"Scanning dell'IP: {scan_ip}: {result}")
    if result == True:
        assigned_ip_list.append(scan_ip)
        ui = input("[I] IP {} assegnato; premi INVIO per continuare o  x  per uscire: ".format(scan_ip))
        if ui in ["x", "X"]:
            exit(0)
    
n = 1
print("[I] Elenco degli IP assegnati:")
for ip in assigned_ip_list:
    print(" - %3d: %s" %(n, ip))
    n += 1

################################################################################
#_______________________________________________________________________________

La sintassi del programma è la seguente:

    net_scan.py <ip_mask> [ip_start] [ip_end]
    esempio:
    net_scan.py 192.168.0 1 254

Dove “<ip_mask>” è la base degli indirizzi IP di qui si vuole fare lo scan; ad esempio, su Windows, possiamo aprire il prompt del DOS con Win+r ed ottenere l’indirizzo IP della macchina con ipconfig :

Esempio di risultato fornito da ipconfig; l’indirizzo IP sulla scheda ethernet 4 è “192.168.42.38”

Dato l’ip della macchina la maschera di cui sopra è rappresentata dalla prima tripletta di numeri – separati dal punto – che è: 192.168.42

Volendo fare lo scan di tutta la LAN che utilizza un indirizzo compreso tra “192.168.42.1” e “192.168.42.254” possiamo usare:

net_scan.py 192.168.42

Se, invece, vogliamo solo fare lo scano di una porzione della rete, possiamo anche specificare la partenza ed eventualmente anche la fine, ad esempio:

net_scan.py 192.168.42 38 39

Esegue lo scan di un solo indirizzo: 192.168.42.38

In tutti i casi, alla fine, viene visualizzato un rapporto di tutti gli indirizzi IP eventualmente trovati raggiungibili.

N.B.: Lo script è stato realizzato per e con Python 3.8

Autore: BuDuS

Disegnatore Meccanico, con la passione per l'Informatica. Come hobby, produco piccoli software di (in)utilità.