2 min read

Python Port Scanner

This utility scans a target IP address or hostname for open ports. It uses the socket module to attempt connections and threading to scan multiple ports simultaneously for performance.

Modules Used:

  • socket: To create network connections and check ports.
  • threading: To run multiple scan attempts concurrently.
  • queue: To manage the list of ports to be scanned in a thread-safe way.
  • argparse: To handle command-line arguments.

The Code

Save this as port_scanner.py.

import socket
import threading
import queue
import argparse
from datetime import datetime

# Thread-safe print lock to prevent garbled output
print_lock = threading.Lock()

def scan_port(target, port):
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(1) # Timeout for connection attempt

        # connect_ex returns 0 if connection is successful, error code otherwise
        result = s.connect_ex((target, port))
        if result == 0:
            with print_lock:
                print(f"Port {port}: OPEN")
        s.close()
    except Exception:
        pass

def worker(target, q):
    while True:
        port = q.get()
        scan_port(target, port)
        q.task_done()

def main(target, start_port, end_port, thread_count):
    print(f"Scanning target: {target}")
    print(f"Scanning ports: {start_port}-{end_port}")
    print(f"Time started: {datetime.now()}")
    print("-" * 50)

    q = queue.Queue()

    # Create threads
    for _ in range(thread_count):
        t = threading.Thread(target=worker, args=(target, q))
        t.daemon = True # Daemon threads exit when main program exits
        t.start()

    # Fill queue with ports
    for port in range(start_port, end_port + 1):
        q.put(port)

    # Wait for queue to be empty
    q.join()
    print("-" * 50)
    print("Scanning completed")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Multi-threaded Port Scanner")
    parser.add_argument("target", help="Target IP or Hostname")
    parser.add_argument("--start", type=int, default=1, help="Start Port (default: 1)")
    parser.add_argument("--end", type=int, default=1024, help="End Port (default: 1024)")
    parser.add_argument("--threads", type=int, default=100, help="Number of threads (default: 100)")

    args = parser.parse_args()

    # Resolve hostname to IP
    try:
        target_ip = socket.gethostbyname(args.target)
    except socket.gaierror:
        print("Hostname could not be resolved.")
        exit()

    main(target_ip, args.start, args.end, args.threads)

Usage

# Scan common ports (1-1024) on localhost
python port_scanner.py localhost

# Scan a specific range on a server
python port_scanner.py 192.168.1.1 --start 80 --end 8080 --threads 200

programming/python/python