Skip to content
    PyMap@jonaho2
    .gitignore
    main.py
    Packager files
    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()