-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathlan_scanner.py
More file actions
146 lines (120 loc) · 5.51 KB
/
Copy pathlan_scanner.py
File metadata and controls
146 lines (120 loc) · 5.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import os
import ipaddress
import argparse
from typing import List, Optional
from scanner.network_scanner import NetworkScanner
from utils.network_utils import get_local_networks, get_upstream_networks
def _prompt_custom_network() -> Optional[str]:
"""Prompt for a network in CIDR notation, re-asking until valid or cancelled."""
while True:
raw = input("Enter network in CIDR notation (e.g. 192.168.1.0/24), or blank to cancel: ").strip()
if not raw:
return None
try:
# strict=False lets the user type a host address (192.168.1.5/24) and
# still get the surrounding network, matching how NetworkScanner treats it.
return str(ipaddress.ip_network(raw, strict=False))
except ValueError:
print("Invalid CIDR. Example of a valid value: 192.168.1.0/24")
def _prompt_upstream_network() -> Optional[str]:
"""Auto-discover reachable upstream networks and let the user pick one."""
print("\nTracing route to discover upstream networks (this may take a few seconds)...")
upstream = get_upstream_networks()
if not upstream:
print("No upstream networks found (traceroute tool missing, or the gateway")
print("blocks the trace). You can still enter a network manually.")
return _prompt_custom_network()
print("\nDiscovered upstream networks (reachable via the gateway):")
for idx, net in enumerate(upstream, 1):
print(f"{idx}. {net['network']} (via hop {net['via']})")
while True:
raw = input("\nSelect an upstream network to scan (number), or blank to cancel: ").strip()
if not raw:
return None
try:
choice = int(raw) - 1
if 0 <= choice < len(upstream):
return upstream[choice]["network"]
except ValueError:
pass
print("Invalid choice!")
def select_network(networks: List[dict]) -> Optional[str]:
"""Interactively pick a network to scan.
Offers the locally-attached interface networks plus two extras: entering a
custom CIDR by hand, and auto-discovering upstream networks (the routers above
the gateway, which never show up as local interfaces). Returns the chosen CIDR
string, or None if the user cancels.
"""
if networks:
print("\nAvailable networks:")
for idx, net in enumerate(networks, 1):
print(f"{idx}. {net['network']} (Interface: {net['interface']})")
else:
print("\nNo local interface networks detected.")
print("\nOther options:")
print(" c. Enter a custom network manually (CIDR, e.g. 192.168.1.0/24)")
print(" d. Auto-discover upstream networks (landlord/gateway side)")
while True:
choice = input("\nSelect network to scan (number, or c/d): ").strip().lower()
if choice == "c":
result = _prompt_custom_network()
if result:
return result
continue
if choice == "d":
result = _prompt_upstream_network()
if result:
return result
continue
try:
index = int(choice) - 1
if 0 <= index < len(networks):
return networks[index]["network"]
except ValueError:
pass
print("Invalid choice! Enter a listed number, or 'c'/'d'.")
def main() -> None:
parser = argparse.ArgumentParser(description="Advanced Network Scanner")
parser.add_argument("-n", "--network", help="Network to scan (CIDR format, e.g., 192.168.1.0/24)")
parser.add_argument("--discover-upstream", action="store_true",
help="Auto-discover reachable upstream networks (routers above the gateway) and pick one to scan")
parser.add_argument("-t", "--threads", type=int, default=50, help="Number of threads (default: 50)")
parser.add_argument("-o", "--output", choices=["json", "csv", "txt"], help="Export format (json, csv, txt)")
parser.add_argument("-d", "--output-dir", default="scan_results", help="Output directory for scan results")
parser.add_argument("-T", "--timeout", type=float, default=0.5, help="Scan timeout in seconds (default: 0.5)")
parser.add_argument("--ip-timeout", type=float, default=2.0, help="Maximum time to spend on a single IP in seconds (default: 2.0)")
args = parser.parse_args()
try:
print("\n=== Advanced Network Scanner v4.0 ===")
if args.network:
network = args.network
elif args.discover_upstream:
network = _prompt_upstream_network()
if not network:
print("No network selected.")
return
else:
networks = get_local_networks()
network = select_network(networks)
if not network:
print("No network selected.")
return
# Create output directory if it doesn't exist
if args.output and not os.path.exists(args.output_dir):
os.makedirs(args.output_dir)
scanner = NetworkScanner(
network=network,
num_threads=args.threads,
scan_timeout=args.timeout,
ip_timeout=args.ip_timeout,
output_dir=args.output_dir
)
scanner.scan(export_format=args.output)
if args.output:
print(f"\nResults exported to {args.output_dir} directory in {args.output} format.")
except KeyboardInterrupt:
print("\n\nScanning stopped by user!")
except Exception as e:
print(f"\nError: {e}")
if __name__ == "__main__":
main()