moriarty-project 0.1.10__py3-none-any.whl → 0.1.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,810 @@
1
+ """
2
+ Utility functions for WifiPPLER.
3
+
4
+ This module provides various utility functions used throughout the WifiPPLER
5
+ package, including network interface management, dependency checking, and
6
+ other helper functions.
7
+ """
8
+ import os
9
+ import re
10
+ import sys
11
+ import time
12
+ import logging
13
+ import subprocess
14
+ import shutil
15
+ import fcntl
16
+ import struct
17
+ import array
18
+ import socket
19
+ import platform
20
+ from typing import List, Dict, Tuple, Optional, Union, Any, Callable, Set
21
+ from dataclasses import asdict
22
+
23
+ # Configure logging
24
+ logging.basicConfig(level=logging.INFO)
25
+ logger = logging.getLogger(__name__)
26
+
27
+ # Constants
28
+ WIRELESS_EXT = 0x8B01 # SIOCGIWNAME
29
+ SIOCGIFHWADDR = 0x8927 # Get hardware address
30
+ SIOCGIFADDR = 0x8915 # Get IP address
31
+ SIOCGIFNETMASK = 0x891B # Get netmask
32
+ SIOCGIFBRDADDR = 0x8919 # Get broadcast address
33
+ SIOCGIFMTU = 0x8921 # Get MTU
34
+ SIOCGIFINDEX = 0x8933 # Get interface index
35
+ SIOCGIFNAME = 0x8910 # Get interface name
36
+ SIOCGIFFLAGS = 0x8913 # Get interface flags
37
+ SIOCSIFFLAGS = 0x8914 # Set interface flags
38
+
39
+ # Platform-specific constants
40
+ IS_LINUX = platform.system() == 'Linux'
41
+ IS_MAC = platform.system() == 'Darwin'
42
+ IS_WINDOWS = platform.system() == 'Windows'
43
+
44
+ # Network interface flags
45
+ IFF_UP = 0x1
46
+ IFF_BROADCAST = 0x2
47
+ IFF_DEBUG = 0x4
48
+ IFF_LOOPBACK = 0x8
49
+ IFF_POINTOPOINT = 0x10
50
+ IFF_NOTRAILERS = 0x20
51
+ IFF_RUNNING = 0x40
52
+ IFF_NOARP = 0x80
53
+ IFF_PROMISC = 0x100
54
+ IFF_ALLMULTI = 0x200
55
+ IFF_MASTER = 0x400
56
+ IFF_SLAVE = 0x800
57
+ IFF_MULTICAST = 0x1000
58
+ IFF_PORTSEL = 0x2000
59
+ IFF_AUTOMEDIA = 0x4000
60
+ IFF_DYNAMIC = 0x8000
61
+
62
+ def is_root() -> bool:
63
+ """
64
+ Check if the script is running with root privileges.
65
+
66
+ Returns:
67
+ bool: True if running as root, False otherwise
68
+ """
69
+ return os.geteuid() == 0
70
+
71
+ def check_dependencies() -> List[str]:
72
+ """
73
+ Check for required system dependencies.
74
+
75
+ Returns:
76
+ List[str]: List of missing dependencies
77
+ """
78
+ required = [
79
+ 'iwconfig', 'iw', 'ifconfig', 'aircrack-ng', 'airodump-ng',
80
+ 'aireplay-ng', 'airmon-ng', 'wash', 'reaver', 'bully', 'hcxdumptool',
81
+ 'hcxpcapngtool', 'hashcat', 'tshark', 'macchanger', 'rfkill'
82
+ ]
83
+
84
+ missing = []
85
+ for cmd in required:
86
+ if not command_exists(cmd):
87
+ missing.append(cmd)
88
+
89
+ return missing
90
+
91
+ def command_exists(cmd: str) -> bool:
92
+ """
93
+ Check if a command exists in the system PATH.
94
+
95
+ Args:
96
+ cmd: Command to check
97
+
98
+ Returns:
99
+ bool: True if command exists, False otherwise
100
+ """
101
+ return shutil.which(cmd) is not None
102
+
103
+ def get_network_interfaces() -> List[Dict[str, Any]]:
104
+ """
105
+ Get a list of all network interfaces.
106
+
107
+ Returns:
108
+ List[Dict[str, Any]]: List of interfaces with their properties
109
+ """
110
+ interfaces = []
111
+
112
+ if IS_LINUX:
113
+ # Linux implementation using /sys/class/net
114
+ net_path = '/sys/class/net'
115
+ if os.path.exists(net_path):
116
+ for ifname in os.listdir(net_path):
117
+ if ifname == 'lo':
118
+ continue
119
+
120
+ iface = {
121
+ 'name': ifname,
122
+ 'wireless': os.path.exists(f"{net_path}/{ifname}/wireless"),
123
+ 'state': 'down',
124
+ 'mac': get_interface_mac(ifname),
125
+ 'ip': get_interface_ip(ifname),
126
+ 'netmask': get_interface_netmask(ifname),
127
+ 'broadcast': get_interface_broadcast(ifname),
128
+ 'mtu': get_interface_mtu(ifname)
129
+ }
130
+
131
+ # Check if interface is up
132
+ try:
133
+ with open(f"{net_path}/{ifname}/operstate", 'r') as f:
134
+ state = f.read().strip()
135
+ iface['state'] = state if state in ['up', 'down'] else 'unknown'
136
+ except:
137
+ pass
138
+
139
+ interfaces.append(iface)
140
+
141
+ elif IS_MAC:
142
+ # macOS implementation using ifconfig
143
+ try:
144
+ result = subprocess.run(['ifconfig', '-l'], capture_output=True, text=True)
145
+ if result.returncode == 0:
146
+ for ifname in result.stdout.strip().split():
147
+ if ifname == 'lo0':
148
+ continue
149
+
150
+ iface = {
151
+ 'name': ifname,
152
+ 'wireless': ifname.startswith(('en', 'wl')), # Approximate
153
+ 'state': 'unknown',
154
+ 'mac': get_interface_mac(ifname),
155
+ 'ip': get_interface_ip(ifname),
156
+ 'netmask': get_interface_netmask(ifname),
157
+ 'broadcast': get_interface_broadcast(ifname),
158
+ 'mtu': get_interface_mtu(ifname)
159
+ }
160
+
161
+ # Check if interface is up
162
+ result = subprocess.run(['ifconfig', ifname], capture_output=True, text=True)
163
+ if 'status: active' in result.stdout or 'UP' in result.stdout:
164
+ iface['state'] = 'up'
165
+ else:
166
+ iface['state'] = 'down'
167
+
168
+ interfaces.append(iface)
169
+ except Exception as e:
170
+ logger.error(f"Error getting network interfaces: {e}")
171
+
172
+ return interfaces
173
+
174
+ def get_wireless_interfaces() -> List[Dict[str, Any]]:
175
+ """
176
+ Get a list of wireless network interfaces.
177
+
178
+ Returns:
179
+ List[Dict[str, Any]]: List of wireless interfaces with their properties
180
+ """
181
+ return [iface for iface in get_network_interfaces()
182
+ if iface.get('wireless', False)]
183
+
184
+ def get_interface_mac(interface: str) -> Optional[str]:
185
+ """
186
+ Get the MAC address of a network interface.
187
+
188
+ Args:
189
+ interface: Interface name
190
+
191
+ Returns:
192
+ Optional[str]: MAC address or None if not found
193
+ """
194
+ try:
195
+ if IS_LINUX or IS_MAC:
196
+ with open(f"/sys/class/net/{interface}/address") as f:
197
+ return f.read().strip()
198
+ except:
199
+ pass
200
+
201
+ try:
202
+ if IS_LINUX:
203
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
204
+ info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', interface[:15].encode()))
205
+ return ':'.join(f'{b:02x}' for b in info[18:24])
206
+ elif IS_MAC:
207
+ result = subprocess.run(['ifconfig', interface], capture_output=True, text=True)
208
+ match = re.search(r'([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})', result.stdout)
209
+ if match:
210
+ return match.group(0).lower()
211
+ except:
212
+ pass
213
+
214
+ return None
215
+
216
+ def get_interface_ip(interface: str) -> Optional[str]:
217
+ """
218
+ Get the IP address of a network interface.
219
+
220
+ Args:
221
+ interface: Interface name
222
+
223
+ Returns:
224
+ Optional[str]: IP address or None if not found
225
+ """
226
+ try:
227
+ if IS_LINUX or IS_MAC:
228
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
229
+ try:
230
+ # Works for both IPv4 and IPv6
231
+ return socket.inet_ntoa(fcntl.ioctl(
232
+ s.fileno(),
233
+ 0x8915, # SIOCGIFADDR
234
+ struct.pack('256s', interface[:15].encode())
235
+ )[20:24])
236
+ except:
237
+ pass
238
+ except:
239
+ pass
240
+
241
+ try:
242
+ if IS_MAC:
243
+ result = subprocess.run(['ifconfig', interface, 'inet'], capture_output=True, text=True)
244
+ match = re.search(r'inet (\d+\.\d+\.\d+\.\d+)', result.stdout)
245
+ if match:
246
+ return match.group(1)
247
+ except:
248
+ pass
249
+
250
+ return None
251
+
252
+ def get_interface_netmask(interface: str) -> Optional[str]:
253
+ """
254
+ Get the netmask of a network interface.
255
+
256
+ Args:
257
+ interface: Interface name
258
+
259
+ Returns:
260
+ Optional[str]: Netmask or None if not found
261
+ """
262
+ try:
263
+ if IS_LINUX or IS_MAC:
264
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
265
+ try:
266
+ netmask = socket.inet_ntoa(fcntl.ioctl(
267
+ s.fileno(),
268
+ 0x891B, # SIOCGIFNETMASK
269
+ struct.pack('256s', interface[:15].encode())
270
+ )[20:24])
271
+ return netmask
272
+ except:
273
+ pass
274
+ except:
275
+ pass
276
+
277
+ try:
278
+ if IS_MAC:
279
+ result = subprocess.run(['ifconfig', interface, 'inet'], capture_output=True, text=True)
280
+ match = re.search(r'netmask (0x[0-9a-fA-F]+)', result.stdout)
281
+ if match:
282
+ # Convert hex netmask to dotted decimal
283
+ netmask_hex = match.group(1)
284
+ netmask_int = int(netmask_hex, 16)
285
+ return socket.inet_ntoa(struct.pack('>I', netmask_int))
286
+ except:
287
+ pass
288
+
289
+ return None
290
+
291
+ def get_interface_broadcast(interface: str) -> Optional[str]:
292
+ """
293
+ Get the broadcast address of a network interface.
294
+
295
+ Args:
296
+ interface: Interface name
297
+
298
+ Returns:
299
+ Optional[str]: Broadcast address or None if not found
300
+ """
301
+ try:
302
+ if IS_LINUX or IS_MAC:
303
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
304
+ try:
305
+ broadcast = socket.inet_ntoa(fcntl.ioctl(
306
+ s.fileno(),
307
+ 0x8919, # SIOCGIFBRDADDR
308
+ struct.pack('256s', interface[:15].encode())
309
+ )[20:24])
310
+ return broadcast
311
+ except:
312
+ pass
313
+ except:
314
+ pass
315
+
316
+ try:
317
+ if IS_MAC:
318
+ result = subprocess.run(['ifconfig', interface, 'inet'], capture_output=True, text=True)
319
+ match = re.search(r'broadcast (\d+\.\d+\.\d+\.\d+)', result.stdout)
320
+ if match:
321
+ return match.group(1)
322
+ except:
323
+ pass
324
+
325
+ return None
326
+
327
+ def get_interface_mtu(interface: str) -> Optional[int]:
328
+ """
329
+ Get the MTU of a network interface.
330
+
331
+ Args:
332
+ interface: Interface name
333
+
334
+ Returns:
335
+ Optional[int]: MTU or None if not found
336
+ """
337
+ try:
338
+ if IS_LINUX:
339
+ with open(f"/sys/class/net/{interface}/mtu", 'r') as f:
340
+ return int(f.read().strip())
341
+ elif IS_MAC:
342
+ result = subprocess.run(['ifconfig', interface], capture_output=True, text=True)
343
+ match = re.search(r'mtu (\d+)', result.stdout)
344
+ if match:
345
+ return int(match.group(1))
346
+ except:
347
+ pass
348
+
349
+ return None
350
+
351
+ def set_monitor_mode(interface: str, channel: int = None) -> bool:
352
+ """
353
+ Set a wireless interface to monitor mode.
354
+
355
+ Args:
356
+ interface: Interface name
357
+ channel: Optional channel to set
358
+
359
+ Returns:
360
+ bool: True if successful, False otherwise
361
+ """
362
+ if not is_root():
363
+ logger.error("Root privileges required to set monitor mode")
364
+ return False
365
+
366
+ try:
367
+ # Bring interface down
368
+ subprocess.run(['ip', 'link', 'set', interface, 'down'], check=True)
369
+
370
+ # Set monitor mode
371
+ subprocess.run(['iw', 'dev', interface, 'set', 'monitor', 'none'], check=True)
372
+
373
+ # Bring interface up
374
+ subprocess.run(['ip', 'link', 'set', interface, 'up'], check=True)
375
+
376
+ # Set channel if specified
377
+ if channel is not None:
378
+ subprocess.run(['iw', 'dev', interface, 'set', 'channel', str(channel)], check=True)
379
+
380
+ return True
381
+ except subprocess.CalledProcessError as e:
382
+ logger.error(f"Failed to set monitor mode: {e}")
383
+ return False
384
+
385
+ def set_managed_mode(interface: str) -> bool:
386
+ """
387
+ Set a wireless interface to managed mode.
388
+
389
+ Args:
390
+ interface: Interface name
391
+
392
+ Returns:
393
+ bool: True if successful, False otherwise
394
+ """
395
+ if not is_root():
396
+ logger.error("Root privileges required to set managed mode")
397
+ return False
398
+
399
+ try:
400
+ # Bring interface down
401
+ subprocess.run(['ip', 'link', 'set', interface, 'down'], check=True)
402
+
403
+ # Set managed mode
404
+ subprocess.run(['iw', 'dev', interface, 'set', 'type', 'managed'], check=True)
405
+
406
+ # Bring interface up
407
+ subprocess.run(['ip', 'link', 'set', interface, 'up'], check=True)
408
+
409
+ # Restart network manager
410
+ if command_exists('systemctl'):
411
+ subprocess.run(['systemctl', 'restart', 'NetworkManager'], check=False)
412
+ elif command_exists('service'):
413
+ subprocess.run(['service', 'network-manager', 'restart'], check=False)
414
+
415
+ return True
416
+ except subprocess.CalledProcessError as e:
417
+ logger.error(f"Failed to set managed mode: {e}")
418
+ return False
419
+
420
+ def get_monitor_interfaces() -> List[str]:
421
+ """
422
+ Get a list of interfaces in monitor mode.
423
+
424
+ Returns:
425
+ List[str]: List of interface names in monitor mode
426
+ """
427
+ interfaces = []
428
+
429
+ try:
430
+ if IS_LINUX:
431
+ # List all interfaces
432
+ for iface in os.listdir('/sys/class/net'):
433
+ if iface.startswith(('mon', 'wlan', 'wlp', 'wlo')):
434
+ # Check if in monitor mode
435
+ proc = subprocess.Popen(['iwconfig', iface],
436
+ stdout=subprocess.PIPE,
437
+ stderr=subprocess.PIPE)
438
+ out, _ = proc.communicate()
439
+
440
+ if b'Mode:Monitor' in out:
441
+ interfaces.append(iface)
442
+ elif IS_MAC:
443
+ # On macOS, interfaces in monitor mode typically start with 'mon'
444
+ result = subprocess.run(['ifconfig', '-l'], capture_output=True, text=True)
445
+ interfaces = [iface for iface in result.stdout.strip().split()
446
+ if iface.startswith('en') and 'monitor' in
447
+ subprocess.run(['ifconfig', iface], capture_output=True, text=True).stdout]
448
+ except Exception as e:
449
+ logger.error(f"Error getting monitor interfaces: {e}")
450
+
451
+ return interfaces
452
+
453
+ def get_interface_signal(interface: str) -> Optional[int]:
454
+ """
455
+ Get the signal strength of a wireless interface in dBm.
456
+
457
+ Args:
458
+ interface: Interface name
459
+
460
+ Returns:
461
+ Optional[int]: Signal strength in dBm or None if not available
462
+ """
463
+ try:
464
+ if IS_LINUX or IS_MAC:
465
+ proc = subprocess.Popen(['iwconfig', interface],
466
+ stdout=subprocess.PIPE,
467
+ stderr=subprocess.PIPE)
468
+ out, _ = proc.communicate()
469
+
470
+ # Look for signal level in the format "Signal level=-XX dBm"
471
+ match = re.search(r'Signal level=(-\d+)\s*dBm', out.decode('utf-8', 'ignore'))
472
+ if match:
473
+ return int(match.group(1))
474
+ except:
475
+ pass
476
+
477
+ return None
478
+
479
+ def get_interface_ssid(interface: str) -> Optional[str]:
480
+ """
481
+ Get the SSID that a wireless interface is connected to.
482
+
483
+ Args:
484
+ interface: Interface name
485
+
486
+ Returns:
487
+ Optional[str]: SSID or None if not connected
488
+ """
489
+ try:
490
+ if IS_LINUX:
491
+ proc = subprocess.Popen(['iwconfig', interface],
492
+ stdout=subprocess.PIPE,
493
+ stderr=subprocess.PIPE)
494
+ out, _ = proc.communicate()
495
+
496
+ # Look for ESSID in the format "ESSID:"MyWiFi""
497
+ match = re.search(r'ESSID:"([^"]+)"', out.decode('utf-8', 'ignore'))
498
+ if match and match.group(1) != 'off/any':
499
+ return match.group(1)
500
+ elif IS_MAC:
501
+ result = subprocess.run(['/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport', '-I'],
502
+ capture_output=True, text=True)
503
+ match = re.search(r' SSID: (.+)', result.stdout)
504
+ if match:
505
+ return match.group(1).strip()
506
+ except:
507
+ pass
508
+
509
+ return None
510
+
511
+ def get_interface_channel(interface: str) -> Optional[int]:
512
+ """
513
+ Get the current channel of a wireless interface.
514
+
515
+ Args:
516
+ interface: Interface name
517
+
518
+ Returns:
519
+ Optional[int]: Channel number or None if not available
520
+ """
521
+ try:
522
+ if IS_LINUX or IS_MAC:
523
+ proc = subprocess.Popen(['iwconfig', interface],
524
+ stdout=subprocess.PIPE,
525
+ stderr=subprocess.PIPE)
526
+ out, _ = proc.communicate()
527
+
528
+ # Look for channel in the format "Channel:XX"
529
+ match = re.search(r'Channel:(\d+)', out.decode('utf-8', 'ignore'))
530
+ if match:
531
+ return int(match.group(1))
532
+ except:
533
+ pass
534
+
535
+ return None
536
+
537
+ def get_interface_bitrate(interface: str) -> Optional[float]:
538
+ """
539
+ Get the current bitrate of a wireless interface in Mbps.
540
+
541
+ Args:
542
+ interface: Interface name
543
+
544
+ Returns:
545
+ Optional[float]: Bitrate in Mbps or None if not available
546
+ """
547
+ try:
548
+ if IS_LINUX or IS_MAC:
549
+ proc = subprocess.Popen(['iwconfig', interface],
550
+ stdout=subprocess.PIPE,
551
+ stderr=subprocess.PIPE)
552
+ out, _ = proc.communicate()
553
+
554
+ # Look for bit rate in the format "Bit Rate=XX Mb/s"
555
+ match = re.search(r'Bit Rate[:=](\d+(?:\.\d+)?)\s*Mb/s', out.decode('utf-8', 'ignore'))
556
+ if match:
557
+ return float(match.group(1))
558
+ except:
559
+ pass
560
+
561
+ return None
562
+
563
+ def randomize_mac(interface: str) -> bool:
564
+ """
565
+ Randomize the MAC address of a network interface.
566
+
567
+ Args:
568
+ interface: Interface name
569
+
570
+ Returns:
571
+ bool: True if successful, False otherwise
572
+ """
573
+ if not is_root():
574
+ logger.error("Root privileges required to change MAC address")
575
+ return False
576
+
577
+ try:
578
+ # Generate a random MAC address
579
+ import random
580
+ new_mac = ':'.join(['%02x' % random.randint(0x00, 0xff) for _ in range(6)])
581
+
582
+ # Bring interface down
583
+ subprocess.run(['ip', 'link', 'set', interface, 'down'], check=True)
584
+
585
+ # Set new MAC address
586
+ subprocess.run(['ip', 'link', 'set', 'dev', interface, 'address', new_mac], check=True)
587
+
588
+ # Bring interface up
589
+ subprocess.run(['ip', 'link', 'set', interface, 'up'], check=True)
590
+
591
+ return True
592
+ except subprocess.CalledProcessError as e:
593
+ logger.error(f"Failed to randomize MAC address: {e}")
594
+ return False
595
+
596
+ def run_command(cmd: Union[str, List[str]], capture_output: bool = False,
597
+ check: bool = True, **kwargs) -> subprocess.CompletedProcess:
598
+ """
599
+ Run a shell command with error handling.
600
+
601
+ Args:
602
+ cmd: Command to run (string or list)
603
+ capture_output: Whether to capture stdout/stderr
604
+ check: Whether to raise an exception on non-zero exit code
605
+ **kwargs: Additional arguments to subprocess.run()
606
+
607
+ Returns:
608
+ subprocess.CompletedProcess: Command execution result
609
+ """
610
+ if isinstance(cmd, str):
611
+ cmd = cmd.split()
612
+
613
+ kwargs.setdefault('stdout', subprocess.PIPE if capture_output else None)
614
+ kwargs.setdefault('stderr', subprocess.PIPE if capture_output else None)
615
+ kwargs.setdefault('text', True)
616
+
617
+ try:
618
+ return subprocess.run(cmd, check=check, **kwargs)
619
+ except subprocess.CalledProcessError as e:
620
+ logger.error(f"Command failed with exit code {e.returncode}: {' '.join(cmd)}")
621
+ if capture_output and e.stderr:
622
+ logger.error(f"Error output: {e.stderr.strip()}")
623
+ raise
624
+
625
+ async def run_command_async(cmd: Union[str, List[str]], **kwargs) -> subprocess.CompletedProcess:
626
+ """
627
+ Run a shell command asynchronously.
628
+
629
+ Args:
630
+ cmd: Command to run (string or list)
631
+ **kwargs: Additional arguments to asyncio.create_subprocess_exec()
632
+
633
+ Returns:
634
+ subprocess.CompletedProcess: Command execution result
635
+ """
636
+ if isinstance(cmd, str):
637
+ cmd = cmd.split()
638
+
639
+ process = await asyncio.create_subprocess_exec(
640
+ *cmd,
641
+ stdout=asyncio.subprocess.PIPE,
642
+ stderr=asyncio.subprocess.PIPE,
643
+ **kwargs
644
+ )
645
+
646
+ stdout, stderr = await process.communicate()
647
+
648
+ return subprocess.CompletedProcess(
649
+ args=cmd,
650
+ returncode=process.returncode,
651
+ stdout=stdout.decode() if stdout else '',
652
+ stderr=stderr.decode() if stderr else ''
653
+ )
654
+
655
+ def get_wireless_drivers() -> List[Dict[str, str]]:
656
+ """
657
+ Get a list of wireless drivers and their information.
658
+
659
+ Returns:
660
+ List[Dict[str, str]]: List of driver information
661
+ """
662
+ drivers = []
663
+
664
+ if IS_LINUX:
665
+ try:
666
+ # Check loaded kernel modules
667
+ with open('/proc/modules', 'r') as f:
668
+ for line in f:
669
+ module = line.split()[0]
670
+ if any(x in module.lower() for x in ['wlan', 'wireless', '80211', 'ath', 'rtl', 'rtw', 'mt76']):
671
+ drivers.append({
672
+ 'name': module,
673
+ 'type': 'kernel',
674
+ 'status': 'loaded'
675
+ })
676
+
677
+ # Check loaded kernel modules with modinfo
678
+ for driver in drivers[:]: # Iterate over a copy of the list
679
+ try:
680
+ result = subprocess.run(['modinfo', driver['name']],
681
+ capture_output=True, text=True)
682
+ if result.returncode == 0:
683
+ # Parse modinfo output
684
+ info = {}
685
+ for line in result.stdout.splitlines():
686
+ if ':' in line:
687
+ key, value = line.split(':', 1)
688
+ info[key.strip()] = value.strip()
689
+
690
+ # Update driver info
691
+ driver.update({
692
+ 'description': info.get('description', ''),
693
+ 'version': info.get('version', ''),
694
+ 'author': info.get('author', ''),
695
+ 'license': info.get('license', '')
696
+ })
697
+ except:
698
+ pass
699
+
700
+ # Check for USB wireless devices
701
+ if os.path.exists('/sys/bus/usb/drivers'):
702
+ for driver in os.listdir('/sys/bus/usb/drivers'):
703
+ if any(x in driver.lower() for x in ['wlan', 'wireless', '80211', 'ath', 'rtl', 'rtw']):
704
+ drivers.append({
705
+ 'name': driver,
706
+ 'type': 'usb',
707
+ 'status': 'available'
708
+ })
709
+
710
+ # Check for PCI wireless devices
711
+ if os.path.exists('/sys/bus/pci/drivers'):
712
+ for driver in os.listdir('/sys/bus/pci/drivers'):
713
+ if any(x in driver.lower() for x in ['wlan', 'wireless', '80211', 'ath', 'rtl', 'rtw']):
714
+ drivers.append({
715
+ 'name': driver,
716
+ 'type': 'pci',
717
+ 'status': 'available'
718
+ })
719
+
720
+ except Exception as e:
721
+ logger.error(f"Error getting wireless drivers: {e}")
722
+
723
+ return drivers
724
+
725
+ def check_wireless_extensions(interface: str) -> bool:
726
+ """
727
+ Check if a network interface supports wireless extensions.
728
+
729
+ Args:
730
+ interface: Interface name
731
+
732
+ Returns:
733
+ bool: True if wireless extensions are supported, False otherwise
734
+ """
735
+ try:
736
+ if IS_LINUX:
737
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
738
+ try:
739
+ # Try to get wireless name
740
+ fcntl.ioctl(s.fileno(), WIRELESS_EXT, interface.encode() + b'\x00' * 32)
741
+ return True
742
+ except IOError:
743
+ return False
744
+ elif IS_MAC:
745
+ # macOS always supports wireless extensions
746
+ return True
747
+ else:
748
+ return False
749
+ except:
750
+ return False
751
+
752
+ def get_wireless_capabilities(interface: str) -> Dict[str, Any]:
753
+ """
754
+ Get the wireless capabilities of an interface.
755
+
756
+ Args:
757
+ interface: Interface name
758
+
759
+ Returns:
760
+ Dict[str, Any]: Dictionary of wireless capabilities
761
+ """
762
+ capabilities = {
763
+ 'monitor': False,
764
+ 'injection': False,
765
+ 'frequency_bands': [],
766
+ 'encryption': [],
767
+ 'modes': []
768
+ }
769
+
770
+ if not check_wireless_extensions(interface):
771
+ return capabilities
772
+
773
+ try:
774
+ # Check if interface supports monitor mode
775
+ result = subprocess.run(['iw', 'phy', interface, 'info'],
776
+ capture_output=True, text=True)
777
+
778
+ if 'monitor' in result.stdout.lower():
779
+ capabilities['monitor'] = True
780
+
781
+ # Check for packet injection support
782
+ if 'RX invalid nwid' in result.stdout:
783
+ capabilities['injection'] = True
784
+
785
+ # Check supported frequency bands
786
+ if '5180 MHz' in result.stdout:
787
+ capabilities['frequency_bands'].append('5GHz')
788
+ if '2412 MHz' in result.stdout:
789
+ capabilities['frequency_bands'].append('2.4GHz')
790
+
791
+ # Check supported encryption types
792
+ if 'WPA' in result.stdout:
793
+ capabilities['encryption'].append('WPA')
794
+ if 'WPA2' in result.stdout:
795
+ capabilities['encryption'].append('WPA2')
796
+ if 'WEP' in result.stdout:
797
+ capabilities['encryption'].append('WEP')
798
+
799
+ # Check supported modes
800
+ if 'AP' in result.stdout:
801
+ capabilities['modes'].append('AP')
802
+ if 'station' in result.stdout.lower():
803
+ capabilities['modes'].append('station')
804
+ if 'monitor' in result.stdout.lower():
805
+ capabilities['modes'].append('monitor')
806
+
807
+ except Exception as e:
808
+ logger.error(f"Error getting wireless capabilities: {e}")
809
+
810
+ return capabilities