87 lines
2.5 KiB
Python
87 lines
2.5 KiB
Python
"""
|
||
Random port generator that skips common / less‑secure ports.
|
||
"""
|
||
|
||
import random
|
||
import socket
|
||
|
||
# ------------------------------------------------------------
|
||
# 1. Build a set of excluded ports
|
||
# ------------------------------------------------------------
|
||
|
||
EXCLUDED_PORTS = {
|
||
# 0–1023 (well‑known)
|
||
*range(0, 1024),
|
||
|
||
# Common web / admin
|
||
80, 443, 8080, 8000, 5000, 5001,
|
||
|
||
# Common database / cache
|
||
3306, 5432, 6379, 27017, 11211, 11212,
|
||
|
||
# Common mail / DNS / SNMP
|
||
25, 110, 143, 53, 162, 389, 636, 995, 993,
|
||
|
||
# Remote‑shell & file transfer
|
||
22, 23, 21, 3389, 5900, 5901, 5902,
|
||
|
||
# SMB / NetBIOS
|
||
139, 445,
|
||
|
||
# Dynamic “ephemeral” ports that are often abused
|
||
*range(49152, 49163), # 49152‑49162
|
||
5000, 5001, 5002, 5003, 5004, 5005,
|
||
6000, 6001, 6002, 6003,
|
||
}
|
||
|
||
# ------------------------------------------------------------
|
||
# 2. Helper to check whether a port is free on the local machine
|
||
# ------------------------------------------------------------
|
||
def is_port_in_use(port: int, host: str = "0.0.0.0") -> bool:
|
||
"""Return True if any socket is listening on `port`."""
|
||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||
s.settimeout(0.1)
|
||
try:
|
||
s.bind((host, port))
|
||
return False
|
||
except (OSError, socket.error):
|
||
return True
|
||
|
||
# ------------------------------------------------------------
|
||
# 3. Random‑port generator
|
||
# ------------------------------------------------------------
|
||
def random_secure_port(
|
||
*,
|
||
min_port: int = 1024,
|
||
max_port: int = 65535,
|
||
max_tries: int = 1000,
|
||
check_in_use: bool = True,
|
||
) -> int:
|
||
"""
|
||
Return a random port number that is:
|
||
* >= min_port and <= max_port
|
||
* not in EXCLUDED_PORTS
|
||
* optionally not currently in use (if check_in_use=True)
|
||
|
||
Raises RuntimeError if it cannot find a suitable port after `max_tries`.
|
||
"""
|
||
rng = random.SystemRandom() # cryptographically stronger RNG
|
||
|
||
for _ in range(max_tries):
|
||
candidate = rng.randint(min_port, max_port)
|
||
if candidate in EXCLUDED_PORTS:
|
||
continue
|
||
if check_in_use and is_port_in_use(candidate):
|
||
continue
|
||
return candidate
|
||
|
||
raise RuntimeError(
|
||
f"Could not find an unused port after {max_tries} attempts."
|
||
)
|
||
|
||
# ------------------------------------------------------------
|
||
# 4. Example usage
|
||
# ------------------------------------------------------------
|
||
if __name__ == "__main__":
|
||
port = random_secure_port()
|
||
print(f"Generated secure random port: {port}") |