Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions CONTRIBUTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# 🛠️ Contribution — NET-Shell Feature Expansion

## Overview

This contribution significantly expands the NET-Shell toolkit from a 4-tool diagnostic suite into a comprehensive **7-module operator platform**, adding active reconnaissance, infrastructure analysis, performance benchmarking, and full session logging capabilities.

---

## Modules Added

### 1. 🗺️ Traceroute Path Analysis (`modules/traceroute.py`)
Implements network hop tracing using raw ICMP/UDP socket probes with incrementing TTL values — the same technique used by the Unix `traceroute` utility. Each hop is resolved to a hostname where possible, with per-hop RTT displayed in a formatted operator table. Supports configurable max hop depth and graceful Ctrl+C interruption.

### 2. 🌍 WHOIS & IP Geolocation Lookup (`modules/whois_lookup.py`)
Performs a two-part intelligence query on any domain or IP address:
- **Geolocation** via the `ip-api.com` JSON API — returns country, region, city, ISP, ASN, and organization.
- **WHOIS registration data** via the `python-whois` library — returns registrar, creation/expiry dates, name servers, and contact emails.

### 3. 📡 Continuous Ping / Latency Monitor (`modules/ping_monitor.py`)
A TCP-based connectivity probe that continuously measures round-trip time to a target host on a configurable port. Displays per-probe results with a color-coded latency bar (green/yellow/red) and live statistics including minimum, maximum, average latency, jitter (mean absolute deviation), and packet loss percentage. Final summary printed on exit.

### 4. 🔍 WAF / Firewall Fingerprinter (`modules/waf_fingerprint.py`)
Sends a battery of 5 crafted HTTP probes (normal request, SQL injection, XSS, path traversal, malicious User-Agent) to a target and analyzes response status codes and headers against a database of **15 known WAF/CDN signatures** including Cloudflare, Akamai, AWS CloudFront, Imperva Incapsula, ModSecurity, F5 BIG-IP, and more. Produces a fingerprint report with server banner and detected protection layers.

### 5. ⚡ Bandwidth Speed Estimator (`modules/speedtest.py`)
Measures real-world download throughput by streaming test payloads from public CDN endpoints (Cloudflare Workers, GitHub). Displays a live animated progress bar with real-time Mbps readout during download, then produces a summary report with per-endpoint results, average speed, and a connection tier rating (Excellent / Good / Fair / Poor).

### 6. 📊 Network Interface Monitor (`modules/net_monitor.py`)
A live, auto-refreshing terminal dashboard powered by `psutil` that displays per-interface network statistics for every adapter on the system. Metrics include download/upload rates (human-readable), packet counts, error counts, and drop counts — all updated every configurable interval using in-place ANSI cursor redraw. Activity levels are visualized with a color-coded bar that saturates at 10 MB/s.

### 7. 🗂️ Session Logger & Report Exporter (`modules/session_logger.py`)
A stdout interception system using a `TeeStream` wrapper that transparently captures the output of any tool run during the session without disrupting live display. Captured entries are stored in memory with timestamps and tool labels. Operators can view a paginated in-session log or export the full session as:
- A structured **plain-text report** (`.txt`)
- A machine-readable **JSON report** (`.json`)

Automatic capture is wired into the WAF Fingerprinter, Speed Estimator, and Interface Monitor — no manual intervention required.

---

## Files Modified

| File | Change |
|------|--------|
| `modules/menu.py` | Added imports, 7 new menu entries (`[5]`–`[7]`, `[A]`–`[C]`, `[L]`), and handler functions for each new tool |
| `main.py` | Added imports and routing for all new menu choices in the main event loop |
| `requirements.txt` | Added `python-whois` dependency |

---

## Technical Highlights

- **No heavy new dependencies** — all network operations use Python stdlib (`socket`, `urllib`, `ssl`, `asyncio`); only `python-whois` added
- **macOS SSL compatibility** — all HTTPS requests use a safe SSL context (certifi bundle or unverified fallback) to prevent `CERTIFICATE_VERIFY_FAILED` errors common on macOS Python installs
- **Consistent operator UX** — all modules follow the existing ANSI color scheme (green/cyan/yellow/red), use the same interrupt-handling pattern (`KeyboardInterrupt`), and return cleanly to the main menu
- **Modular architecture** — each feature is fully self-contained in its own module file, keeping `main.py` and `menu.py` as thin orchestration layers
39 changes: 37 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Add current directory to path to ensure modules are found
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from modules import menu, host, utils, scanner, system
from modules import menu, host, utils, scanner, system, traceroute, whois_lookup, ping_monitor
from modules import waf_fingerprint, speedtest, session_logger, net_monitor

# Conditional imports for setup, update, and maintenance utilities
try:
Expand Down Expand Up @@ -61,16 +62,50 @@ def start():
input("\nPress Enter to return...")

elif choice == '5':
menu.handle_traceroute_input()
input("\nPress Enter to return...")

elif choice == '6':
menu.handle_whois_input()
input("\nPress Enter to return...")

elif choice == '7':
menu.handle_ping_monitor_input()
input("\nPress Enter to return...")

elif choice == '8':
m_choice = menu.maintenance_menu()
if m_choice == '1':
setup.install_requirements()
elif m_choice == '2':
cleaner.purge_cache()

elif choice == '6':
elif choice == '9':
update.check_for_updates()
input("\nPress Enter to return...")

elif choice == 'a':
session_logger.start_capture("WAF / Firewall Fingerprinter")
menu.handle_waf_input()
session_logger.stop_capture()
input("\nPress Enter to return...")

elif choice == 'b':
session_logger.start_capture("Bandwidth Speed Estimator")
menu.handle_speedtest_input()
session_logger.stop_capture()
input("\nPress Enter to return...")

elif choice == 'c':
session_logger.start_capture("Network Interface Monitor")
menu.handle_net_monitor_input()
session_logger.stop_capture()
input("\nPress Enter to return...")

elif choice == 'l':
menu.handle_session_logger_input()
input("\nPress Enter to return...")

elif choice == 'q':
utils.typing_effect("\033[91mSession Terminated. Goodbye, Operator.\033[0m")
sys.exit(0)
Expand Down
94 changes: 90 additions & 4 deletions modules/menu.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os
import time
from ui import name
from modules import host, flood, utils, scanner, system
from modules import host, flood, utils, scanner, system, traceroute, whois_lookup, ping_monitor
from modules import waf_fingerprint, speedtest, session_logger, net_monitor

# ANSI Styling for a cohesive terminal look
GREEN = "\033[92m"
Expand Down Expand Up @@ -31,10 +32,17 @@ def display_main_menu():
print(f"{GREEN}[2]{RESET} HTTP Request Flood (Full Config)")
print(f"{GREEN}[3]{RESET} TCP Port Scanner")
print(f"{GREEN}[4]{RESET} Local System Information")
print(f"{YELLOW}[5]{RESET} Maintenance & Setup")
print(f"{YELLOW}[6]{RESET} Check for Updates")
print(f"{CYAN}[5]{RESET} Traceroute Path Analysis")
print(f"{CYAN}[6]{RESET} WHOIS & IP Geolocation Lookup")
print(f"{CYAN}[7]{RESET} Continuous Ping / Latency Monitor")
print(f"{CYAN}[A]{RESET} WAF / Firewall Fingerprinter")
print(f"{CYAN}[B]{RESET} Bandwidth Speed Estimator")
print(f"{CYAN}[C]{RESET} Network Interface Monitor")
print(f"{CYAN}[L]{RESET} Session Logger & Report Exporter")
print(f"{YELLOW}[8]{RESET} Maintenance & Setup")
print(f"{YELLOW}[9]{RESET} Check for Updates")
print(f"{RED}[Q]{RESET} Exit System")
print(f"{CYAN}{'━'*35}{RESET}")
print(f"{CYAN}{'━'*40}{RESET}")

try:
return input(PROMPT).strip().lower()
Expand Down Expand Up @@ -74,6 +82,84 @@ def handle_flood_input():
except ValueError:
print(f"{RED}[!] Input Error: Please enter numeric values for counts and intervals.{RESET}")

def handle_traceroute_input():
"""Collects target and runs traceroute path analysis."""
print(f"\n{CYAN}--- TRACEROUTE ---{RESET}")
try:
target = input(f"{CYAN}Target (IP or Domain): {RESET}").strip()
hops_input = input(f"{CYAN}Max Hops [30]: {RESET}").strip()
max_hops = int(hops_input) if hops_input.isdigit() else 30
traceroute.traceroute(target, max_hops=max_hops)
except KeyboardInterrupt:
print(f"\n{YELLOW}[!] Aborted. Returning to net-shell...{RESET}")
time.sleep(1)

def handle_whois_input():
"""Collects target and runs WHOIS + geolocation lookup."""
print(f"\n{CYAN}--- WHOIS & GEOLOCATION ---{RESET}")
try:
target = input(f"{CYAN}Target (Domain or IP): {RESET}").strip()
whois_lookup.whois_lookup(target)
except KeyboardInterrupt:
print(f"\n{YELLOW}[!] Aborted. Returning to net-shell...{RESET}")
time.sleep(1)

def handle_ping_monitor_input():
"""Collects config and runs the continuous latency monitor."""
print(f"\n{CYAN}--- PING / LATENCY MONITOR ---{RESET}")
try:
target = input(f"{CYAN}Target (IP or Domain): {RESET}").strip()
count_input = input(f"{CYAN}Probe Count [20]: {RESET}").strip()
interval_input = input(f"{CYAN}Interval Seconds [1]: {RESET}").strip()
port_input = input(f"{CYAN}TCP Port [80]: {RESET}").strip()
count = int(count_input) if count_input.isdigit() else 20
interval = float(interval_input) if interval_input else 1.0
port = int(port_input) if port_input.isdigit() else 80
ping_monitor.ping_monitor(target, count=count, interval=interval, port=port)
except KeyboardInterrupt:
print(f"\n{YELLOW}[!] Aborted. Returning to net-shell...{RESET}")
time.sleep(1)
except ValueError:
print(f"{RED}[!] Input Error: Please enter numeric values.{RESET}")

def handle_waf_input():
"""Collects target URL and runs WAF/firewall fingerprinting."""
print(f"\n{CYAN}--- WAF / FIREWALL FINGERPRINTER ---{RESET}")
try:
target = input(f"{CYAN}Target URL (e.g. https://example.com): {RESET}").strip()
waf_fingerprint.fingerprint(target)
except KeyboardInterrupt:
print(f"\n{YELLOW}[!] Aborted. Returning to net-shell...{RESET}")
time.sleep(1)

def handle_speedtest_input():
"""Runs the bandwidth speed estimator."""
print(f"\n{CYAN}--- BANDWIDTH SPEED ESTIMATOR ---{RESET}")
try:
speedtest.run_speed_test()
except KeyboardInterrupt:
print(f"\n{YELLOW}[!] Aborted. Returning to net-shell...{RESET}")
time.sleep(1)

def handle_net_monitor_input():
"""Collects config and runs the live network interface monitor."""
print(f"\n{CYAN}--- NETWORK INTERFACE MONITOR ---{RESET}")
try:
interval_input = input(f"{CYAN}Refresh interval seconds [1]: {RESET}").strip()
duration_input = input(f"{CYAN}Monitor duration seconds [60]: {RESET}").strip()
interval = float(interval_input) if interval_input else 1.0
duration = int(duration_input) if duration_input.isdigit() else 60
net_monitor.run_interface_monitor(interval=interval, duration=duration)
except KeyboardInterrupt:
print(f"\n{YELLOW}[!] Aborted. Returning to net-shell...{RESET}")
time.sleep(1)
except ValueError:
print(f"{RED}[!] Input Error: Please enter numeric values.{RESET}")

def handle_session_logger_input():
"""Opens the session logger sub-menu."""
session_logger.session_menu()

def maintenance_menu():
"""Renders the maintenance sub-menu with interrupt handling."""
header()
Expand Down
130 changes: 130 additions & 0 deletions modules/net_monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import psutil
import time
import sys
import os

GREEN = "\033[92m"
RED = "\033[91m"
YELLOW = "\033[93m"
CYAN = "\033[96m"
DIM = "\033[2m"
BOLD = "\033[1m"
RESET = "\033[0m"
CLEAR_LINE = "\033[2K\r"

def _bytes_fmt(n: float) -> str:
"""Formats bytes into a human-readable string."""
for unit in ("B", "KB", "MB", "GB"):
if abs(n) < 1024:
return f"{n:.1f} {unit}"
n /= 1024
return f"{n:.1f} TB"

def _bar(ratio: float, width: int = 18) -> str:
ratio = max(0.0, min(ratio, 1.0))
filled = int(ratio * width)
color = GREEN if ratio < 0.6 else (YELLOW if ratio < 0.85 else RED)
return f"{color}{'█' * filled}{'░' * (width - filled)}{RESET}"

def _get_interface_stats() -> dict:
"""Returns per-interface counters from psutil."""
return psutil.net_io_counters(pernic=True)

def _clear_dashboard(line_count: int):
"""Moves cursor up 'line_count' lines to redraw the dashboard in-place."""
sys.stdout.write(f"\033[{line_count}A")

def run_interface_monitor(interval: float = 1.0, duration: int = 60):
"""
Displays a live, auto-refreshing dashboard of per-interface network stats:
bytes sent/received, packets, errors, and drops — updated every `interval` seconds.
Press Ctrl+C to stop early.
"""
print(f"\n{CYAN}{'━'*65}{RESET}")
print(f"{CYAN} NETWORK INTERFACE MONITOR (refresh: {interval}s | runtime: {duration}s){RESET}")
print(f"{CYAN} Press Ctrl+C to stop{RESET}")
print(f"{CYAN}{'━'*65}{RESET}\n")

try:
prev_stats = _get_interface_stats()
prev_time = time.perf_counter()
first_draw = True
drawn_lines = 0
elapsed = 0

while elapsed < duration:
time.sleep(interval)
curr_stats = _get_interface_stats()
curr_time = time.perf_counter()
dt = curr_time - prev_time

# Collect all rows to know how many lines to redraw
rows = []
for iface, curr in curr_stats.items():
prev = prev_stats.get(iface)
if prev is None:
continue

rx_rate = (curr.bytes_recv - prev.bytes_recv) / dt
tx_rate = (curr.bytes_sent - prev.bytes_sent) / dt
pkt_rx = (curr.packets_recv - prev.packets_recv)
pkt_tx = (curr.packets_sent - prev.packets_sent)
errin = curr.errin
errout = curr.errout
dropin = curr.dropin
dropout = curr.dropout

rows.append((iface, rx_rate, tx_rate, pkt_rx, pkt_tx, errin, errout, dropin, dropout))

# Redraw — move cursor up on subsequent draws
if not first_draw:
_clear_dashboard(drawn_lines)

lines_written = 0
header = (
f"{DIM}{'INTERFACE':<14} {'▼ RX':>12} {'▲ TX':>12} "
f"{'PKT RX':>8} {'PKT TX':>8} "
f"{'ERR':>5} {'DROP':>5} {'ACTIVITY'}{RESET}"
)
print(header)
print(f"{DIM}{'─'*75}{RESET}")
lines_written += 2

for (iface, rx_rate, tx_rate, pkt_rx, pkt_tx,
errin, errout, dropin, dropout) in rows:

err_total = errin + errout
drop_total = dropin + dropout
activity = _bar(min((rx_rate + tx_rate) / (10 * 1024 * 1024), 1.0)) # saturates at 10 MB/s

err_col = f"{RED}{err_total}{RESET}" if err_total else f"{DIM}0{RESET}"
drop_col = f"{RED}{drop_total}{RESET}" if drop_total else f"{DIM}0{RESET}"

print(
f"{GREEN}{iface:<14}{RESET}"
f"{CYAN}{_bytes_fmt(rx_rate):>10}/s{RESET}"
f" {YELLOW}{_bytes_fmt(tx_rate):>10}/s{RESET}"
f" {pkt_rx:>8} {pkt_tx:>8}"
f" {err_col:>5} {drop_col:>5} {activity}"
)
lines_written += 1

# Footer
elapsed += interval
remaining = duration - elapsed
sys.stdout.write(
f"\n{DIM}╰─ Elapsed: {elapsed:.0f}s | Remaining: {remaining:.0f}s{RESET}\n"
)
sys.stdout.flush()
lines_written += 2

drawn_lines = lines_written
first_draw = False
prev_stats = curr_stats
prev_time = curr_time

except KeyboardInterrupt:
print(f"\n\n{YELLOW}[!] Monitor stopped by operator.{RESET}")
return

print(f"\n{GREEN}[+] Monitoring session complete.{RESET}")
Loading