From 3a61b31e0a5bdf0b369a2b278a4e20e158c89100 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 3 Aug 2024 22:06:37 +0800 Subject: [PATCH] Wifi (Linux): implement libnm stuff with plain dbus calls --- src/detection/wifi/wifi_linux.c | 144 ++++++++++++++++++++++++++++---- 1 file changed, 129 insertions(+), 15 deletions(-) diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index 137b81816..95a81325d 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -1,4 +1,5 @@ #include "wifi.h" +#include "common/dbus.h" #include "common/processing.h" #include "common/properties.h" #include "util/stringUtils.h" @@ -6,6 +7,118 @@ #include #include +// https://people.freedesktop.org/~lkundrak/nm-docs/nm-dbus-types.html#NM80211ApFlags +typedef enum { + NM_802_11_AP_FLAGS_NONE = 0x00000000, + NM_802_11_AP_FLAGS_PRIVACY = 0x00000001, + NM_802_11_AP_FLAGS_WPS = 0x00000002, + NM_802_11_AP_FLAGS_WPS_PBC = 0x00000004, + NM_802_11_AP_FLAGS_WPS_PIN = 0x00000008, +} NM80211ApFlags; + +// https://people.freedesktop.org/~lkundrak/nm-docs/nm-dbus-types.html#NM80211ApSecurityFlags +typedef enum { + NM_802_11_AP_SEC_NONE = 0x00000000, + NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001, + NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002, + NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004, + NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008, + NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010, + NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020, + NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040, + NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080, + NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100, + NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200, + NM_802_11_AP_SEC_KEY_MGMT_SAE = 0x00000400, + NM_802_11_AP_SEC_KEY_MGMT_OWE = 0x00000800, + NM_802_11_AP_SEC_KEY_MGMT_OWE_TM = 0x00001000, + NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192 = 0x00002000, +} NM80211ApSecurityFlags; + +static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) +{ + FFDBusData dbus; + const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus); + if(error) + return error; + + { + DBusMessage* device = ffDBusGetMethodReply(&dbus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "GetDeviceByIpIface", item->inf.description.chars); + if(!device) + return "Failed to call GetDeviceByIpIface"; + + ffStrbufClear(buffer); + DBusMessageIter rootIter; + if(!dbus.lib->ffdbus_message_iter_init(device, &rootIter) || !ffDBusGetString(&dbus, &rootIter, buffer)) + { + dbus.lib->ffdbus_message_unref(device); + return "Failed to get device path"; + } + dbus.lib->ffdbus_message_unref(device); + } + + if (item->conn.txRate != item->conn.txRate) + { + uint32_t bitrate; + if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", buffer->chars, "org.freedesktop.NetworkManager.Device.Wireless", "Bitrate", &bitrate)) + item->conn.txRate = bitrate / 1000.; + } + + FF_STRBUF_AUTO_DESTROY apPath = ffStrbufCreate(); + if (!ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", buffer->chars, "org.freedesktop.NetworkManager.Device.Wireless", "ActiveAccessPoint", &apPath)) + return "Failed to get active access point path"; + + if (!item->conn.status.length) + ffStrbufSetStatic(&item->conn.status, "connected"); + + if (!item->conn.ssid.length) + ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Ssid", &item->conn.ssid); + + if (!item->conn.bssid.length) + ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "HwAddress", &item->conn.bssid); + + if (item->conn.signalQuality != item->conn.signalQuality) + { + uint32_t strengthPercent; + if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Strength", &strengthPercent)) + item->conn.signalQuality = strengthPercent; + } + + NM80211ApFlags flags; + NM80211ApSecurityFlags wpaFlags, rsnFlags; + if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Flags", &flags) && + ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "WpaFlags", &wpaFlags) && + ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars , "org.freedesktop.NetworkManager.AccessPoint", "RsnFlags", &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/"); + if (wpaFlags != NM_802_11_AP_SEC_NONE) + ffStrbufAppendS(&item->conn.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/"); + } + if (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { + ffStrbufAppendS(&item->conn.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/"); + } + 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/"); + } + if (!item->conn.security.length) + ffStrbufAppendS(&item->conn.security, "Insecure"); + else + ffStrbufTrimRight(&item->conn.security, '/'); + } + + return NULL; +} + static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) { const char* error = NULL; @@ -28,9 +141,9 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) return NULL; } - ffStrbufAppendS(&item->conn.status, "connected"); ffStrbufSubstrBeforeFirstC(&item->conn.bssid, ' '); + ffStrbufUpperCase(&item->conn.bssid); ffParsePropLines(output.chars, "SSID: ", &item->conn.ssid); @@ -63,8 +176,6 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) } #if FF_HAVE_LINUX_WIRELESS -#define FF_DETECT_WIFI_WITH_IOCTLS - #include "common/io/io.h" #include @@ -86,7 +197,10 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) iwr.u.essid.length = IW_ESSID_MAX_SIZE + 1; iwr.u.essid.flags = 0; if(ioctl(sock, SIOCGIWESSID, &iwr) >= 0) + { + ffStrbufSetStatic(&item->conn.status, "connected"); ffStrbufRecalculateLength(&item->conn.ssid); + } if(ioctl(sock, SIOCGIWNAME, &iwr) >= 0 && !ffStrEqualsIgnCase(iwr.u.name, "IEEE 802.11")) { @@ -99,10 +213,13 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) 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]); + ffStrbufAppendF(&item->conn.bssid, "%.2X:", (uint8_t) iwr.u.ap_addr.sa_data[i]); ffStrbufTrimRight(&item->conn.bssid, '-'); } + if(ioctl(sock, SIOCGIWRATE, &iwr) >= 0) + item->conn.txRate = iwr.u.bitrate.value / 1000000.; + struct iw_statistics stats; iwr.u.data.pointer = &stats; iwr.u.data.length = sizeof(stats); @@ -156,7 +273,6 @@ const char* ffDetectWifi(FF_MAYBE_UNUSED FFlist* result) return "if_nameindex() failed"; FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); - const char* error = NULL; for(struct if_nameindex* i = infs; !(i->if_index == 0 && i->if_name == NULL); ++i) { @@ -184,18 +300,16 @@ const char* ffDetectWifi(FF_MAYBE_UNUSED FFlist* result) if (!ffStrbufEqualS(&item->inf.status, "up")) continue; - if (detectWifiWithIw(item, &buffer) == NULL) - continue; + if (detectWifiWithIw(item, &buffer) != NULL) + { + #ifdef FF_HAVE_LINUX_WIRELESS + detectWifiWithIoctls(item); + #endif + } - #ifdef FF_DETECT_WIFI_WITH_IOCTLS - detectWifiWithIoctls(item); - continue; - #endif - - error = "`iw` failed and `linux/wireless.h` not found during compilation"; - break; + detectWifiWithNm(item, &buffer); } if_freenameindex(infs); - return error; + return NULL; }