DEV Community

Cover image for Build Your Own Port Scanner in Python (and Understand How Nmap Thinks)
Lorenzo Fazioli
Lorenzo Fazioli

Posted on Originally published at zyvop.com

Build Your Own Port Scanner in Python (and Understand How Nmap Thinks)

Why write one when Nmap exists?

Because using a tool and understanding a tool are different skills. When you write the scan loop yourself, you feel why a full connect scan is loud, why timeouts dominate your runtime, and why threading matters. That intuition transfers directly to reading Nmap output later.

The naive version

Start with the simplest thing that works: a socket, a connect call, and a loop.

import socket

def scan(host, ports):

    for port in ports:

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        s.settimeout(0.5)

        if s.connect_ex((host, port)) == 0:

            print(f"[+] {port}/tcp open")

        s.close()

scan("127.0.0.1", range(1, 1025))
Enter fullscreen mode Exit fullscreen mode

connect_ex is the key: it returns an error code instead of raising, so a closed port is just a non-zero return, not an exception to catch.

Why it’s painfully slow

Run it against 1024 ports and you’ll wait. Each closed port burns the full timeout serially. Scanning 1024 ports at 0.5s each is over eight minutes in the worst case — for one host.

Making it threaded

Network scanning is I/O bound, so threads help enormously here despite the GIL.

from concurrent.futures import ThreadPoolExecutor

def check(host, port):

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:

        s.settimeout(0.5)

        if s.connect_ex((host, port)) == 0:

            return port

def scan(host, ports, workers=200):

    with ThreadPoolExecutor(max_workers=workers) as pool:

        results = pool.map(lambda p: check(host, p), ports)

    return [p for p in results if p]
Enter fullscreen mode Exit fullscreen mode

Suddenly 1024 ports finish in seconds.

Where to go next

  • Grab banners: after connecting, send a probe and read the first bytes to fingerprint the service.

  • Add a SYN scan with raw sockets (requires root) to avoid completing the handshake.

  • Rate-limit yourself so you don’t trip IDS on networks you’re allowed to test.

One rule before you run it

Only scan hosts you own or have written permission to test. A port scan against someone else’s infrastructure can be illegal in most jurisdictions, full stop.

If you want the finished version, my Portscanner repo is on GitHub.


Published via ZyVOP — Write once in Markdown, auto-backup to GitHub, and syndicate to Dev.to, Medium & Hashnode in 1 click.

Top comments (0)