.gitignore
main.py
Packager files
.pythonlibs
poetry.lock
pyproject.toml
Config files
.replit
"""
Jonah Olsen
7/17/2024
This program listens for open ports on a given IP address and port range. Then prints
the open ports to a file.
example terminal command: python3 pymap.py 185.199.111.153 1 4000 --f open_ports.txt
# title ip start end file name
my website ip is 185.199.111.153 it has two open ports 80 and 443
"""
import socket
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor, as_completed
import argparse
def create_parser():
parser = argparse.ArgumentParser(description="A simple port scanner")
parser.add_argument("ip", help="The IP address to scan")
parser.add_argument("start_port", type=int, help="The starting port")
parser.add_argument("end_port", type=int, help="The ending port")
parser.add_argument("--f",
type=str,
help="The file to write the open ports to")
return parser
def scan_port(target_ip, port):
"""
Scans a single port and returns the port number if open, otherwise None.
"""
try:
sock = socket.socket(socket.AF_INET,
socket.SOCK_STREAM) # sets ip to IPv4 and TCP
sock.settimeout(
1) # sets timeout to 1 second in case something goes wrong
result = sock.connect_ex(
(target_ip, port)) # sets result to the connection status
sock.close()
if result == 0:
return port
except socket.error:
return None # returns None if there is an error
def scan_ports_concurrent(
target_ip,
port_range,
max_workers=500
): #you might want to change max workers depending on your computer
open_ports = [] # this will be the list of open ports that gets returned
total_ports = len(port_range)
with ThreadPoolExecutor(
max_workers=max_workers
) as executor: # manages threads so nothing gets mixed up
futures = {
executor.submit(scan_port, target_ip, port): port
for port in port_range
} #makes dictionaries of available ports
for i, future in enumerate(as_completed(futures),
start=1): # tries all the ports
port = futures[
future] # multi threading stuff that I don't fully understand. Basically just runs the func multiple times
if future.result() is not None:
open_ports.append(
port) # addes port to list if port has a result
if i % 100 == 0:
status_update(
i, total_ports) # gives a status update every 100 ports
return open_ports
def status_update(current_port, max):
percent_complete = (current_port / max) * 100
print(
f"Working...{percent_complete:.2f}%", end="\r"
) # end="\r" makes it so that it rewrites over the last print looks really cool
def output_results(open_ports, target_ip, file_name=None):
if file_name:
with open(file_name, "w") as file:
for port in open_ports:
file.write(f"{port}\n")
print(f"\nOpen ports on {target_ip}: {open_ports}")
def main():
# this will be the defult settings to make testing easier
# target_ip = "185.199.111.153" # this is my own website
# target_ip = "23.212.62.201" # this is the church's website
# target_ip = "34.217.126.252" # AWS server that I started (this will not work once I close it)
# start_port = 1
# end_port = 4000 # realistically you would only need to go up to 1024. The max is 65535
# target_ip = input("Enter the IP address to scan: ").strip()
# start_port = int(input("Enter the start port: ").strip())
# end_port = int(input("Enter the end port: ").strip())
parser = create_parser(
) # creates the parser // this is for terminal commands
args = parser.parse_args() # parses arguments
#set variables
target_ip = args.ip
start_port = args.start_port
end_port = args.end_port
port_range = range(start_port, end_port + 1)
print(f"Starting concurrent scan on host: {target_ip}")
start_time = datetime.now() # start stopwatch
open_ports = scan_ports_concurrent(target_ip, port_range) # scan ports
end_time = datetime.now() # stop stopwatch
total_time = end_time - start_time # calculate time
output_results(open_ports, target_ip, args.f) # output results
print(f"Scan completed in: {total_time}")
if __name__ == "__main__":
main()