-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDetector.py
More file actions
198 lines (161 loc) · 6.04 KB
/
Copy pathDetector.py
File metadata and controls
198 lines (161 loc) · 6.04 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
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"""
Módulo de detección y utilidades de red.
Este módulo proporciona funciones para detectar interfaces de red activas,
obtener direcciones MAC, y realizar conversiones entre formatos de direcciones.
También incluye utilidades para detectar entornos containerizados.
Funcionalidades principales:
- Detección automática de interfaces Wi-Fi y Ethernet activas
- Obtención de direcciones MAC usando ioctl
- Conversión entre formatos string y bytes para direcciones MAC
- Detección de entornos Docker
"""
import os
import socket
import fcntl
import struct
import threading
import time
import tempfile
import shutil
# Funcion para detectar interfaces de wifi o ethernet activas
def get_active_network_interfaces():
"""
Detecta y devuelve las interfaces de red activas (Wi-Fi y Ethernet).
Examina las interfaces en /sys/class/net y filtra solo aquellas que:
- Tienen estado operativo 'up'
- Tienen carrier activo (si aplica)
- Son interfaces físicas (no virtuales, excepto en contenedores)
- Son de tipo Wi-Fi o Ethernet
Returns:
list: Lista de nombres de interfaces activas
"""
"""
Devuelve un dict con las interfaces activas clasificadas:
{
'wifi': ['wlp2s0', ...],
'ethernet': ['enp3s0', ...]
}
Solo considera interfaces físicas y activas (operstate=up y, si existe, carrier=1).
"""
base = "/sys/class/net"
result = []
is_container = running_in_docker()
if not os.path.isdir(base):
return result
for name in sorted(os.listdir(base)):
if name == "lo":
continue
iface_path = os.path.join(base, name)
if not os.path.isdir(iface_path):
continue
if not is_container:
# Saltar interfaces que no tienen dispositivo físico (virtuales)
if not os.path.exists(os.path.join(iface_path, "device")):
continue
# Comprobar estado operativo
try:
with open(os.path.join(iface_path, "operstate")) as f:
oper = f.read().strip()
except FileNotFoundError:
continue
if oper != "up":
continue
# Si existe 'carrier', requerir que sea 1 (enlace activo)
carrier_path = os.path.join(iface_path, "carrier")
if os.path.exists(carrier_path):
try:
with open(carrier_path) as f:
if f.read().strip() != "1":
continue
except OSError:
continue
# Determinar si es Wi‑Fi
is_wifi = os.path.isdir(os.path.join(iface_path, "wireless"))
uevent_path = os.path.join(iface_path, "uevent")
if not is_wifi and os.path.exists(uevent_path):
try:
with open(uevent_path) as f:
uev = f.read()
if "DEVTYPE=wlan" in uev:
is_wifi = True
except OSError:
pass
if is_wifi:
result.append(name)
continue
# Determinar si es Ethernet (ARPHRD_ETHER => type == 1)
try:
with open(os.path.join(iface_path, "type")) as f:
if f.read().strip() == "1":
result.append(name)
except OSError:
pass
return result
# Funcion para obtener la MAC de una interfaz dada
def get_mac_address(interface: str) -> str:
"""
Obtiene la dirección MAC de una interfaz de red específica.
Utiliza el comando SIOCGIFHWADDR a través de ioctl para obtener
la dirección MAC a nivel de enlace de datos.
Args:
interface (str): Nombre de la interfaz de red (ej: 'eth0', 'wlan0')
Returns:
str: Dirección MAC en formato 'aa:bb:cc:dd:ee:ff'
Raises:
ValueError: Si el nombre de interfaz es inválido
FileNotFoundError: Si no se puede obtener la MAC de la interfaz
"""
"""
Devuelve la MAC de la interfaz usando solo capa de enlace (SIOCGIFHWADDR).
Formato 'aa:bb:cc:dd:ee:ff'.
"""
if not interface or "/" in interface:
raise ValueError("Nombre de interfaz inválido")
SIOCGIFHWADDR = 0x8927
# AF_PACKET asegura operar a nivel de enlace
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003)) # ETH_P_ALL
try:
ifreq = struct.pack("256s", interface.encode("utf-8")[:15])
res = fcntl.ioctl(s.fileno(), SIOCGIFHWADDR, ifreq)
hw = res[18:24] # ifr_hwaddr.sa_data
mac = ":".join(f"{b:02x}" for b in hw)
if mac == "00:00:00:00:00:00":
raise FileNotFoundError(f"No se pudo obtener la MAC de '{interface}'")
return mac
finally:
s.close()
# Convierte MAC de string a bytes
def mac_to_bytes(mac: str) -> bytes:
"""
Convierte una dirección MAC de formato string a bytes.
Acepta formatos con o sin separadores de dos puntos.
Args:
mac (str): Dirección MAC en formato 'aa:bb:cc:dd:ee:ff' o 'aabbccddeeff'
Returns:
bytes: Dirección MAC en formato binario (6 bytes)
"""
"""Convierte 'aa:bb:cc:dd:ee:ff' o 'aabbccddeeff' a b'\xaa\xbb\xcc\xdd\xee\xff'"""
mac = mac.replace(":", "")
aux = bytes(int(mac[i:i+2], 16) for i in range(0, 12, 2))
return aux
# Convierte MAC de bytes a string
def mac_bytes_to_str(mac: bytes) -> str:
"""
Convierte una dirección MAC de formato bytes a string.
Args:
mac (bytes): Dirección MAC en formato binario (6 bytes)
Returns:
str: Dirección MAC en formato 'aa:bb:cc:dd:ee:ff'
"""
aux = ':'.join(f"{b:02x}" for b in mac)
return aux
# Detecta si el programa se está ejecutando dentro de un contenedor Docker
def running_in_docker() -> bool:
"""
Detecta si el programa se está ejecutando dentro de un contenedor Docker.
Verifica la existencia del archivo /.dockerenv que Docker crea automáticamente
en todos los contenedores.
Returns:
bool: True si está ejecutándose en Docker, False en caso contrario
"""
return os.path.exists("/.dockerenv")