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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
import subprocess import re import binascii import math def capture_wifi_packets(interface, duration): """Captura paquetes Wi-Fi usando TShark durante un tiempo específico.""" try: command = [ '/Applications/Wireshark.app/Contents/MacOS/tshark', '-I', '-i', interface, '-a', f'duration:{duration}', '-T', 'fields', '-e', 'wlan.sa', '-e', 'wlan.bssid', '-e', 'wlan.fc.type_subtype', '-e', 'wlan_radio.signal_dbm', '-e', 'wlan.ssid', '-E', 'separator=,' ] print("Ejecutando comando:", ' '.join(command)) result = subprocess.check_output(command, universal_newlines=True, timeout=duration + 5) # Timeout para evitar bloqueos return result except subprocess.CalledProcessError as e: print(f"Error ejecutando tshark: {e}") return None except subprocess.TimeoutExpired: print("Tiempo de captura agotado.") return None def hex_to_ascii(hex_str): """Convierte una cadena hexadecimal en texto ASCII.""" try: ascii_str = bytes.fromhex(hex_str).decode('ascii') return ascii_str except ValueError: return None def calculate_distance(signal_dBm, reference_signal_dBm=-30, decay_exponent=2): """ Calcula la distancia estimada en metros basándose en la potencia de la señal en dBm. """ try: distance = 10 ** ((signal_dBm - reference_signal_dBm) / (10 * decay_exponent)) return distance except Exception as e: print(f"Error calculando la distancia: {e}") return float('inf') # Si no se puede calcular, retorna infinito def extract_aps_and_devices(packet_data): """Extrae direcciones MAC de APs, dispositivos Wi-Fi, y relaciona asociaciones, incluyendo potencia de señal y distancia.""" aps = {} devices = {} associations = {} # Almacena la relación entre APs y dispositivos conectados signal_strengths = {} # Almacena la potencia de señal y distancia mac_re = re.compile(r'(?:\S{2}:){5}\S{2}') assoc_request_re = re.compile(r'Association Request') for line in packet_data.splitlines(): fields = line.split(',') if len(fields) >= 5: sa = fields[0].strip() # Dirección MAC del dispositivo bssid = fields[1].strip() # Dirección MAC del AP fc_type_subtype = fields[2].strip() # Tipo de paquete signal_dbm = fields[3].strip() # Potencia de señal en dBm ssid_hex = fields[4].strip() # SSID en hexadecimal ssid = hex_to_ascii(ssid_hex) # Convertir SSID hexadecimal a texto # Verificar si es un tipo de paquete de interés if fc_type_subtype.startswith('0x00') or fc_type_subtype.startswith('0x01'): # Association Request if bssid: if bssid not in associations: associations[bssid] = set() if sa: associations[bssid].add(sa) # Detectar APs y dispositivos if bssid: aps[bssid] = ssid if signal_dbm: signal_strengths[bssid] = int(signal_dbm) if sa and sa not in aps: devices[sa] = ssid # Calcular distancias distance_estimates = {} signal_strengths_formatted = {} # Para almacenar la potencia de señal for ap, signal_dbm in signal_strengths.items(): try: distance = calculate_distance(signal_dbm) distance_estimates[ap] = distance signal_strengths_formatted[ap] = signal_dbm except Exception as e: print(f"Error calculando la distancia para AP {ap}: {e}") return aps, devices, associations, distance_estimates, signal_strengths_formatted def print_table(associations, aps, devices, distance_estimates, signal_strengths): """Imprime una tabla consolidada con toda la información.""" print("\nRelación entre APs y dispositivos conectados:") print(f"{'Punto de Acceso (AP)':<30} {'Dispositivos Conectados':<60} {'Distancia Estimada (m)':<25} {'Potencia de Señal (dBm)':<25}") print("="*140) for ap, connected_devices in associations.items(): ap_ssid = aps.get(ap, 'Desconocido') ap_distance = distance_estimates.get(ap, None) ap_signal = signal_strengths.get(ap, None) # Asegurarse de que ap_distance y ap_signal sean valores numéricos o cadenas 'Desconocido' if ap_distance is None: ap_distance = 'Desconocido' else: ap_distance = f'{ap_distance:.2f}' if ap_signal is None: ap_signal = 'Desconocido' else: ap_signal = f'{ap_signal} dBm' # Crear una lista de dispositivos conectados en líneas separadas devices_list = [f"{devices.get(device, 'Desconocido')} ({device})" for device in connected_devices] # Imprimir el AP print(f"{ap_ssid:<30}") # Imprimir cada dispositivo conectado en una línea separada for device_line in devices_list: print(f"{'':<30} {device_line:<60}") # Imprimir la distancia estimada y la potencia de señal print(f"{'':<30} {ap_distance:<25} {ap_signal:<25}") # Línea de separación print("-" * 140) def print_macs(aps, devices): """Imprime un listado de todas las direcciones MAC encontradas.""" all_macs = set(aps.keys()).union(devices.keys()) print("\nListado de direcciones MAC encontradas:") for mac in sorted(all_macs): print(mac) def main(): interface = 'en0' # Cambia a tu interfaz Wi-Fi si es necesario duration = 20 # Tiempo en segundos para capturar paquetes print("Escaneando dispositivos Wi-Fi...\n") packet_data = capture_wifi_packets(interface, duration) if packet_data: print("Datos capturados:\n", packet_data[:1000]) # Mostrar los primeros 1000 caracteres para depuración aps, devices, associations, distance_estimates, signal_strengths = extract_aps_and_devices(packet_data) if aps: print("Puntos de Acceso Wi-Fi encontrados:") for ap, ssid in aps.items(): print(f"AP: {ap} - SSID: {ssid if ssid else 'Desconocido'}") else: print("No se encontraron puntos de acceso Wi-Fi.") if devices: print("\nDispositivos Wi-Fi encontrados (no APs):") for device, ssid in devices.items(): print(f"Dispositivo: {device} - SSID: {ssid if ssid else 'Desconocido'}") else: print("No se encontraron dispositivos Wi-Fi.") if associations: print_table(associations, aps, devices, distance_estimates, signal_strengths) else: print("No se encontraron asociaciones entre APs y dispositivos.") if distance_estimates: print("\nEstimación de distancias de los APs:") for ap, distance in distance_estimates.items(): print(f"AP: {ap} - SSID: {aps.get(ap, 'Desconocido')} -> Distancia estimada: {distance:.2f} metros") else: print("No se pudo estimar la distancia de los APs.") print_macs(aps, devices) else: print("No se pudo capturar ningún paquete.") if __name__ == '__main__': main() |