diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index b9dafc001..deadf6dcc 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -4,6 +4,7 @@ #include "common/processing.h" #include "common/properties.h" #include "util/stringUtils.h" +#include "util/debug.h" #include @@ -45,48 +46,77 @@ typedef enum { static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) { + FF_DEBUG("Starting NetworkManager wifi detection for interface %s", item->inf.description.chars); FFDBusData dbus; const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus); if(error) + { + FF_DEBUG("Failed to load DBus data: %s", error); return error; + } { + FF_DEBUG("Getting device by IP interface name"); DBusMessage* device = ffDBusGetMethodReply(&dbus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "GetDeviceByIpIface", item->inf.description.chars); if(!device) + { + FF_DEBUG("GetDeviceByIpIface failed for interface %s", item->inf.description.chars); return "Failed to call GetDeviceByIpIface"; + } ffStrbufClear(buffer); DBusMessageIter rootIter; if(!dbus.lib->ffdbus_message_iter_init(device, &rootIter) || !ffDBusGetString(&dbus, &rootIter, buffer)) { + FF_DEBUG("Failed to initialize message iterator or get device path"); dbus.lib->ffdbus_message_unref(device); return "Failed to get device path"; } + FF_DEBUG("Got device path: %s", buffer->chars); dbus.lib->ffdbus_message_unref(device); } if (item->conn.txRate != item->conn.txRate) { + FF_DEBUG("Getting bitrate from NetworkManager"); uint32_t bitrate; if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", buffer->chars, "org.freedesktop.NetworkManager.Device.Wireless", "Bitrate", &bitrate)) + { item->conn.txRate = bitrate / 1000.; + FF_DEBUG("Got bitrate: %.2f Mbps", item->conn.txRate); + } + else + FF_DEBUG("Failed to get bitrate"); } + FF_DEBUG("Getting active access point path"); FF_STRBUF_AUTO_DESTROY apPath = ffStrbufCreate(); if (!ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", buffer->chars, "org.freedesktop.NetworkManager.Device.Wireless", "ActiveAccessPoint", &apPath)) + { + FF_DEBUG("Failed to get active access point path"); return "Failed to get active access point path"; + } + FF_DEBUG("Got access point path: %s", apPath.chars); if (!item->conn.status.length) + { ffStrbufSetStatic(&item->conn.status, "connected"); + FF_DEBUG("Setting connection status to 'connected'"); + } + FF_DEBUG("Getting access point properties"); DBusMessage* reply = ffDBusGetAllProperties(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint"); if(reply == NULL) + { + FF_DEBUG("Failed to get access point properties"); return "Failed to get access point properties"; + } DBusMessageIter rootIterator; if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator) && dbus.lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY) { + FF_DEBUG("Invalid type of access point properties"); dbus.lib->ffdbus_message_unref(reply); return "Invalid type of access point properties"; } @@ -98,6 +128,7 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) NM80211ApSecurityFlags wpaFlags, rsnFlags; int flagCount = 0; + FF_DEBUG("Parsing access point properties"); while(true) { if(dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) @@ -114,32 +145,49 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) if (ffStrEquals(key, "Ssid")) { if (!item->conn.ssid.length) + { + FF_DEBUG("Found SSID property"); ffDBusGetString(&dbus, &dictIterator, &item->conn.ssid); + FF_DEBUG("SSID: %s", item->conn.ssid.chars); + } } else if (ffStrEquals(key, "HwAddress")) { if (!item->conn.bssid.length) + { + FF_DEBUG("Found HwAddress property"); ffDBusGetString(&dbus, &dictIterator, &item->conn.bssid); + FF_DEBUG("BSSID: %s", item->conn.bssid.chars); + } } else if (ffStrEquals(key, "Strength")) { if (item->conn.signalQuality != item->conn.signalQuality) { + FF_DEBUG("Found Strength property"); uint32_t strengthPercent; if (ffDBusGetUint(&dbus, &dictIterator, &strengthPercent)) + { item->conn.signalQuality = strengthPercent; + FF_DEBUG("Signal quality: %u%%", strengthPercent); + } } } else if (ffStrEquals(key, "Frequency")) { if (item->conn.frequency == 0) { + FF_DEBUG("Found Frequency property"); uint32_t frequency; if (ffDBusGetUint(&dbus, &dictIterator, &frequency)) { item->conn.frequency = (uint16_t) frequency; + FF_DEBUG("Frequency: %u MHz", item->conn.frequency); if (item->conn.channel == 0) + { item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); + FF_DEBUG("Calculated channel: %u", item->conn.channel); + } } } } @@ -154,40 +202,68 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) if (flagCount == 3) { + FF_DEBUG("Determining security type from flags (Flags: 0x%08x, WPA: 0x%08x, RSN: 0x%08x)", + flags, wpaFlags, rsnFlags); if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpaFlags == NM_802_11_AP_SEC_NONE) && (rsnFlags == NM_802_11_AP_SEC_NONE)) + { ffStrbufAppendS(&item->conn.security, "WEP/"); + FF_DEBUG("Adding security: WEP"); + } if (wpaFlags != NM_802_11_AP_SEC_NONE) + { ffStrbufAppendS(&item->conn.security, "WPA/"); + FF_DEBUG("Adding security: WPA"); + } if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK) || (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { ffStrbufAppendS(&item->conn.security, "WPA2/"); + FF_DEBUG("Adding security: WPA2"); } if (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { ffStrbufAppendS(&item->conn.security, "WPA3/"); + FF_DEBUG("Adding security: WPA3"); } if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE) || (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { ffStrbufAppendS(&item->conn.security, "OWE/"); + FF_DEBUG("Adding security: OWE"); } if ((wpaFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) || (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { ffStrbufAppendS(&item->conn.security, "802.1X/"); + FF_DEBUG("Adding security: 802.1X"); } if (!item->conn.security.length) + { ffStrbufAppendS(&item->conn.security, "Insecure"); + FF_DEBUG("No security detected, marking as 'Insecure'"); + } else + { ffStrbufTrimRight(&item->conn.security, '/'); + FF_DEBUG("Final security string: %s", item->conn.security.chars); + } + + if (wpaFlags & NM_802_11_AP_SEC_PAIR_TKIP || rsnFlags & NM_802_11_AP_SEC_PAIR_TKIP) { + FF_DEBUG("Detected TKIP encryption"); + } + if (wpaFlags & NM_802_11_AP_SEC_PAIR_CCMP || rsnFlags & NM_802_11_AP_SEC_PAIR_CCMP) { + FF_DEBUG("Detected CCMP/AES encryption"); + } } + FF_DEBUG("NetworkManager wifi detection completed successfully"); return NULL; } #endif // FF_HAVE_DBUS static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) { + FF_DEBUG("Starting iw wifi detection for interface %s", item->inf.description.chars); const char* error = NULL; FF_STRBUF_AUTO_DESTROY output = ffStrbufCreate(); + FF_DEBUG("Executing 'iw dev %s link'", item->inf.description.chars); if((error = ffProcessAppendStdOut(&output, (char* const[]){ "iw", "dev", @@ -195,48 +271,79 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) "link", NULL }))) + { + FF_DEBUG("iw command execution failed: %s", error); return error; + } if(output.length == 0) + { + FF_DEBUG("iw command output is empty"); return "iw command execution failed"; + } if(!ffParsePropLines(output.chars, "Connected to ", &item->conn.bssid)) { + FF_DEBUG("Not connected to any access point"); ffStrbufAppendS(&item->conn.status, "disconnected"); return NULL; } + FF_DEBUG("Connected to an access point"); ffStrbufAppendS(&item->conn.status, "connected"); ffStrbufSubstrBeforeFirstC(&item->conn.bssid, ' '); ffStrbufUpperCase(&item->conn.bssid); + FF_DEBUG("BSSID: %s", item->conn.bssid.chars); - ffParsePropLines(output.chars, "SSID: ", &item->conn.ssid); + if(ffParsePropLines(output.chars, "SSID: ", &item->conn.ssid)) + FF_DEBUG("SSID: %s", item->conn.ssid.chars); + else + FF_DEBUG("SSID not found in iw output"); ffStrbufClear(buffer); if(ffParsePropLines(output.chars, "signal: ", buffer)) { int level = (int) ffStrbufToSInt(buffer, INT_MAX); if (level != INT_MAX) + { item->conn.signalQuality = level >= -50 ? 100 : level <= -100 ? 0 : (level + 100) * 2; + FF_DEBUG("Signal level: %d dBm, quality: %.0f%%", level, item->conn.signalQuality); + } } ffStrbufClear(buffer); if(ffParsePropLines(output.chars, "rx bitrate: ", buffer)) + { item->conn.rxRate = ffStrbufToDouble(buffer); + FF_DEBUG("RX bitrate: %.2f Mbps", item->conn.rxRate); + } ffStrbufClear(buffer); if(ffParsePropLines(output.chars, "tx bitrate: ", buffer)) { item->conn.txRate = ffStrbufToDouble(buffer); + FF_DEBUG("TX bitrate: %.2f Mbps (raw: %s)", item->conn.txRate, buffer->chars); if(ffStrbufContainS(buffer, " EHT-MCS ")) + { ffStrbufSetStatic(&item->conn.protocol, "802.11be (Wi-Fi 7)"); + FF_DEBUG("Detected protocol: Wi-Fi 7"); + } else if(ffStrbufContainS(buffer, " HE-MCS ")) + { ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)"); + FF_DEBUG("Detected protocol: Wi-Fi 6"); + } else if(ffStrbufContainS(buffer, " VHT-MCS ")) + { ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)"); + FF_DEBUG("Detected protocol: Wi-Fi 5"); + } else if(ffStrbufContainS(buffer, " MCS ")) + { ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)"); + FF_DEBUG("Detected protocol: Wi-Fi 4"); + } } ffStrbufClear(buffer); @@ -244,8 +351,10 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) { item->conn.frequency = (uint16_t) ffStrbufToUInt(buffer, 0); item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); + FF_DEBUG("Frequency: %u MHz, Channel: %u", item->conn.frequency, item->conn.channel); } + FF_DEBUG("iw wifi detection completed successfully"); return NULL; } @@ -257,12 +366,19 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) static const char* detectWifiWithIoctls(FFWifiResult* item) { + FF_DEBUG("Starting ioctl wifi detection for interface %s", item->inf.description.chars); FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if(sock < 0) + { + FF_DEBUG("Failed to create socket: %m"); return "socket() failed"; + } struct iwreq iwr; ffStrCopy(iwr.ifr_name, item->inf.description.chars, IFNAMSIZ); + + // Get SSID + FF_DEBUG("Getting SSID via ioctl"); ffStrbufEnsureFree(&item->conn.ssid, IW_ESSID_MAX_SIZE); iwr.u.essid.pointer = (caddr_t) item->conn.ssid.chars; iwr.u.essid.length = IW_ESSID_MAX_SIZE + 1; @@ -271,31 +387,54 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) { ffStrbufSetStatic(&item->conn.status, "connected"); ffStrbufRecalculateLength(&item->conn.ssid); + FF_DEBUG("SSID: %s", item->conn.ssid.chars); } + else + FF_DEBUG("Failed to get SSID via ioctl: %m"); + // Get protocol name + FF_DEBUG("Getting protocol name via ioctl"); if(ioctl(sock, SIOCGIWNAME, &iwr) >= 0 && !ffStrEqualsIgnCase(iwr.u.name, "IEEE 802.11")) { if(ffStrStartsWithIgnCase(iwr.u.name, "IEEE ")) ffStrbufSetS(&item->conn.protocol, iwr.u.name + strlen("IEEE ")); else ffStrbufSetS(&item->conn.protocol, iwr.u.name); + FF_DEBUG("Protocol: %s", item->conn.protocol.chars); } + else + FF_DEBUG("Failed to get protocol name via ioctl: %m"); + // Get BSSID + FF_DEBUG("Getting BSSID via ioctl"); if(ioctl(sock, SIOCGIWAP, &iwr) >= 0) { for(int i = 0; i < 6; ++i) ffStrbufAppendF(&item->conn.bssid, "%.2X:", (uint8_t) iwr.u.ap_addr.sa_data[i]); ffStrbufTrimRight(&item->conn.bssid, ':'); + FF_DEBUG("BSSID: %s", item->conn.bssid.chars); } + else + FF_DEBUG("Failed to get BSSID via ioctl: %m"); + // Get bitrate + FF_DEBUG("Getting bitrate via ioctl"); if(ioctl(sock, SIOCGIWRATE, &iwr) >= 0) + { item->conn.txRate = iwr.u.bitrate.value / 1000000.; + FF_DEBUG("TX bitrate: %.2f Mbps", item->conn.txRate); + } + else + FF_DEBUG("Failed to get bitrate via ioctl: %m"); + // Get frequency/channel + FF_DEBUG("Getting frequency via ioctl"); if(ioctl(sock, SIOCGIWFREQ, &iwr) >= 0) { if (iwr.u.freq.e == 0 && iwr.u.freq.m <= 1000) { item->conn.channel = (uint16_t) iwr.u.freq.m; + FF_DEBUG("Direct channel value: %u", item->conn.channel); } else { @@ -312,9 +451,14 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) } item->conn.frequency = (uint16_t) iwr.u.freq.m; item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); + FF_DEBUG("Frequency: %u MHz, Channel: %u", item->conn.frequency, item->conn.channel); } } + else + FF_DEBUG("Failed to get frequency via ioctl: %m"); + // Get signal strength + FF_DEBUG("Getting signal stats via ioctl"); struct iw_statistics stats; iwr.u.data.pointer = &stats; iwr.u.data.length = sizeof(stats); @@ -322,11 +466,15 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) if(ioctl(sock, SIOCGIWSTATS, &iwr) >= 0) { - int8_t level = (int8_t) stats.qual.level; // https://stackoverflow.com/questions/18079771/wireless-h-how-do-i-print-out-the-signal-level + int8_t level = (int8_t) stats.qual.level; item->conn.signalQuality = level >= -50 ? 100 : level <= -100 ? 0 : (level + 100) * 2; + FF_DEBUG("Signal level: %d dBm, quality: %.0f%%", level, item->conn.signalQuality); } + else + FF_DEBUG("Failed to get signal stats via ioctl: %m"); - //FIXME: doesn't work + // Get security info + FF_DEBUG("Getting security info via ioctl"); struct iw_encode_ext iwe; iwr.u.data.pointer = &iwe; iwr.u.data.length = sizeof(iwe); @@ -337,43 +485,61 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) { case IW_ENCODE_ALG_WEP: ffStrbufAppendS(&item->conn.security, "WEP"); + FF_DEBUG("Security: WEP"); break; case IW_ENCODE_ALG_TKIP: ffStrbufAppendS(&item->conn.security, "TKIP"); + FF_DEBUG("Security: TKIP"); break; case IW_ENCODE_ALG_CCMP: ffStrbufAppendS(&item->conn.security, "CCMP"); + FF_DEBUG("Security: CCMP"); break; case IW_ENCODE_ALG_PMK: ffStrbufAppendS(&item->conn.security, "PMK"); + FF_DEBUG("Security: PMK"); break; case IW_ENCODE_ALG_AES_CMAC: ffStrbufAppendS(&item->conn.security, "CMAC"); + FF_DEBUG("Security: CMAC"); break; default: ffStrbufAppendF(&item->conn.security, "Unknown (%d)", (int) iwe.alg); + FF_DEBUG("Security: Unknown (%d)", (int) iwe.alg); break; } } + else + FF_DEBUG("Failed to get security info via ioctl: %m"); + FF_DEBUG("ioctl wifi detection completed"); return NULL; } #endif // FF_HAVE_LINUX_WIRELESS const char* ffDetectWifi(FF_MAYBE_UNUSED FFlist* result) { + FF_DEBUG("Starting wifi detection"); struct if_nameindex* infs = if_nameindex(); if(!infs) + { + FF_DEBUG("if_nameindex() failed: %m"); return "if_nameindex() failed"; + } FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); for(struct if_nameindex* i = infs; !(i->if_index == 0 && i->if_name == NULL); ++i) { + FF_DEBUG("Checking interface: %s (index: %u)", i->if_name, i->if_index); ffStrbufSetF(&buffer, "/sys/class/net/%s/phy80211/", i->if_name); if(!ffPathExists(buffer.chars, FF_PATHTYPE_DIRECTORY)) + { + FF_DEBUG("Not a wifi interface (no phy80211 directory)"); continue; + } + FF_DEBUG("Found wifi interface: %s", i->if_name); FFWifiResult* item = (FFWifiResult*)ffListAdd(result); ffStrbufInitS(&item->inf.description, i->if_name); ffStrbufInit(&item->inf.status); @@ -390,24 +556,36 @@ const char* ffDetectWifi(FF_MAYBE_UNUSED FFlist* result) ffStrbufSetF(&buffer, "/sys/class/net/%s/operstate", i->if_name); if (!ffAppendFileBuffer(buffer.chars, &item->inf.status)) + { + FF_DEBUG("Failed to read operstate file"); continue; + } ffStrbufTrimRightSpace(&item->inf.status); + FF_DEBUG("Interface status: %s", item->inf.status.chars); if (!ffStrbufEqualS(&item->inf.status, "up")) + { + FF_DEBUG("Skipping interface as it's not up"); continue; + } + FF_DEBUG("Trying to detect wifi with iw"); if (detectWifiWithIw(item, &buffer) != NULL) { + FF_DEBUG("iw detection failed, trying fallback methods"); #ifdef FF_HAVE_LINUX_WIRELESS + FF_DEBUG("Trying to detect wifi with ioctls"); detectWifiWithIoctls(item); #endif } #ifdef FF_HAVE_DBUS + FF_DEBUG("Enhancing wifi info with NetworkManager"); detectWifiWithNm(item, &buffer); #endif } if_freenameindex(infs); + FF_DEBUG("Wifi detection completed, found %u wifi interfaces", result->length); return NULL; }