DEV Community

IT Solutions Pro
IT Solutions Pro

Posted on

Build a "Military-Grade" Network Scanner in Python (Scapy Tutorial)

In the world of cybersecurity, information is power. Before an attack happens, there is a phase of observation—watching, listening, and mapping out the network.

Imagine knowing exactly every device connected to your Wi-Fi right now. Your neighbor’s phone, your smart TV, or maybe even an intruder lurking on your network.

Most people rely on pre-made tools like Nmap. But today, we are going to build our own.

In this tutorial, we will write a Python script that reverse-engineers the ARP (Address Resolution Protocol) to discover devices on any network.

Prerequisites

Before we write code, we need to handle the "Layer 2" drivers. Python cannot speak directly to the network card without help.

1. For Windows Users (Critical)

You must install Npcap.

  • Go to npcap.com.

  • Important: During installation, check the box "Install Npcap in WinPcap API-compatible Mode".

2. Install Scapy

We will use scapy, a powerful packet manipulation library.
Open your terminal/command prompt and run:

pip install scapy

The Code Construction
We will build this in 3 phases using a single file: scanner.py.

Phase 1: Handling Arguments
We don't want to hard-code the IP. We want to pass it via the command line (e.g., -t 10.0.0.1/24).

import scapy.all as scapy
import argparse
import time

def get_arguments():
    parser = argparse.ArgumentParser()
    parser.add_argument("-t", "--target", dest="target", help="Target IP / IP range.")
    options = parser.parse_args()

    # Smart Logic: If user forgets the IP, default to a test range
    if not options.target:
        print("[-] No target specified. Defaulting to 192.168.1.1/24 for demo.")
        return "192.168.1.1/24"

    return options.target
Enter fullscreen mode Exit fullscreen mode

Phase 2: The Scanner Engine
This is where the magic happens. We create an Ethernet frame destined for ff:ff:ff:ff:ff:ff (Broadcast), ensuring every device hears us.

def scan(ip):
    print(f"\n[+] Starting Scan on {ip}...\n")
    print("-" * 50)
    print("IP Address\t\tMAC Address")
    print("-" * 50)

    # 1. Create ARP Request
    arp_request = scapy.ARP(pdst=ip)

    # 2. Create Broadcast Frame
    broadcast = scapy.Ether(dst="ff:ff:ff:ff:ff:ff")

    # 3. Combine Frame
    arp_request_broadcast = broadcast/arp_request

    # 4. Send & Receive
    # verbose=False keeps the terminal clean
    answered_list = scapy.srp(arp_request_broadcast, timeout=1, verbose=False)[0]

    clients_list = []

    for element in answered_list:
        client_dict = {"ip": element[1].psrc, "mac": element[1].hwsrc}
        clients_list.append(client_dict)

        # visual effect: print immediately
        print(f"{element[1].psrc}\t\t{element[1].hwsrc}")
        time.sleep(0.1) # Cinematic delay

    return clients_list
Enter fullscreen mode Exit fullscreen mode

The Full Source Code
Here is the complete script. Copy this into a file named scanner.py.

Python

import scapy.all as scapy
import argparse
import time

def get_arguments():
    parser = argparse.ArgumentParser()
    parser.add_argument("-t", "--target", dest="target", help="Target IP / IP range.")
    options = parser.parse_args()
    if not options.target:
        print("[-] Please specify a target IP range. Use --help for more info.")
        # Default to local range if not provided
        return "192.168.1.1/24" 
    return options.target

def scan(ip):
    print(f"\n[+] Starting Scan on {ip}...\n")
    print("-" * 50)
    print("IP Address\t\tMAC Address")
    print("-" * 50)

    arp_request = scapy.ARP(pdst=ip)
    broadcast = scapy.Ether(dst="ff:ff:ff:ff:ff:ff")
    arp_request_broadcast = broadcast/arp_request

    # Send packet and wait for response
    answered_list = scapy.srp(arp_request_broadcast, timeout=1, verbose=False)[0]

    clients_list = []
    for element in answered_list:
        client_dict = {"ip": element[1].psrc, "mac": element[1].hwsrc}
        clients_list.append(client_dict)
        print(f"{element[1].psrc}\t\t{element[1].hwsrc}")
        time.sleep(0.1) # Added delay for visual effect

    return clients_list

def print_result(results_list):
    print("-" * 50)
    print(f"[+] Scan Complete. Found {len(results_list)} devices.")

if __name__ == "__main__":
    target_ip = get_arguments()
    scan_result = scan(target_ip)
    print_result(scan_result)
Enter fullscreen mode Exit fullscreen mode

Conclusion
You just built a professional network reconnaissance tool in under 60 lines of code. This is the foundation of network security.

If you enjoyed this, I have a full video breakdown explaining every single line of code below.

📺 Watch the Masterclass

For more IT Masterclasses, subscribe to: @it_solutions_pro

Top comments (0)