MCPcopy Create free account
hub / github.com/PierreGode/Ragnar / _scan_bluetooth

Method _scan_bluetooth

wardriving.py:3104–3167  ·  view source on GitHub ↗

Scan for Bluetooth Classic + BLE devices.

(self)

Source from the content-addressed store, hash-verified

3102 it is unmanaged (Ragnar marks its own scan adapters unmanaged so NM
3103 doesn't add competing routes), left in monitor mode, or its driver
3104 loaded after NM started. Treating sysfs as a fallback that only runs
3105 when nmcli returned *nothing* silently dropped exactly those adapters,
3106 so a third dongle never joined the sweep. sysfs is the authority on
3107 "this radio exists"; nmcli only adds names sysfs might miss.
3108 """
3109 found = set()
3110
3111 try:
3112 result = subprocess.run(
3113 ['nmcli', '-t', '-f', 'DEVICE,TYPE,STATE', 'device'],
3114 capture_output=True, text=True, timeout=5
3115 )
3116 if result.returncode == 0:
3117 for line in result.stdout.strip().split('\n'):
3118 parts = line.split(':')
3119 if len(parts) >= 3 and parts[1] == 'wifi':
3120 found.add(parts[0])
3121 except Exception as e:
3122 logger.debug(f"nmcli detection failed: {e}")
3123
3124 # sysfs: every wireless netdev, including nl80211 *and* wext-only
3125 # dongles that report no wireless/ dir but do have phy80211/.
3126 try:
3127 for name in os.listdir('/sys/class/net'):
3128 if os.path.isdir(f'/sys/class/net/{name}/wireless') \
3129 or os.path.isdir(f'/sys/class/net/{name}/phy80211'):
3130 found.add(name)
3131 except Exception as e:
3132 logger.debug(f"sysfs wifi detection failed: {e}")
3133
3134 # Drop the monitor/child vifs our own tooling (and airmon-ng) creates,
3135 # so a rebuilt monitor interface never doubles up with its parent.
3136 interfaces = sorted(n for n in found
3137 if not n.endswith('mon') and not n.startswith('mon'))
3138
3139 blocked = [n for n in interfaces if self._iface_rfkill_blocked(n)]
3140 if blocked and not quiet:
3141 # A soft-blocked dongle is present in sysfs but cannot scan; say so
3142 # explicitly because the symptom (adapter listed, zero networks) is
3143 # otherwise indistinguishable from a driver problem.
3144 logger.warning(
3145 f"Wardriving: {', '.join(blocked)} is rfkill-blocked and will not "
3146 f"scan until unblocked — run 'sudo rfkill unblock all'")
3147 # quiet=True on the periodic hot-plug rescan, so it doesn't log this
3148 # every cycle — only the genuine start-up detection is announced.
3149 (logger.debug if quiet else logger.info)(
3150 f"Wardriving detected {len(interfaces)} WiFi interface(s): "
3151 f"{', '.join(interfaces) or '(none)'}")
3152 return interfaces
3153
3154 @staticmethod
3155 def _iface_rfkill_blocked(iface):
3156 """True when this radio is soft/hard rfkill-blocked. A freshly plugged
3157 USB dongle commonly comes up blocked, so it enumerates but never scans."""
3158 try:
3159 phy = os.path.realpath(f'/sys/class/net/{iface}/phy80211')
3160 for entry in os.listdir(f'{phy}/rfkill'):
3161 if not entry.startswith('rfkill'):

Callers 1

_bt_scan_loopMethod · 0.95

Calls 6

infoMethod · 0.80
warningMethod · 0.80
addMethod · 0.80
appendMethod · 0.80
setFunction · 0.50
runMethod · 0.45

Tested by

no test coverage detected