Building a Port Scanner in Python
Create a multi-threaded Python port scanner with banner grabbing for network security auditing.
Port scanning is a technique used to identify open ports and services available on a network. It’s commonly used by network administrators for security auditing and by ethical hackers to discover potential vulnerabilities in a system. Python, with its simplicity and rich set of networking libraries, is a great choice for building a basic port scanner.
Hi,my name is CyCoderX. In this article, we’ll explore how to build a simple port scanner in Python, understand how it works, and examine some common port scanning techniques. By the end, you’ll have a working Python script capable of scanning a target IP address and identifying open ports.
Please consider helping by clapping and following me! 😊
Understanding Ports and Networking Basics
Before diving into the code, let’s quickly cover what ports are and why port scanning is important.
What Are Ports?
In networking, a port is a logical address assigned to a service or application on a device. It helps identify the type of communication happening over the network. Ports range from 0 to 65535 and are categorized into:
- Well-known Ports (0–1023): Reserved for popular services like HTTP (port 80) and FTP (port 21).
- Registered Ports (1024–49151): Assigned to specific services by software developers.
- Dynamic/Private Ports (49152–65535): Typically used for client applications.
Why Port Scanning?
Port scanning helps identify which ports are open or closed on a system. Open ports could indicate running services that may be exploited if not properly secured, so identifying them is crucial for system security.
Introduction to Socket Programming in Python
Python’s socket module is part of its standard library and provides the tools you need to perform low-level network communication. We’ll use this module to create connections and determine whether a port is open.
Basic Socket Functions
Here are a few key functions from the socket module that we’ll use in the port scanner:
socket.socket(): This creates a new socket object.socket.connect(): This tries to connect to an IP address on a specified port.socket.settimeout(): This sets a timeout to avoid waiting indefinitely for a response.
Example: Simple Socket Connection
To understand how sockets work, let’s look at a basic example of connecting to a web server:
import socket
def connect_to_server():
server = 'python.org'
port = 80
s = socket.socket()
s.settimeout(1)
try:
s.connect((server, port))
print(f"Connection to {server} on port {port} succeeded!")
except socket.error:
print(f"Connection to {server} on port {port} failed.")
finally:
s.close()
connect_to_server()Explanation:
Import the socket module: This module provides access to the BSD socket interface, which is used for network communication.
Define the connect_to_server function:
- Set server and port: The server is set to ‘python.org’ and the port to 80 (HTTP port).
- Create a socket object:
s = socket.socket()creates a new socket using the default parameters (IPv4 and TCP). - Set a timeout:
s.settimeout(1)sets a timeout of 1 second for blocking socket operations.
Try to connect to the server:
- Attempt connection:
s.connect((server, port))tries to connect to the specified server and port. - Print success message: If the connection is successful, it prints a success message.
- Handle connection errors: If there is a socket error, it prints a failure message.
Close the socket: s.close() ensures the socket is closed whether the connection attempt was successful or not.
Call the function: connect_to_server() is called to execute the above steps.
This simple script attempts to connect to python.org on port 80 (the HTTP port). If successful, it prints a success message, otherwise it reports a failure.
Building the Port Scanner
Now that we have an understanding of how sockets work, we can start building our port scanner. The scanner will attempt to connect to each port within a specified range on a target IP address. If a connection is successful, it means the port is open.
Step 1: Setting Up the Scanner Function
We’ll write a function that scans a range of ports on a given IP address. Let’s start with the core functionality:
def port_scan(target, port_range):
print(f"Scanning target: {target}")
for port in range(*port_range):
s = socket.socket()
s.settimeout(0.5)
try:
s.connect((target, port))
print(f"Port {port} is open")
except:
pass # Ignore closed ports
finally:
s.close()
# Example usage:
target_ip = '192.168.1.1' # Replace with your target IP
port_range = (1, 1024) # Scan ports from 1 to 1024
port_scan(target_ip, port_range)Explanation:
Define the port_scan function:
- Print target information: Outputs the target being scanned.
- Iterate over port range: Loops through each port in the specified range.
- Create a socket object:
s = socket.socket()creates a new socket for each port. - Set a timeout:
s.settimeout(0.5)sets a timeout of 0.5 seconds for each connection attempt.
Try to connect to each port:
- Attempt connection:
s.connect((target, port))tries to connect to the target on the current port. - Print open port: If the connection is successful, it prints that the port is open.
- Handle connection failures: If the connection fails, it does nothing (ignores closed ports).
Close the socket: s.close() ensures the socket is closed after each connection attempt.
Example usage:
- Set target IP:
target_ip = '192.168.1.1'specifies the target IP address. - Set port range:
port_range = (1, 1024)specifies the range of ports to scan (from 1 to 1024). - Call the function:
port_scan(target_ip, port_range)initiates the port scan on the specified target and port range.
This function loops through the specified range of ports and attempts to connect to each one. If a connection is successful, it prints the open port number.
Improving the Port Scanner with Multi-threading
Scanning a large range of ports sequentially can take time, especially if many ports are closed. To speed up the process, we can use multi-threading, which allows us to scan multiple ports simultaneously. Python’s threading module makes it easy to implement this.
Step 2: Adding Multi-threading
Let’s modify the port_scan function to use threads so that multiple ports can be scanned at the same time:
import threading
def threaded_port_scan(target, port_range):
def scan_port(port):
s = socket.socket()
s.settimeout(0.5)
try:
s.connect((target, port))
print(f"Port {port} is open")
except:
pass
finally:
s.close()
threads = []
for port in range(*port_range):
t = threading.Thread(target=scan_port, args=(port,))
threads.append(t)
t.start()
# Wait for all threads to finish
for t in threads:
t.join()
# Example usage:
target_ip = '192.168.1.1' # Replace with your target IP
port_range = (1, 1024) # Scan ports from 1 to 1024
threaded_port_scan(target_ip, port_range)Code Explanation:
Import the threading module: This module allows for the creation and management of threads in Python.
Define the threaded_port_scan function:
Get CyCoderX’s stories in your inbox
Join Medium for free to get updates from this writer.
Define the scan_port function:
- Create a socket object:
s = socket.socket()creates a new socket. - Set a timeout:
s.settimeout(0.5)sets a timeout of 0.5 seconds for each connection attempt. - Attempt connection:
s.connect((target, port))tries to connect to the target on the current port. - Print open port: If the connection is successful, it prints that the port is open.
- Handle connection failures: If the connection fails, it does nothing (ignores closed ports).
- Close the socket:
s.close()ensures the socket is closed after each connection attempt.
Create a list for threads: threads = [] initializes an empty list to store thread objects.
Iterate over port range: Loops through each port in the specified range.
Create and start threads:
- Create a thread:
t = threading.Thread(target=scan_port, args=(port,))creates a new thread to run thescan_portfunction for each port. - Add thread to list:
threads.append(t)adds the thread to the list. - Start the thread:
t.start()starts the thread, initiating the port scan for that port.
Wait for all threads to finish:
- Join threads:
for t in threads: t.join()waits for each thread to complete before moving on.
Example usage:
- Set target IP:
target_ip = '192.168.1.1'specifies the target IP address. - Set port range:
port_range = (1, 1024)specifies the range of ports to scan (from 1 to 1024). - Call the function:
threaded_port_scan(target_ip, port_range)initiates the threaded port scan on the specified target and port range.
How It Works:
- We create a
scan_port()function that handles the scanning of individual ports. - We create a new thread for each port in the range and start it.
- After starting all threads, we call
join()to ensure that the main program waits for all threads to complete before exiting.
This method significantly speeds up the scanning process since multiple ports are being checked simultaneously.
Adding a Banner Grabbing Feature
To enhance the port scanner, we can implement banner grabbing. This technique involves sending a request to an open port and capturing the response, which often reveals information about the service running on that port (e.g., an HTTP server may return details about its software version).
Step 3: Implementing Banner Grabbing
Let’s add a simple banner grabbing function to our port scanner:
def grab_banner(s):
try:
banner = s.recv(1024).decode().strip()
return banner
except:
return None
def banner_grabbing_port_scan(target, port_range):
def scan_port(port):
s = socket.socket()
s.settimeout(0.5)
try:
s.connect((target, port))
banner = grab_banner(s)
if banner:
print(f"Port {port} is open: {banner}")
else:
print(f"Port {port} is open")
except (socket.timeout, ConnectionRefusedError):
pass
finally:
s.close()
threads = []
for port in range(*port_range):
t = threading.Thread(target=scan_port, args=(port,))
threads.append(t)
t.start()
for t in threads:
t.join()
# Example usage:
target_ip = '192.168.1.1' # Replace with your target IP
port_range = (1, 1024) # Scan ports from 1 to 1024
banner_grabbing_port_scan(target_ip, port_range)In this example:
- We define the
grab_banner()function, which attempts to receive and decode a response from the open port. - If a response (banner) is received, it’s printed along with the port number.
Full Code and Summary:
Python Port Scanner with Multi-threading and Banner Grabbing
import socket
import threading
def grab_banner(s):
try:
banner = s.recv(1024).decode().strip()
return banner
except:
return None
def scan_port(target, port):
s = socket.socket()
s.settimeout(0.5)
try:
s.connect((target, port))
banner = grab_banner(s)
if banner:
print(f"Port {port} is open: {banner}")
else:
print(f"Port {port} is open")
except (socket.timeout, ConnectionRefusedError):
pass
finally:
s.close()
def banner_grabbing_port_scan(target, port_range):
threads = []
for port in range(*port_range):
t = threading.Thread(target=scan_port, args=(target, port))
threads.append(t)
t.start()
for t in threads:
t.join()
# Example usage:
target_ip = '192.168.1.1' # Replace with your target IP
port_range = (1, 1024) # Scan ports from 1 to 1024
banner_grabbing_port_scan(target_ip, port_range)Summary of What the Code Does:
- Builds a multi-threaded port scanner in Python using the
socketmodule. - Scans a specified range of ports on a target IP address.
- Uses multi-threading to scan ports simultaneously, speeding up the process.
- Checks each port to see if it is open or closed.
- Adds a banner grabbing feature to capture service information from open ports.
- Handles timeouts and connection errors gracefully, avoiding crashes.
Conclusion
In this article, we’ve walked through building a simple yet powerful port scanner in Python using the socket module. We explored the basics of networking, how to scan ports, and ways to improve our scanner with multi-threading and error handling. Additionally, we implemented a banner grabbing feature to collect more information about the services running on open ports.
Here’s a quick recap of the key points:
- Understanding ports: Ports are crucial for network communication, and open ports can expose vulnerabilities.
- Socket programming: We used Python’s
socketmodule to create connections and check port statuses. - Multi-threading: By implementing multi-threading, we made our port scanner faster and more efficient.
- Error handling: Properly managing errors and timeouts ensured our scanner was robust.
- Banner grabbing: We added a feature to capture service information from open ports.
Port scanning is an essential skill for anyone interested in network security, and Python provides all the tools you need to implement it efficiently. As you gain more experience, you can further enhance your port scanner by adding features like logging, scanning specific protocols (e.g., TCP/UDP), or even integrating it with larger security auditing tools.
Further Exploration
Now that you’ve built a basic port scanner, here are some ways you can extend this project:
- Advanced scanning techniques: Implement more complex scanning techniques like SYN scanning or stealth scans.
- UDP port scanning: Add functionality to scan UDP ports, which behave differently from TCP ports.
- Service fingerprinting: Integrate libraries like
scapyornmapto perform more advanced service detection and OS fingerprinting.
By continuing to experiment and enhance your port scanner, you’ll deepen your understanding of network security and Python’s networking capabilities.
Final Words:
Thank you for taking the time to read my article.
This article was first published on Medium by CyCoderX.
Hey There! I’m CyCoderX, a data engineer who loves crafting end-to-end solutions. I write articles about Python, SQL, AI, Data Engineering, lifestyle and more!
If you want to explore similar articles and updates, feel free to explore my Medium profile:
Join me as we explore the exciting world of tech, data and beyond!
What did you think about this article? Let me know in the comments below … or above, depending on your device! 🙃
Please consider supporting me by:
- Clapping 50 times for this story
- Leaving a comment telling me your thoughts
- Highlighting your favorite part of the story
In Plain English 🚀
Thank you for being a part of the In Plain English community! Before you go:
- Be sure to clap and follow the writer ️👏️️
- Follow us: X | LinkedIn | YouTube | Discord | Newsletter
- Visit our other platforms: CoFeed | Differ
- More content at PlainEnglish.io








