🚀 Executive Summary

TL;DR: SysAdmins often waste time manually checking port availability after deployments or firewall changes. This article provides a simple Python script using the `socket` module to automate targeted port scanning, significantly reducing diagnostic time and improving efficiency.

🎯 Key Takeaways

  • The core of the Python port scanner utilizes the built-in `socket` module, specifically `connect_ex()`, which returns `0` for an open port and an error code for a closed one, avoiding exceptions.
  • Implementing a `timeout` using `sock.settimeout()` is critical to prevent the script from hanging indefinitely when scanning filtered or unresponsive ports.
  • The `argparse` module enables the script to be command-line friendly, allowing users to specify the target host and a range of ports for scanning.
  • For scanning large port ranges, `threading` can be used to dramatically speed up the process by checking multiple ports concurrently.
  • Port scanning reveals reachability, meaning firewalls (network or local) can block access, causing a port to appear closed even if a service is running.

Checking Port Availability: A Python Port Scanner for SysAdmins

Checking Port Availability: A Python Port Scanner for SysAdmins

Hey team, Darian Vance here. I wanted to share a quick script that’s become a cornerstone of my diagnostic toolkit. I used to spend way too much time manually running `telnet` or `nmap` for simple checks after a deployment or firewall change. I finally realized I was burning at least an hour or two a week on repetitive tasks. Automating this with a simple Python script was a game-changer. It’s not meant to replace robust tools like Nmap, but for a quick, targeted check, it’s perfect and saves a ton of time. Let’s build it.

Prerequisites

Before we dive in, make sure you have the following:

  • Python 3 installed on your system.
  • A target host to scan. For safe testing, you can always use 127.0.0.1 (your local machine).
  • Basic familiarity with running a Python script from your terminal.

I’ll skip the standard virtual environment setup since you likely have your own workflow for that. Just make sure you’re working in an isolated environment before you start writing code. Let’s jump straight to the Python logic.


The Guide: Building the Port Scanner Step-by-Step

Step 1: The Core Logic with the `socket` Module

The heart of our scanner is Python’s built-in `socket` library. It gives us low-level access to network interfaces. We’ll use it to attempt a connection to a specific port. If the connection succeeds, the port is open; if it fails, it’s closed.

The key function here is `connect_ex()`. Unlike `connect()`, which throws an exception on failure, `connect_ex()` returns an error code. A return value of `0` means the connection was successful (port is open). This is much cleaner for our purposes.

Here’s the most basic implementation:


import socket

# Target host and port
target_host = "127.0.0.1"
target_port = 80

# Create a socket object
# AF_INET specifies we're using IPv4
# SOCK_STREAM specifies this is a TCP socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Attempt to connect
result_code = client_socket.connect_ex((target_host, target_port))

if result_code == 0:
    print(f"Port {target_port} is open on {target_host}")
else:
    print(f"Port {target_port} is closed on {target_host}. Error code: {result_code}")

# Cleanly close the connection
client_socket.close()

Step 2: Creating a Reusable Function and Adding a Timeout

Hardcoding values isn’t ideal. Let’s wrap this logic in a function. More importantly, we need to add a timeout. Without one, the script could hang for a long time trying to connect to a port that’s filtered or unresponsive. In my production setups, a short timeout (1-2 seconds) is essential.


import socket

def check_port(host, port, timeout=2):
    """
    Checks if a given port is open on a host.
    Returns True if open, False otherwise.
    """
    try:
        # Create a new socket for each check
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        
        # connect_ex returns 0 on success
        result = sock.connect_ex((host, port))
        sock.close()
        
        return result == 0
    except socket.gaierror:
        # This handles DNS resolution errors
        print(f"Error: Hostname '{host}' could not be resolved.")
        return False
    except socket.error:
        print(f"Error: Could not connect to host '{host}'.")
        return False

# --- Example Usage ---
target_host = "127.0.0.1"
test_ports = [22, 80, 443, 3306]

for port in test_ports:
    if check_port(target_host, port):
        print(f"Port {port} is OPEN")
    else:
        print(f"Port {port} is CLOSED")

Step 3: Making the Script Command-Line Friendly

To make this a truly useful tool, we need to pass the target host and port range via the command line. Python’s `argparse` module is perfect for this. It lets us create a proper command-line interface for our script.


import socket
import argparse

def check_port(host, port, timeout=2):
    # (Same function as above)
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        result = sock.connect_ex((host, port))
        sock.close()
        return result == 0
    except (socket.gaierror, socket.error):
        # We can handle errors more gracefully in the main block
        return False

def main():
    parser = argparse.ArgumentParser(description="A simple Python port scanner.")
    parser.add_argument("host", help="The target host or IP address to scan.")
    parser.add_argument("-s", "--start", type=int, default=1, help="The starting port.")
    parser.add_argument("-e", "--end", type=int, default=1024, help="The ending port.")
    args = parser.parse_args()

    print(f"Scanning {args.host} from port {args.start} to {args.end}...")

    for port in range(args.start, args.end + 1):
        if check_port(args.host, port):
            print(f"[+] Port {port} is OPEN")

if __name__ == "__main__":
    main()

Now you can run this from your terminal. For instance, you could save the file as `port_checker.py` and execute it to check for common web ports on your local machine.

Pro Tip: Speeding it Up with Threading
Scanning ports one by one is slow, especially for large ranges. In a real-world scenario, I’d use Python’s `threading` module to check multiple ports concurrently. You’d create a pool of worker threads, and a queue of ports to check. Each thread would pull a port from the queue and run our `check_port` function. This dramatically reduces the total scan time. It’s a bit more complex, but a fantastic next step once you’re comfortable with the basics.

Common Pitfalls (Where I Usually Mess Up)

  • Forgetting the Timeout: This is the number one mistake. If you scan a port that’s filtered by a firewall, it might not send a “connection refused” packet back. It just drops your packet. Without a timeout, your script will hang, waiting for a response that will never come.
  • Firewall Interference: Remember that you’re not just testing the service; you’re also testing the path to it. If a network firewall or a local one (like `iptables` or Windows Firewall) is blocking the port, the script will report it as closed, even if the service is running. This isn’t a bug; it’s accurate information about reachability.
  • Permissions and Scope: Only scan hosts you own or have explicit permission to test. Running a port scan against an unknown network can be seen as hostile activity and get your IP address blocked or flagged. Stick to your own infrastructure.

Conclusion

And there you have it. A simple, effective port scanner that you can customize to your heart’s content. It’s a great little utility for post-deployment checks, firewall rule validation, or just general network troubleshooting. From here, you could easily expand it to log open ports to a file, send an alert if a critical port is unexpectedly closed, or integrate it into a larger health-check script.

Happy scripting,

Darian Vance
Senior DevOps Engineer, TechResolve

Darian Vance - Lead Cloud Architect

Darian Vance

Lead Cloud Architect & DevOps Strategist

With over 12 years in system architecture and automation, Darian specializes in simplifying complex cloud infrastructures. An advocate for open-source solutions, he founded TechResolve to provide engineers with actionable, battle-tested troubleshooting guides and robust software alternatives.


🤖 Frequently Asked Questions

âť“ How does the Python script determine if a port is open?

The script uses Python’s `socket` module to create a TCP socket (`AF_INET`, `SOCK_STREAM`) and attempts to connect to the target host and port using `connect_ex()`. A return value of `0` from `connect_ex()` indicates a successful connection, meaning the port is open.

âť“ How does this Python port scanner compare to tools like Nmap or `telnet`?

This Python script is a lightweight, targeted solution for quick availability checks and automation, saving time on repetitive tasks. While it doesn’t offer the comprehensive network discovery and advanced features of Nmap, it’s more efficient for simple, programmatic checks than manual `telnet` commands.

âť“ What is a common implementation pitfall, and how can it be avoided?

A common pitfall is forgetting to set a `timeout` for the socket connection. Without a timeout, the script can hang indefinitely if it attempts to connect to a port that is filtered by a firewall and doesn’t send a response. This is avoided by calling `sock.settimeout(timeout)` before attempting the connection.

Leave a Reply

Discover more from TechResolve - SaaS Troubleshooting & Software Alternatives

Subscribe now to keep reading and get access to the full archive.

Continue reading