/cnc/img/python-network-scanner.png

Creating a Network Port Scanner in Python Cheat Sheet: Part 1

Building a Command-Line Network Port Scanner in Python

In this tutorial, we’ll explore network programming in Python by building a command-line network port scanner. This tool will allow us to specify a target host and a range of ports to scan, and will report back on which ports are open and which are closed.

Prerequisites

Before we start, ensure that you have:

  1. A basic understanding of Python programming.
  2. Familiarity with networking concepts.
  3. Python installed on your machine. If you don’t have Python installed, you can download it from Python’s official website.

What is a Port Scanner?

A port scanner is a software application designed to probe a server or host for open ports. This information can be used by administrators to verify security policies of their networks and by attackers to identify running services on a host with the view to compromise it.

Now, let’s get started with our code.

Steps

  • Import necessary libraries
  • Initialize argparse and parse arguments
  • Define the port scanning function
  • Define the thread worker function
  • Populate the queue with ports to scan
  • Create threads and start the scan-
  • Wait for all threads to finish and print the results

Importing the required modules

First, we need to import the necessary libraries:

python
import socket
import threading
import argparse
from queue import Queue

Setting up The Options Menu With Argparse

We’re using Python’s built-in socket, threading, argparse and queue libraries. socket is used to create and interact with network sockets. threading is used to create and manage threads. argparse is used to handle command-line arguments, and Queue from the queue library is used to distribute work among multiple threads.

Now, we’ll set up our argument parser and define our port scanning function. Here is where we can define the help menu that will be shown to make using the tool easier. We choose -t to define our target ip address and -r for a range of ports to scan.

python
# Initialize argparse and setup the help menu to be triggered for the scanner
parser = argparse.ArgumentParser(description="Port scanner. Scans the specified host for open ports.")
parser.add_argument("-t", "--target", help="Specify the target. Default is localhost.", default="127.0.0.1")
parser.add_argument("-r", "--range", help="Specify the range of ports to be scanned. Default is 1-1024.", default="1-1024")
# Parse arguments
args = parser.parse_args()
# Extract host and port range from arguments
host = args.target
port_range = args.range.split("-")
start_port = int(port_range[0])
end_port = int(port_range[1])
# Initialize queues and lists for handling ports
queue = Queue()
open_ports = []
closed_ports = []
# The actual port scanning function
def port_scanner(port):
try:
# Create a new socket using the AF_INET address family (IPv4) and the SOCK_STREAM socket type (TCP)
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Try to connect to the host using that socket
socket_obj.connect((host, port))
return True
except:
return False

This block initializes our argument parser, which allows us to take inputs directly from the command line. It also sets up our port scanner function, which tries to connect to a given port and returns True if successful (the port is open), and False if not (the port is closed).

Implementing Threading

Next, we’ll add threading and our user-friendly output:

python
# The function to handle threading
def worker():
while not queue.empty():
port = queue.get()
if port_scanner(port):
print(f"Port {port} is open!")
open_ports.append(port)
else:
print(f"Port {port} is NOT open!")
closed_ports.append(port)

Next, we create a list to store our threads and create new threads targeting our worker function:

python
# Creating a new thread for each of the port in the queue
thread_list = []
for t in range(200): # Creating 200 threads
thread = threading.Thread(target=worker)
thread_list.append(thread)

Here, we’re creating 200 threads (this number can be adjusted as needed) and setting their target function as our worker function defined earlier. Each of these threads, when started, will work concurrently, taking ports from the queue and scanning them.

Initiate the Scan and Start Threading!

Now we’re ready to start our scan:

python
# Starting the scan
print(f"Starting the scan on host: {host}, over port range: {start_port}-{end_port}")
# Starting all threads
for thread in thread_list:
thread.start()

After creating them and initiating the scan, we start all our threads:

python
# Starting all threads
for thread in thread_list:
thread.start()

Each thread will start working on the worker function concurrently, taking ports from the queue and scanning them.

After starting them, we also want to wait for all threads to finish before we proceed. We do this by joining all threads:

python
# Waiting for all threads to finish
for thread in thread_list:
thread.join()

The join() function makes sure that the main program waits for all threads to complete their tasks before it continues. This is necessary because we want to make sure that all ports are scanned before we print out the results.

Once all threads have finished their work, we print the results: print(“Scan finished!“)

python
# Printing the results
print(f"Open ports on {host} are: {open_ports}")
# print(f"Closed ports on {host} are: {closed_ports}")

Putting it All Together

Have a look at our finished Network Port scanner!

python
# Import necessary libraries
import socket
import threading
import argparse
from queue import Queue
# Initialize argparse
parser = argparse.ArgumentParser(description="Port scanner. Scans the specified host for open ports.")
parser.add_argument("-t", "--target", help="Specify the target. Default is localhost.", default="127.0.0.1")
parser.add_argument("-r", "--range", help="Specify the range of ports to be scanned. Default is 1-1024.", default="1-1024")
# Parse arguments
args = parser.parse_args()
# Extract host and port range from arguments
host = args.target
port_range = args.range.split("-")
start_port = int(port_range[0])
end_port = int(port_range[1])
# Initialize queues and lists for handling ports
queue = Queue()
open_ports = []
closed_ports = []
# Define the port scanning function
def port_scanner(port):
try:
# Create a new socket using the AF_INET address family (IPv4) and the SOCK_STREAM socket type (TCP)
socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_obj.settimeout(1)
# Try to connect to the host using that socket
socket_obj.connect((host, port))
return True
except:
return False
# Define the thread worker function
def worker():
while not queue.empty():
port = queue.get()
if port_scanner(port):
print(f"Port {port} is open!")
open_ports.append(port)
else:
print(f"Port {port} is NOT open!")
closed_ports.append(port)
# Populate the queue with ports to scan
for port in range(start_port, end_port+1):
queue.put(port)
# Create threads
thread_list = []
for t in range(200): # Creating 200 threads
thread = threading.Thread(target=worker)
thread_list.append(thread)
# Start the scan
print(f"Starting the scan on host: {host}, over port range: {start_port}-{end_port}")
# Start all threads
for thread in thread_list:
thread.start()
# Wait for all threads to finish
for thread in thread_list:
thread.join()
# Print the results
print("Scan finished!")
print(f"Open ports on {host} are: {open_ports}")
print(f"Closed ports on {host} are: {closed_ports}")

And that’s it! You’ve just built a multi-threaded network port scanner in Python that scans a specified range of ports on a target host and reports back the open and closed ports. Remember, it’s important to use tools like this responsibly, and only on networks where you have permission to do so.