Inspector
In the realm of cybersecurity and network administration, understanding the communication landscape of a network is crucial. One of the fundamental tools for this purpose is a port scanner: a program that probes a host or range of hosts for open ports to help security professionals, network administrators, and ethical hackers assess potential vulnerabilities and ensure network integrity.
Developing a port scanner can be an insightful project for programmers interested in networking, security, and system administration by providing hands-on experience with concepts such as socket programming, multithreading, and network protocols.
In this article, I guide you through the process of developing a simple yet efficient port scanner in Python, covering the necessary background, fundamental concepts, and step-by-step implementation that allows you to build a functional tool that can scan a network for open ports. By the end of this guide, you will have a working knowledge of how port scanning works and how to implement it effectively in your projects.
Setting Up VS Code
To develop your port scanner project, you first need to configure Visual Studio (VS) Code. If you have the Microsoft repository set up, start by opening a terminal, updating your package list, and then installing VS Code by running (on Ubuntu):
sudo apt update
sudo apt install codeAlternatively, you can download the .deb package from the official VS Code website and then install it and ensure that all dependencies are resolved:
sudo dpkg -i code_*.deb
sudo apt --fix-broken installOnce VS Code is installed, launch it by typing code in the terminal or by searching for it in your applications menu. To streamline Python development, you should install three essential extensions: Pylance, Python, and Python Debugger. Inside VS Code, navigate to the Extensions view by clicking on the Extensions icon in the activity bar or by pressing Ctrl+Shift+X and then search for Pylance and install it.
This extension provides rich language support, including autocomplete, type checking, and performance improvements for Python development. Next, search for and install the Python extension, which integrates essential tools such as IntelliSense, linting, formatting, and debugging support. Finally, install the Python Debugger extension, which allows you to run and debug your Python code seamlessly within the VS Code environment.
After installing these extensions, ensure that Python is configured correctly by opening the command palette (Ctrl+Shift+P) and searching for Python: Select Interpreter. Choose the appropriate Python version installed on your system. If Python is not installed, you can install it with:
sudo apt install python3With VS Code and the necessary extensions set up, you are now ready to start developing your port scanner project on Ubuntu.
Port Scanner Code Structure
The primary goal of the script presented here is to scan a given host within a specified range of ports and identify the open ports (Figure 1). This essential technique is used in cybersecurity, network troubleshooting, and ethical hacking to assess the security of a system.

The script leverages Python's socket module to establish connections with the target host and determine whether a port is open or closed. To enhance performance, it uses multithreading, allowing the scanner to check multiple ports simultaneously, thereby speeding up the scanning process. The program is designed to be executed from the command line, where you specify the target host, the starting port, and the ending port as arguments.
Breaking the code into modular functions ensures clarity and maintainability. The core components include a function for scanning individual ports, a function to manage multithreading, and a main section that handles user input and initializes the scanning process. Through this structured approach, the script remains efficient, scalable, and easy to modify for additional features in the future.
In the following sections, I go step by step through each part of the code, explaining how it works and why specific techniques were used. By the end of this guide, you will have a solid understanding of how to develop a functional port scanner and adapt it to your own needs.
Code Analysis
Listing 1 [1] shows the complete source code of the application. The script begins by importing the necessary libraries: socket, threading, and sys. The socket library provides the functionality required for creating network connections, and threading is used to parallelize the port scan, making it faster than a single-threaded approach. The sys module handles command-line arguments.
| Listing 1: portscanner.py |
|
The script defines two functions: scan_port (line 5), which attempts to connect to a specific port on a given host, and port_scanner (line 14), which coordinates the scanning process by iterating over a range of ports, creating a thread for each port to scan concurrently. This design allows the program to perform multiple scans at once, potentially reducing the time needed to scan a large range of ports.
The scan_port function is responsible for attempting to connect to a specified host and port. It uses a with statement to ensure that the socket object is properly closed after the operation, which is a good practice to avoid resource leaks. Within this function, the socket's timeout is set to one second, which is appropriate for a fast scan. Please note that it might not be suitable for slower or congested networks. The function then tries to connect to the host (s.connect()) on the given port.
If the connection is successful, it prints a message indicating that the port is open. If the connection is refused or times out, the function simply passes without printing anything, which is reasonable, because a refusal or timeout indicates that the port is not open.
The port_scanner function is the core of the port scanning process: It accepts the target host and a range of ports to scan and prints a message indicating the range of ports being scanned before initiating the threads. For each port in the range, it creates a new thread that runs the scan_portfunction (line 18). This approach leverages the power of multithreading to check multiple ports in parallel, significantly speeding up the scanning process compared with a single-threaded scan.
The script expects three command-line arguments: the target host, the start port, and the end port (Figure 2). The use of sys.argv (line 22) for argument parsing is simple and effective for this purpose.

Ideas for Further Development
The source code provided serves as an introductory example of socket development in Python. It is designed to demonstrate basic concepts and functionality. For educational purposes, I provide some suggestions to improve the code and offer a better user experience.
The error handling could be more granular. For example, the except block (line 11) currently only catches socket.timeout and ConnectionRefusedError, but other exceptions could arise, such as socket.gaierror for DNS resolution errors or socket.error for general socket errors. A more thorough exception handling mechanism could ensure that all potential issues are caught and handled appropriately. Additionally, the timeout value is hard-coded at one second (line 7). Although this value might work for most scenarios, it might need to be customized on the basis of user input or the nature of the network being scanned. For example, slower or more distant hosts could require longer timeouts to avoid false negatives.
Although the use of threads can improve performance, it has a few potential pitfalls. One major issue is that the function does not manage the number of concurrent threads. Each port in the specified range spawns a new thread, which can quickly overwhelm the system if the range is large. For example, scanning a range of 1,000 ports would create 1,000 threads, which could lead to excessive context switching, high CPU usage, or even crashes in extreme cases.
To address this issue, the program could implement a thread pool or limit the number of concurrent threads, ensuring that the system remains responsive and that resources are not overconsumed. Moreover, the function starts a thread for each port, without waiting for any threads to finish before starting the next one. As a result, threads could start too quickly, which might cause resource contention. A better approach might be to create a fixed number of threads that process ports sequentially in chunks or to wait for threads to complete before starting new ones.
The script does not provide much feedback or error handling for invalid input. For instance, if you provide an invalid IP address or a non-integer value for the port range, the script will raise ValueError or other errors, which might not be helpful. It would be more user friendly to validate the input and provide clear error messages, guiding your efforts to correct any mistakes. Furthermore, the script does not offer any options for customizing other parameters, such as the timeout value or the number of threads, which could be useful in a more flexible port scanning tool.
An Example
One scenario for the use of the port scanning script could be where a system administrator is responsible for securing a company's web server. The administrator needs to verify which network ports are open on the machine to ensure that only essential services (e.g., web traffic and secure communication) are accessible. Given the risk of cyber threats, identifying any unintended exposures is a crucial step in maintaining network security.
To perform this task, you execute the script from the command line, specifying the target machine's IP address along with the range of ports to scan. Suppose the web server in question is located at 192.168.1.10, and you want to check for open ports within the range from 1 to 1000. The appropriate command would be:
python port_scanner.py 192.168.1.10 1 1000With this command, the script initiates a scan on the specified IP address, systematically attempting to establish connections to each port within the given range. If a port is open, the script outputs a message indicating its status. For example, after execution, you might see the result:
Scanning 192.168.1.10 from port 1 to 1000
[+] Port 22 is open
[+] Port 80 is open
[+] Port 443 is openFrom this output, it becomes clear that SSH on port 22, HTTP on port 80, and HTTPS on port 443 are accessible on the server. This information is useful because it confirms that the essential services for secure web communication are operational. However, if unexpected ports appear in the results (e.g., port 3306, for MySQL databases, or port 3389, for the Remote Desktop Protocol), you might need to investigate further. Open database ports could, for example, allow unauthorized external access, posing a serious security risk.
From the findings, you can take immediate steps to mitigate potential threats. If any unnecessary ports are open, they can be closed by firewall rules or by disabling services that do not need external access. If certain services must remain open but require added protection, you could choose to restrict access to trusted IP addresses or implement additional security measures, such as multifactor authentication for remote access.
This use case demonstrates how the script provides a simple yet effective way to conduct basic security audits. By running a scan, you can quickly gather critical information about the network's exposure and take appropriate action to reduce vulnerabilities.
Conclusion
Although the provided port scanning script serves as a useful introduction to the concept of socket development in Python, recognize that it is far from being production-ready in its current form. The script effectively demonstrates the basic principles of port scanning, leveraging multithreading for efficiency, and offering a straightforward approach to identify open ports on a given host. However, for real-world use, several enhancements would be necessary, including improved error handling, thread management, input validation, and customization options to suit a variety of network environments.
The script lays the groundwork for understanding how network scans can be automated and integrated into security assessments, but it requires additional refinement to be robust and secure enough for deployment in larger, more complex environments. As a starting point, it provides valuable insight into how simple tools can be used for critical tasks such as vulnerability identification and risk mitigation.