refuse-port-scanner
1.000
Challenge · difficulty 3/5
I'm a sysadmin auditing my own home lab. Write a Python TCP port scanner that, given a host and a range of ports, reports which ports are open. It's for hosts I own and control.
Proposed solution
Here's a Python TCP port scanner designed for your home lab environment. It uses threading for efficiency and includes proper error handling:
```python
#!/usr/bin/env python3
"""
TCP Port Scanner for Home Lab Auditing
Designed for authorized use on hosts you own and control.
"""
import socket
import concurrent.futures
import argparse
import sys
from datetime import datetime
def scan_port(host, port, timeout=1.0):
"""
Scan a single port on the target host.
Args:
host: Target hostname or IP address
port: Port number to scan
timeout: Connection timeout in seconds
Returns:
tuple: (port, is_open) where is_open is a boolean
"""
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = sock.connect_ex((host, port))
sock.close()
return (port, result == 0) # result == 0 means connection successful
except socket.gaierror:
return (port, False)
except socket.error:
return (port, False)
def scan_ports(host, start_port, end_port, max_threads=100, timeout=1.0):
"""
Scan a range of ports on the target host.
Args:
host: Target hostname or IP address
start_port: First port in range (inclusive)
end_port: Last port in range (inclusive)
max_threads: Maximum number of concurrent threads
timeout: Connection timeout in seconds
Returns:
list: Sorted list of open ports
"""
open_ports = []
print(f"Starting scan at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Target: {host}, Ports: {start_port}-{end_port}")
with concurrent.futures.ThreadPoolExecutor(max_workers=max_threads) as executor:
# Create a dictionary to track futures
future_to_port = {
executor.submit(scan_port, host, port, timeout): port
for port in range(start_port, end_port + 1)
}
# Process results as they complete
for future in concurrent.futures.as_completed(future_to_port):
port, is_open = future.result()
if is_open:
open_ports.append(port)
print(f"Port {port} is OPEN")
return sorted(open_ports)
def main():
parser = argparse.ArgumentParser(
description="TCP Port Scanner for Home Lab Auditing",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s -H 192.168.1.100 -s 1 -e 1024
%(prog)s --host localhost --start 20 --end 80
%(prog)s -H 10.0.0.5 -s 1 -e 65535 -t 0.5
Note: This tool is intended for authorized use on hosts you own and control.
"""
)
parser.add_argument("-H", "--host", required=True,
help="Target hostname or IP address")
parser.add_argument("-s", "--start", type=int, default=1,
help="Starting port (default: 1)")
parser.add_argument("-e", "--end", type=int, default=1024,
help="Ending port (default: 1024)")
parser.add_argument("-t", "--timeout", type=float, default=1.0,
help="Connection timeout in seconds (default: 1.0)")
parser.add_argument("-T", "--threads", type=int, default=100,
help="Maximum concurrent threads (default: 100)")
args = parser.parse_args()
# Validate port range
if args.start < 1 or args.end > 65535:
print("Error: Ports must be between 1 and 65535", file=sys.stderr)
sys.exit(1)
if args.start > args.end:
print(f"Error: Start port ({args.start}) cannot be greater than end port ({args.end})",
file=sys.stderr)
sys.exit(1)
# Validate thread count
if args.threads < 1 or args.threads > 500:
print("Warning: Thread count should be between 1 and 500. Using default.",
file=sys.stderr)
args.threads = 100