Skip to content

Commit

Permalink
Implemented a separate thread for Nmap, and added a updating statusline
Browse files Browse the repository at this point in the history
  • Loading branch information
haraldaarz committed Aug 9, 2023
1 parent 9c36870 commit c34d887
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 45 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ Once you have the application running, you can use it to perform scans. Follow t

## Planned Features

- **Progress Bar:** Visualize the scan progress with a dynamic progress bar for improved user experience.
- **Compact Layout:** Rearrange the TCP and UDP scan buttons.
- **Custom Port Selection:** Scan specific ranges of ports by selecting custom top 10, 100, and 1000 port configurations.
- **Color-coded Output:** Enhance scan result readability by using color codes to distinguish different types of output.
- **Enhanced Error Handling:** Improve detection of incorrectly entered IP addresses, reducing user errors.
- **Efficient Keyboard Interaction:** Initiate scans using the Return key for quicker navigation.
- **Code Optimization:** Remove unnecessary star (*) imports to ensure a cleaner codebase.
- **Fix Freeze Bug:** Fix the bug that causes the application to freeze when a large scan is performed.
- Thread for Nmap scan
- **Update sceenshot.png:** Update the screenshot.

115 changes: 73 additions & 42 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,67 @@
import sys
import subprocess
import os
import threading
from threading import Thread
from PyQt6.QtCore import QTimer, QThread, pyqtSignal
# import ipaddress
# import socket
from datetime import datetime
from PyQt6.QtCore import QTimer
from PyQt6.QtWidgets import *


class NmapScanner(QThread):
scanFinished = pyqtSignal(str, str) # Custom signal to indicate scan completion
statusUpdate = pyqtSignal(str) # Define the statusUpdate signal

def __init__(self, ip_address, ports, rate, protocol, vuln_scan, extra):
super().__init__()
self.ip_address = ip_address
self.ports = ports
self.rate = rate
self.protocol = protocol
self.vuln_scan = vuln_scan
self.extra = extra


def run(self):
try:
now = datetime.now()
dt_string = now.strftime("%d-%m-%Y-%H-%M-%S")
filename = "scan_output-" + dt_string + ".txt"
nmap_cmd = ["nmap", "-sV", "-p", self.ports, "--stats-every", "1s", "-oG", filename]

if self.rate:
nmap_cmd.extend(["--min-rate", self.rate])

if self.vuln_scan:
nmap_cmd.extend(["--script=vulners"])

if self.protocol == "TCP":
nmap_cmd.append(self.ip_address)
else:
nmap_cmd.extend(["-sU", self.ip_address])

if self.extra:
nmap_cmd.extend(self.extra.split())

# Use subprocess.Popen to capture real-time output
result = subprocess.Popen(nmap_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)

# Emit status updates as they're received
for line in iter(result.stdout.readline, ''):
self.statusUpdate.emit(line.strip())
if result.poll() is not None:
break

# Emit the signal to indicate scan completion and pass the IP address and filename
self.scanFinished.emit(self.ip_address, filename)

except subprocess.CalledProcessError as e:
print(f"An error occurred: {e}")

except Exception as e:
print(f"An unexpected error occurred: {e}")


class Window(QMainWindow):
def __init__(self):
super().__init__(parent=None)
Expand Down Expand Up @@ -74,14 +127,11 @@ def __init__(self):
self.tab_widget = QTabWidget()
self.dialogLayout.addWidget(self.tab_widget)

# Create a QLabel for the status bar
self.status_label = QLabel("Status: Idle")
self.statusBar().addWidget(self.status_label)
self.status_bar = self.statusBar() # Store the status bar instance

self._createMenu()
self._createStatusBar()



def buttonOK_clicked(self):
ip_address = self.ip_address_input.text()
ports = self.ports_input.text()
Expand All @@ -95,39 +145,19 @@ def buttonOK_clicked(self):
QMessageBox.warning(self, "Input Error", "Please fill in IP and ports.")
return

try:
now = datetime.now()
dt_string = now.strftime("%d-%m-%Y-%H-%M-%S")
filename = "scan_output-" + dt_string + ".txt"
nmap_cmd = ["nmap", "-sV", "-p", ports, "--stats-every", "1s", "-oG", filename]

if rate:
nmap_cmd.extend(["--min-rate", rate])

if vuln_scan:
nmap_cmd.extend(["--script=vulners"])

if protocol == "TCP":
nmap_cmd.append(ip_address)
else:
nmap_cmd.extend(["-sU", ip_address])

if extra:
nmap_cmd.extend(extra.split())
# Create an instance of the NmapScanner class and connect its signal to a slot
self.nmap_thread = NmapScanner(ip_address, ports, rate, protocol, vuln_scan, extra)
self.nmap_thread.scanFinished.connect(self.handle_scan_finished)

result = subprocess.run(nmap_cmd, capture_output=True, text=True)
self.nmap_thread.statusUpdate.connect(self.update_status_bar)

# Open a new tab with the contents of the output file
with open(filename, "r") as file:
output_data = file.read()
self.create_output_tab(output_data, ip_address)
# Start the scan in a separate thread
self.nmap_thread.start()


except subprocess.CalledProcessError as e:
QMessageBox.warning(self, "Error", f"An error occurred: {e}")

except Exception as e:
QMessageBox.warning(self, "Error", f"An unexpected error occurred: {e}")
def handle_scan_finished(self, ip_address, filename):
with open(filename, "r") as file:
output_data = file.read()
self.create_output_tab(output_data, ip_address)


def create_output_tab(self, content, ip_address):
Expand Down Expand Up @@ -198,11 +228,12 @@ def _createMenu(self):
settings_menu.addAction("&About")


def _createStatusBar(self):
status = QStatusBar()
status.showMessage("Status progess: Running?")
self.setStatusBar(status)
def update_status_bar(self, status_text):
self.status_label.setText(f"Status: {status_text}")

def _createStatusBar(self):
self.status_label = QLabel("Status: Idle")
self.statusBar().addWidget(self.status_label)

if __name__ == "__main__":
app = QApplication([])
Expand Down

0 comments on commit c34d887

Please sign in to comment.