How to Build a Fast and Efficient Port Scanner with Python

port scanner with python

Introduction

Port scanning is considered to be a useful mechanism that results from the network reconnaissance process by enabling one to discover the open ports and the working services of the target device.

There are several types of network scans used for different purposes in network security and administration. Some of the most common scan types are:

  • TCP Scan: This scan focuses on connecting with the target port completely and, if possible, establishing a fully opened TCP port.
  • UDP Scan: This scan targets the specified ports by sending out UDP packets. A typical difference between these two protocols is that in terms of UDP there is no connection to a port per say and waits for responses to ascertain the status of the ports.
  • SYN Scan: Also known as a “half-open” scan, in this technique SYN packets are sent to those ports that are to be scanned and a response waiting is done

In particular, these open ports help to gather some crucial information as to the weakness of the device and the type of services trusted.

Why Python for Fast Port Scanning

Dynamic port scanning application can be effectively written in the programming language Python because of its user-friendliness and a wealth of useful libraries.

Further to this, there are powerful tools which have been tailored for network programming in Python such as socket, asyncio and scapy. They help to create better and faster performing port scanners.

However, there is an additional primary factor that should be mentioned. The majority of Python’s libraries offer support for asynchronous programming by default, the most notable example being the asyncio.

By leveraging Python’s features and libraries, you can create a port scanner that is not only effective and fast but also easy to maintain and extend.

Today’s article is about the construction of two port scanners, the first one a simple port scanner and the second one being rich in functions such as concurrency for better performance.

Simple Port Scanner

We will begin by using the socket module in our programs since it will enable us to deal with the connections in the network.

This module presents many functions for creating/using sockets that can be viewed as the most important elements of networks.

import socket

The next function that we are going to define is scan_port(). As for this function, it is used to attempt to connect to a specific port on a given host to determine whether the port is in fact open.

Firstly, we need to create a socket object using socket function. socket, where address-family is given as AF_INET for IPv4, and socket type is given as SOCK_STREAM for TCP.

Setting timeout of 1 second will guarantee that the connection attempt will not take indefinitely.

def scan_port(host, port):
    """Scan a single port on a given host."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.settimeout(1)  # Set a timeout for the connection attempt
        result = s.connect_ex((host, port))
        return result == 0  # Return True if port is open, else False

We will then define a function that we will call scan_ports(). This function makes it possible for us to scan many ports on a specific host at an instance.

We begin by creating an empty list known as open_ports, through which we’ll document which ports are open. To every port in the list of ports to be scanned, we have the scan_port() function called.

def scan_ports(host, ports):
    """Scan multiple ports on a given host."""
    open_ports = []
    for port in ports:
        if scan_port(host, port):
            open_ports.append(port)
            print(f"Port {port} is open")
        else:
            print(f"Port {port} is closed")
    return open_ports

Last but not least, we will cover the remaining part of the script, which executes the main body of the script. Here we define a host IP, which we are going to scan together with the ports of our choice.

if __name__ == "__main__":
    target_host = "127.0.0.1"  # Replace with the target host IP
    ports_to_scan = [22, 80, 443, 8080]  # Replace with the ports you want to scan
    open_ports = scan_ports(target_host, ports_to_scan)
    print(f"Open ports: {open_ports}")

This code offers a simple approach towards scanning for the status of quite a number of ports in a given network host.

Efficient Asynchronous Port Scanner

Fine tuning of a port scanner includes making it work at a faster rate by enabling it to perform more than one task at the same time.

This process is known as concurrency and can certainly save the amount of time that it takes to go for a succession of ports or several hosts.

Python’s asyncio library provides solid ground-time shared parallelism using async and await keywords, providing efficiently scalable solutions.

In this section we will take advantage of asyncio to develop a robust and fast port scanner all in all demonstrating its ability to perform a number asynchronous operations with relative ease.

To begin, we need to import the necessary modules:

import asyncio
import socket

Here we are going to use the asyncio library, which will help us write the asynchronous code.

Subsequently, we will establish an asynchronous function to scan one port.

async def scan_port(host, port):
    """Asynchronously scan a single port on a given host."""
    loop = asyncio.get_event_loop()
    connector = asyncio.open_connection(host, port)
    try:
        reader, writer = await asyncio.wait_for(connector, timeout=1)
        writer.close()
        await writer.wait_closed()
        return True
    except (asyncio.TimeoutError, ConnectionRefusedError):
        return False

In this function, we create an asynchronous function to the specified host and port. To make that connection, we use asyncio.open_connection to open the connection and asyncio.wait_for to provide a timeout.

Next, we will define an async function to scan a range of ports:

async def scan_ports(host, start_port, end_port):
    """Asynchronously scan a range of ports on a given host."""
    ports = range(start_port, end_port + 1)
    tasks = [scan_port(host, port) for port in ports]
    results = await asyncio.gather(*tasks)
    open_ports = [port for port, open in zip(ports, results) if open]
    for port in ports:
        if port in open_ports:
            print(f"Port {port} is open")
        else:
            print(f"Port {port} is closed")
    return open_ports

In this function, we first generate a list of ports based on the range provided and construct a list of tasks to scan each port through the function scan_port.

We then use asyncio.gather to execute all tasks concurrently and gather the results of the completed tasks. After we have gathered the results, we can determine the open ports and print their statuses.

Lastly, we will run the port scanner with the code below:

if __name__ == "__main__":
    target_host = "109.70.148.130"  # Replace with the target host IP
    start_port = 20
    end_port = 1024  # Replace with the desired range of ports
    open_ports = asyncio.run(scan_ports(target_host, start_port, end_port))
    print(f"Open ports: {open_ports}")

In this section, we create the target host and range of ports to scan. This code demonstrates the use of asyncio.run to run the scan_ports() function to list all the open ports.

By walking through all of these steps, we have successfully leveraged asyncio to create a rapid and efficient port scanner tool, which is extraordinarily useful for network evaluations or security assessments.

Conclusion

Utilizing Asyncio in Python to develop a port scanner is an efficient method to assess network security and system connectivity.

Asynchronous programming allows us to simultaneously scan many of a net of ports; thus, it takes a far shorter time than a synchronous programming scan of the same ports. 

Not only does this speed things up to a substantial amount of time reduction, but it also provides us information about open ports on a target host.

🧷Discover the entire source code on GitHub .

🧷Python Socket Chat System: Quick Setup in 5 Minutes


Light