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) self.scan_end_entry.grid(row=0, column=3, sticky="w", padx=5)
# Scan buttons # Add CIDR field in Network Scan
self.scan_buttons_frame = ttk.Frame(self.scan_frame) ttk.Label(self.scan_frame, text="CIDR (/bits):").grid(
self.scan_buttons_frame.grid(row=0, column=4, columnspan=2, padx=5) row=0, column=4, sticky="w", padx=5
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( self.scan_cidr_bits = tk.StringVar(value="24")
row=0, column=1, padx=5 self.scan_cidr_entry = ttk.Entry(
) self.scan_frame, textvariable=self.scan_cidr_bits, width=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
) )
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)
# Scan progress # 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=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=0, column=2, padx=5)
# Scan progress - move to row 2
self.scan_progress = ttk.Progressbar( self.scan_progress = ttk.Progressbar(
self.scan_frame, self.scan_frame,
orient="horizontal", orient="horizontal",
@ -495,18 +519,18 @@ class IPChangerApp:
variable=self.scan_progress_var, variable=self.scan_progress_var,
) )
self.scan_progress.grid( 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( 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 # Frame for results list and scrollbar
self.results_frame = ttk.Frame(self.scan_frame) self.results_frame = ttk.Frame(self.scan_frame)
self.results_frame.grid( 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.columnconfigure(0, weight=1)
self.results_frame.rowconfigure(0, weight=1) self.results_frame.rowconfigure(0, weight=1)
@ -516,25 +540,25 @@ class IPChangerApp:
self.results_frame, self.results_frame,
columns=("ip", "hostname", "mac"), columns=("ip", "hostname", "mac"),
show="headings", show="headings",
height=10 height=10,
) )
# Define columns # Define columns
self.scan_results_tree.heading("ip", text="IP Address") self.scan_results_tree.heading("ip", text="IP Address")
self.scan_results_tree.heading("hostname", text="Hostname") self.scan_results_tree.heading("hostname", text="Hostname")
self.scan_results_tree.heading("mac", text="MAC Address") self.scan_results_tree.heading("mac", text="MAC Address")
# Set column widths # Set column widths
self.scan_results_tree.column("ip", width=120, anchor="w") self.scan_results_tree.column("ip", width=120, anchor="w")
self.scan_results_tree.column("hostname", width=200, anchor="w") self.scan_results_tree.column("hostname", width=200, anchor="w")
self.scan_results_tree.column("mac", width=150, anchor="w") self.scan_results_tree.column("mac", width=150, anchor="w")
# Add scrollbar # Add scrollbar
self.scan_results_scrollbar = ttk.Scrollbar( self.scan_results_scrollbar = ttk.Scrollbar(
self.results_frame, orient="vertical", command=self.scan_results_tree.yview self.results_frame, orient="vertical", command=self.scan_results_tree.yview
) )
self.scan_results_tree.configure(yscrollcommand=self.scan_results_scrollbar.set) self.scan_results_tree.configure(yscrollcommand=self.scan_results_scrollbar.set)
self.scan_results_tree.grid(row=0, column=0, sticky="nsew") self.scan_results_tree.grid(row=0, column=0, sticky="nsew")
self.scan_results_scrollbar.grid(row=0, column=1, sticky="ns") self.scan_results_scrollbar.grid(row=0, column=1, sticky="ns")
@ -711,7 +735,7 @@ class IPChangerApp:
) )
# Actualizar IP prefix si hay una IP válida # Actualizar IP prefix si hay una IP válida
if (interface.ip_address): if interface.ip_address:
prefix = ".".join(interface.ip_address.split(".")[:3]) prefix = ".".join(interface.ip_address.split(".")[:3])
self.ip_prefix.set(prefix) self.ip_prefix.set(prefix)
@ -1090,7 +1114,7 @@ class IPChangerApp:
# Try to get hostname and MAC address # Try to get hostname and MAC address
hostname = self.get_hostname(target) hostname = self.get_hostname(target)
mac_address = self.get_mac_address(target) mac_address = self.get_mac_address(target)
if hostname: if hostname:
self.log_message(f"Hostname: {hostname}") self.log_message(f"Hostname: {hostname}")
if mac_address: if mac_address:
@ -1113,10 +1137,10 @@ class IPChangerApp:
self.show_error("Start IP must be lower than or equal to End IP") self.show_error("Start IP must be lower than or equal to End IP")
return 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(): for item in self.scan_results_tree.get_children():
self.scan_results_tree.delete(item) self.scan_results_tree.delete(item)
self.scan_results = [] self.scan_results = []
# Calculate total IPs to scan for progress bar # Calculate total IPs to scan for progress bar
@ -1124,6 +1148,9 @@ class IPChangerApp:
self.scan_progress_var.set(0) self.scan_progress_var.set(0)
self.scan_progress["maximum"] = ip_range self.scan_progress["maximum"] = ip_range
# Update nodes to scan count
self.nodes_to_scan.set(str(ip_range))
self.log_message( self.log_message(
f"Starting scan from {start_ip} to {end_ip} ({ip_range} addresses)..." 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)) self.scan_queue.put(ipaddress.IPv4Address(ip_int))
# Start worker threads for parallel scanning # 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): for i in range(max_threads):
thread = threading.Thread(target=self._scan_worker, daemon=True) thread = threading.Thread(target=self._scan_worker, daemon=True)
thread.start() thread.start()
@ -1215,11 +1244,10 @@ class IPChangerApp:
ip_str = str(ip_address) ip_str = str(ip_address)
self.log_message(f"Host discovered: {ip_str}") self.log_message(f"Host discovered: {ip_str}")
self.scan_results.append(ip_str) self.scan_results.append(ip_str)
# Add to results tree with placeholder values # Add to results tree with placeholder values
self.master.after( self.master.after(
0, 0, lambda ip=ip_str: self.add_scan_result(ip, "", "")
lambda ip=ip_str: self.add_scan_result(ip, "", "")
) )
# Update progress # Update progress
@ -1237,54 +1265,55 @@ class IPChangerApp:
if not self.scan_results: if not self.scan_results:
self.show_info("No hosts discovered yet. Run a scan first.") self.show_info("No hosts discovered yet. Run a scan first.")
return return
# Start the information gathering in a separate thread # Start the information gathering in a separate thread
threading.Thread( threading.Thread(target=self._execute_host_gathering, daemon=True).start()
target=self._execute_host_gathering,
daemon=True
).start()
def _execute_host_gathering(self): def _execute_host_gathering(self):
"""Perform the actual host information gathering""" """Perform the actual host information gathering"""
try: 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 # Reset progress bar for this operation
total_hosts = len(self.scan_results) total_hosts = len(self.scan_results)
self.scan_progress_var.set(0) self.scan_progress_var.set(0)
self.scan_progress["maximum"] = total_hosts self.scan_progress["maximum"] = total_hosts
# Get information for each host # Get information for each host
for i, ip in enumerate(self.scan_results): for i, ip in enumerate(self.scan_results):
if self.scan_stop_event.is_set(): if self.scan_stop_event.is_set():
self.log_message("Host information gathering stopped.") self.log_message("Host information gathering stopped.")
break 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 # Get hostname and MAC
hostname = self.get_hostname(ip) hostname = self.get_hostname(ip)
mac_address = self.get_mac_address(ip) mac_address = self.get_mac_address(ip)
# Log what we found # Log what we found
if hostname: if hostname:
self.log_message(f" Hostname: {hostname}") self.log_message(f" Hostname: {hostname}")
else: else:
self.log_message(f" Hostname: Not resolved") self.log_message(f" Hostname: Not resolved")
if mac_address: if mac_address:
self.log_message(f" MAC Address: {mac_address}") self.log_message(f" MAC Address: {mac_address}")
else: else:
self.log_message(f" MAC Address: Not found") self.log_message(f" MAC Address: Not found")
# Update the tree # Update the tree
self.update_host_in_tree(ip, hostname, mac_address) self.update_host_in_tree(ip, hostname, mac_address)
# Update progress # Update progress
self.scan_progress_var.set(i + 1) self.scan_progress_var.set(i + 1)
self.log_message("Host information gathering completed.") self.log_message("Host information gathering completed.")
except Exception as e: except Exception as e:
self.log_message(f"Error gathering host information: {str(e)}") self.log_message(f"Error gathering host information: {str(e)}")
@ -1293,12 +1322,14 @@ class IPChangerApp:
try: try:
# Find the item with this IP # Find the item with this IP
for item_id in self.scan_results_tree.get_children(): 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: if values and values[0] == ip:
# Update the values # Update the values
hostname_str = hostname if hostname else "Not resolved" hostname_str = hostname if hostname else "Not resolved"
mac_str = mac if mac else "Not found" 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 break
except Exception as e: except Exception as e:
self.log_message(f"Error updating host in treeview: {str(e)}") self.log_message(f"Error updating host in treeview: {str(e)}")
@ -1309,7 +1340,7 @@ class IPChangerApp:
# Insert the item with all values, even if some are empty # Insert the item with all values, even if some are empty
hostname = hostname if hostname else "Not resolved" hostname = hostname if hostname else "Not resolved"
mac = mac if mac else "Not found" mac = mac if mac else "Not found"
self.scan_results_tree.insert("", "end", values=(ip, hostname, mac)) self.scan_results_tree.insert("", "end", values=(ip, hostname, mac))
except Exception as e: except Exception as e:
self.log_message(f"Error adding scan result to UI: {str(e)}") self.log_message(f"Error adding scan result to UI: {str(e)}")
@ -1602,6 +1633,9 @@ class IPChangerApp:
mask_bits = bin(int(mask_obj))[2:].zfill(32) mask_bits = bin(int(mask_obj))[2:].zfill(32)
network_bits = mask_bits.count("1") network_bits = mask_bits.count("1")
# Update the scan CIDR field
self.scan_cidr_bits.set(str(network_bits))
# Create network object # Create network object
network = ipaddress.IPv4Network( network = ipaddress.IPv4Network(
f"{ip_address}/{network_bits}", strict=False f"{ip_address}/{network_bits}", strict=False
@ -1621,11 +1655,53 @@ class IPChangerApp:
self.scan_start_ip.set(str(start_ip)) self.scan_start_ip.set(str(start_ip))
self.scan_end_ip.set(str(end_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: except Exception as e:
self.log_message(f"Error calculating IP range: {str(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): def get_hostname(self, ip_address):
"""Try to resolve hostname for an IP address with better error handling""" """Try to resolve hostname for an IP address with better error handling"""
try: try:
@ -1642,9 +1718,11 @@ class IPChangerApp:
self.log_message(f"Timeout resolving hostname for {ip_address}") self.log_message(f"Timeout resolving hostname for {ip_address}")
return "" return ""
except Exception as e: 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 "" return ""
def get_mac_address(self, ip_address): def get_mac_address(self, ip_address):
"""Get MAC address for an IP using ARP on Windows with improved parsing""" """Get MAC address for an IP using ARP on Windows with improved parsing"""
try: try:
@ -1654,39 +1732,49 @@ class IPChangerApp:
shell=True, shell=True,
capture_output=True, capture_output=True,
text=True, text=True,
timeout=2 timeout=2,
) )
if result.returncode == 0 and result.stdout: if result.returncode == 0 and result.stdout:
# Log the raw output for debugging # 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 # Parse the output to find the MAC address
# First try the typical format with hyphens or colons # 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(
result.stdout, 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})",
re.IGNORECASE) result.stdout,
re.IGNORECASE,
)
if mac_match: if mac_match:
return mac_match.group(0) return mac_match.group(0)
# Try an alternative format with spaces (Windows format) # 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(
result.stdout, 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})",
re.IGNORECASE) result.stdout,
re.IGNORECASE,
)
if mac_match: if mac_match:
return mac_match.group(0) return mac_match.group(0)
# Try yet another approach - look for any string of hex digits with separators # 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: for line in lines:
if ip_address in line: if ip_address in line:
parts = line.split() parts = line.split()
# Usually the MAC address is the second column in the output # Usually the MAC address is the second column in the output
if len(parts) >= 2: if len(parts) >= 2:
# Check if the second part looks like a MAC address # 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] return parts[1]
self.log_message(f"No MAC address found for {ip_address}") self.log_message(f"No MAC address found for {ip_address}")
return "" return ""
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:

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"}