Random Musings

Sporadic thoughts on tech, economics, business, finance and trading

PyNetScanner

,

An annotated explanation of the code with details on what each component is (method, function, variable, or construct) for my utility at

https://github.com/genzo1977/PyNetScanner


Imports

import tkinter as tk  # Module import
from tkinter import ttk  # Module import
from ipaddress import ip_network  # Function import
from pythonping import ping  # Function import
import threading  # Module import
  • Module Import: tkinter, threading
    • These are libraries/modules that provide additional functionality. tkinter is for GUI creation, and threading is for running tasks in parallel.
  • Function Import: ip_network, ping
    • Specific functions brought into the code for subnet handling (ip_network) and network pinging (ping).

Global Variable

cancel_scan = False  # Global variable
  • Variable: cancel_scan
    • A Boolean flag used to indicate whether the scanning process should stop. It’s modified across functions (global scope).

Function: scan

def scan():  # Function definition
    global cancel_scan  # Keyword: global variable reference
  • Function: scan
    • A block of code that performs the main scanning task when triggered.
  • Global Variable Reference: cancel_scan
    • Allows the function to modify the globally defined variable.

Subsection: Input Validation

    network_addr = network_var.get()  # Method call: variable retrieval
    try:
        network = ip_network(network_addr, strict=False)  # Method: input parsing
    except ValueError:  # Exception Handling: invalid input
  • Variable Assignment: network_addr
    • Fetches the user input from the GUI text field.
  • Method Call: network_var.get()
    • Calls the get method to retrieve text input.
  • Input Parsing: ip_network
    • Ensures the input is a valid CIDR format. Adjusts the IP range with strict=False.
  • Exception Handling: try and except ValueError
    • Catches invalid inputs and gracefully displays an error.

Subsection: Progress Calculation

    total_hosts = len(list(network.hosts()))  # Function calls
    progress_step = 100 / total_hosts  # Calculation
  • Function Calls: list(...) and len(...)
    • Converts the generator of hosts to a list and counts its elements.
  • Variable Assignment: progress_step
    • Calculates the percentage increment for the progress bar per host.

Nested Function: run_scan

    def run_scan():  # Nested function definition
        global cancel_scan  # Global variable reference
  • Function: run_scan
    • A sub-function of scan, handling the actual IP scanning in a separate thread.
  • Global Variable Reference: cancel_scan
    • Ensures the function can check for user cancellation.

Subsection: Looping Through Hosts

        for index, ip in enumerate(network.hosts(), start=1):  # Loop construct
            if cancel_scan:  # Conditional check
  • Loop: for
    • Iterates through all host IPs in the network.
  • Conditional Check: if cancel_scan
    • Stops the scan if the cancel button was clicked.

Subsection: Pinging and GUI Updates

            response = ping(ip, count=1, timeout=1, verbose=False)  # Function call
            if response.success():  # Conditional check
                results_listbox.insert(tk.END, f"IP: {ip} is online")  # Method call
            progress_bar["value"] += progress_step  # Progress bar update
  • Function Call: ping
    • Sends an ICMP ping to check if the IP is reachable.
  • Conditional Check: if response.success()
    • Verifies whether the ping succeeded.
  • Method Call: results_listbox.insert
    • Updates the listbox widget to display a result.
  • Progress Bar Update: progress_bar["value"]
    • Advances the progress bar by the calculated step.

Subsection: Cleanup After Completion

        scan_button.config(state=tk.NORMAL, text="Scan")  # Method call
        cancel_button.config(state=tk.DISABLED)  # Method call
  • Method Call: config
    • Resets the buttons to their initial state after the scan ends.

Threading

    threading.Thread(target=run_scan, daemon=True).start()  # Thread creation
  • Threading: Runs the run_scan function in a separate thread so that the GUI remains responsive.

Function: cancel

def cancel():  # Function definition
    global cancel_scan  # Global variable reference
    cancel_scan = True  # Variable modification
    cancel_button.config(state=tk.DISABLED)  # Method call
  • Function: cancel
    • Handles the user’s action to stop the ongoing scan.
  • Variable Modification: cancel_scan = True
    • Signals the run_scan loop to stop.
  • Method Call: cancel_button.config
    • Disables the cancel button to prevent repeated clicks.

GUI Setup

if __name__ == "__main__":  # Main program check
    root = tk.Tk()  # Object creation: main window
    root.title("Network Scanner")  # Method call
    root.geometry("400x300")  # Method call
    root.resizable(False, False)  # Method call
  • Main Program Check: if __name__ == "__main__"
    • Ensures the code runs only if this script is the entry point.
  • Object Creation: tk.Tk()
    • Initializes the main application window (root).
  • Method Calls: .title(), .geometry(), .resizable()
    • Configure the window title, size, and resize behavior.

Input and Buttons

    tk.Label(root, text="Network (e.g., 192.168.1.0/24):").pack(pady=5)  # Widget creation
    tk.Entry(root, textvariable=network_var, width=entry_width, justify=tk.CENTER).pack(pady=5)  # Widget creation
    scan_button = tk.Button(root, text="Scan", command=scan, width=entry_width).pack(pady=5)  # Widget creation
    cancel_button = tk.Button(root, text="Cancel", command=cancel, state=tk.DISABLED, width=entry_width).pack(pady=5)  # Widget creation
  • Widget Creation: Label, Entry, Button
    • Adds interactive elements (label, text entry, buttons) to the GUI.
  • Attributes:
    • text: Sets the label/button text.
    • command: Specifies the function to call on user interaction.
    • state: Defines the button’s enabled/disabled state.

Progress Bar

    progress_bar = ttk.Progressbar(root, orient="horizontal", length=300, mode="determinate").pack(pady=10)  # Widget creation
    progress_label = tk.Label(root, text="Progress: 0%").pack()  # Widget creation
  • Widget Creation: Progressbar, Label
    • Displays scanning progress visually and as text.

Results Listbox

    results_listbox = tk.Listbox(root, width=45, height=10).pack(pady=10)  # Widget creation
  • Widget Creation: Listbox
    • Adds a scrollable area to display scan results.

Main Loop

    root.mainloop()  # Event loop
  • Event Loop: Starts the GUI application and keeps it running until closed by the user.

This breakdown includes every component’s type, purpose, and role in the program.