Agregado funcion de CIDR para el area de Scan

This commit is contained in:
Miguel 2025-04-04 14:41:10 +02:00
parent 61d669d83a
commit a948581619
2 changed files with 156 additions and 68 deletions

View File

@ -472,21 +472,45 @@ class IPChangerApp:
)
self.scan_end_entry.grid(row=0, column=3, sticky="w", padx=5)
# Scan buttons
# Add CIDR field in Network Scan
ttk.Label(self.scan_frame, text="CIDR (/bits):").grid(
row=0, column=4, sticky="w", padx=5
)
self.scan_cidr_bits = tk.StringVar(value="24")
self.scan_cidr_entry = ttk.Entry(
self.scan_frame, textvariable=self.scan_cidr_bits, width=5
)
self.scan_cidr_entry.grid(row=0, column=5, sticky="w", padx=5)
# Add trace to update the scan range when CIDR changes
self.scan_cidr_bits.trace("w", self.update_scan_range_from_cidr)
# Display number of nodes to scan
ttk.Label(self.scan_frame, text="Nodes to scan:").grid(
row=1, column=0, sticky="w", padx=5
)
self.nodes_to_scan = tk.StringVar(value="0")
nodes_display = ttk.Entry(
self.scan_frame, textvariable=self.nodes_to_scan, width=10, state="readonly"
)
nodes_display.grid(row=1, column=1, sticky="w", padx=5)
# Scan buttons - move to row 1, column 2-5
self.scan_buttons_frame = ttk.Frame(self.scan_frame)
self.scan_buttons_frame.grid(row=0, column=4, columnspan=2, padx=5)
self.scan_buttons_frame.grid(row=1, column=2, columnspan=4, padx=5, sticky="e")
ttk.Button(self.scan_buttons_frame, text="Start Scan", command=self.start_scan).grid(
row=0, column=0, padx=5
)
ttk.Button(self.scan_buttons_frame, text="Stop Scan", command=self.stop_scan).grid(
row=0, column=1, padx=5
)
ttk.Button(self.scan_buttons_frame, text="Get Host Info", command=self.gather_host_information).grid(
row=1, column=0, columnspan=2, padx=5, pady=3
)
ttk.Button(
self.scan_buttons_frame, text="Start Scan", command=self.start_scan
).grid(row=0, column=0, padx=5)
ttk.Button(
self.scan_buttons_frame, text="Stop Scan", command=self.stop_scan
).grid(row=0, column=1, padx=5)
ttk.Button(
self.scan_buttons_frame,
text="Get Host Info",
command=self.gather_host_information,
).grid(row=0, column=2, padx=5)
# Scan progress
# Scan progress - move to row 2
self.scan_progress = ttk.Progressbar(
self.scan_frame,
orient="horizontal",
@ -495,18 +519,18 @@ class IPChangerApp:
variable=self.scan_progress_var,
)
self.scan_progress.grid(
row=1, column=0, columnspan=6, sticky="ew", padx=5, pady=5
row=2, column=0, columnspan=6, sticky="ew", padx=5, pady=5
)
# Scan results
# Scan results - update row numbers
ttk.Label(self.scan_frame, text="Scan Results:").grid(
row=2, column=0, sticky="w", padx=5
row=3, column=0, sticky="w", padx=5
)
# Frame for results list and scrollbar
self.results_frame = ttk.Frame(self.scan_frame)
self.results_frame.grid(
row=3, column=0, columnspan=6, sticky="nsew", padx=5, pady=5
row=4, column=0, columnspan=6, sticky="nsew", padx=5, pady=5
)
self.results_frame.columnconfigure(0, weight=1)
self.results_frame.rowconfigure(0, weight=1)
@ -516,7 +540,7 @@ class IPChangerApp:
self.results_frame,
columns=("ip", "hostname", "mac"),
show="headings",
height=10
height=10,
)
# Define columns
@ -711,7 +735,7 @@ class IPChangerApp:
)
# Actualizar IP prefix si hay una IP válida
if (interface.ip_address):
if interface.ip_address:
prefix = ".".join(interface.ip_address.split(".")[:3])
self.ip_prefix.set(prefix)
@ -1113,7 +1137,7 @@ class IPChangerApp:
self.show_error("Start IP must be lower than or equal to End IP")
return
# Clear previous results - FIXED: use the treeview method instead of the old listbox
# Clear previous results
for item in self.scan_results_tree.get_children():
self.scan_results_tree.delete(item)
@ -1124,6 +1148,9 @@ class IPChangerApp:
self.scan_progress_var.set(0)
self.scan_progress["maximum"] = ip_range
# Update nodes to scan count
self.nodes_to_scan.set(str(ip_range))
self.log_message(
f"Starting scan from {start_ip} to {end_ip} ({ip_range} addresses)..."
)
@ -1176,7 +1203,9 @@ class IPChangerApp:
self.scan_queue.put(ipaddress.IPv4Address(ip_int))
# Start worker threads for parallel scanning
max_threads = min(20, ip_range) # Limit to 20 threads or fewer if range is small
max_threads = min(
20, ip_range
) # Limit to 20 threads or fewer if range is small
for i in range(max_threads):
thread = threading.Thread(target=self._scan_worker, daemon=True)
thread.start()
@ -1218,8 +1247,7 @@ class IPChangerApp:
# Add to results tree with placeholder values
self.master.after(
0,
lambda ip=ip_str: self.add_scan_result(ip, "", "")
0, lambda ip=ip_str: self.add_scan_result(ip, "", "")
)
# Update progress
@ -1239,15 +1267,14 @@ class IPChangerApp:
return
# Start the information gathering in a separate thread
threading.Thread(
target=self._execute_host_gathering,
daemon=True
).start()
threading.Thread(target=self._execute_host_gathering, daemon=True).start()
def _execute_host_gathering(self):
"""Perform the actual host information gathering"""
try:
self.log_message(f"Gathering information for {len(self.scan_results)} hosts...")
self.log_message(
f"Gathering information for {len(self.scan_results)} hosts..."
)
# Reset progress bar for this operation
total_hosts = len(self.scan_results)
@ -1260,7 +1287,9 @@ class IPChangerApp:
self.log_message("Host information gathering stopped.")
break
self.log_message(f"Getting information for host {ip} ({i+1}/{total_hosts})...")
self.log_message(
f"Getting information for host {ip} ({i+1}/{total_hosts})..."
)
# Get hostname and MAC
hostname = self.get_hostname(ip)
@ -1293,12 +1322,14 @@ class IPChangerApp:
try:
# Find the item with this IP
for item_id in self.scan_results_tree.get_children():
values = self.scan_results_tree.item(item_id, 'values')
values = self.scan_results_tree.item(item_id, "values")
if values and values[0] == ip:
# Update the values
hostname_str = hostname if hostname else "Not resolved"
mac_str = mac if mac else "Not found"
self.scan_results_tree.item(item_id, values=(ip, hostname_str, mac_str))
self.scan_results_tree.item(
item_id, values=(ip, hostname_str, mac_str)
)
break
except Exception as e:
self.log_message(f"Error updating host in treeview: {str(e)}")
@ -1602,6 +1633,9 @@ class IPChangerApp:
mask_bits = bin(int(mask_obj))[2:].zfill(32)
network_bits = mask_bits.count("1")
# Update the scan CIDR field
self.scan_cidr_bits.set(str(network_bits))
# Create network object
network = ipaddress.IPv4Network(
f"{ip_address}/{network_bits}", strict=False
@ -1621,11 +1655,53 @@ class IPChangerApp:
self.scan_start_ip.set(str(start_ip))
self.scan_end_ip.set(str(end_ip))
self.log_message(f"Updated scan range: {start_ip} - {end_ip}")
# Update the nodes to scan count
nodes_count = int(end_ip) - int(start_ip) + 1
self.nodes_to_scan.set(str(nodes_count))
self.log_message(
f"Updated scan range: {start_ip} - {end_ip} ({nodes_count} nodes)"
)
except Exception as e:
self.log_message(f"Error calculating IP range: {str(e)}")
def update_scan_range_from_cidr(self, *args):
"""Update scan IP range when CIDR value changes - only modify End IP"""
try:
start_ip = self.scan_start_ip.get().strip()
cidr_bits = self.scan_cidr_bits.get().strip()
if not start_ip or not cidr_bits.isdigit():
return
# Convert CIDR to network
bits = int(cidr_bits)
if 0 <= bits <= 32:
# Use the start IP as the base for the network
network = ipaddress.IPv4Network(f"{start_ip}/{bits}", strict=False)
# Keep the original start IP and just update the end IP
# For the end IP, use the broadcast address (or last usable address)
if network.num_addresses <= 2:
end_ip = network.broadcast_address
else:
end_ip = network.broadcast_address - 1
# Update only the end IP field
self.scan_end_ip.set(str(end_ip))
# Update the nodes to scan count
start = ipaddress.IPv4Address(start_ip)
nodes_count = int(end_ip) - int(start) + 1
self.nodes_to_scan.set(str(nodes_count))
self.log_message(
f"Updated scan range from CIDR: {start_ip} - {end_ip} ({nodes_count} nodes)"
)
except Exception as e:
self.log_message(f"Error updating scan range from CIDR: {str(e)}")
def get_hostname(self, ip_address):
"""Try to resolve hostname for an IP address with better error handling"""
try:
@ -1642,7 +1718,9 @@ class IPChangerApp:
self.log_message(f"Timeout resolving hostname for {ip_address}")
return ""
except Exception as e:
self.log_message(f"Unknown error resolving hostname for {ip_address}: {str(e)}")
self.log_message(
f"Unknown error resolving hostname for {ip_address}: {str(e)}"
)
return ""
def get_mac_address(self, ip_address):
@ -1654,37 +1732,47 @@ class IPChangerApp:
shell=True,
capture_output=True,
text=True,
timeout=2
timeout=2,
)
if result.returncode == 0 and result.stdout:
# Log the raw output for debugging
self.log_message(f"ARP output for {ip_address}: {result.stdout.strip()}")
self.log_message(
f"ARP output for {ip_address}: {result.stdout.strip()}"
)
# Parse the output to find the MAC address
# First try the typical format with hyphens or colons
mac_match = re.search(r"([0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2})",
mac_match = re.search(
r"([0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2}[-:][0-9A-F]{2})",
result.stdout,
re.IGNORECASE)
re.IGNORECASE,
)
if mac_match:
return mac_match.group(0)
# Try an alternative format with spaces (Windows format)
mac_match = re.search(r"([0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2})",
mac_match = re.search(
r"([0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2}[\s-][0-9a-f]{2})",
result.stdout,
re.IGNORECASE)
re.IGNORECASE,
)
if mac_match:
return mac_match.group(0)
# Try yet another approach - look for any string of hex digits with separators
lines = result.stdout.strip().split('\n')
lines = result.stdout.strip().split("\n")
for line in lines:
if ip_address in line:
parts = line.split()
# Usually the MAC address is the second column in the output
if len(parts) >= 2:
# Check if the second part looks like a MAC address
if re.match(r"([0-9a-f]{2}[^\w]){5}[0-9a-f]{2}", parts[1], re.IGNORECASE):
if re.match(
r"([0-9a-f]{2}[^\w]){5}[0-9a-f]{2}",
parts[1],
re.IGNORECASE,
):
return parts[1]
self.log_message(f"No MAC address found for {ip_address}")

View File

@ -1 +1 @@
{"10.1.22": "10.1.22.11", "10.138.182": "10.138.182.94", "10.1.20": "10.1.20.11"}
{"10.1.22": "10.1.22.11", "10.138.182": "10.138.182.94", "10.1.20": "10.1.20.11", "10.255.255": "10.255.255.1"}