using System.IO; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using QSafe.Core; namespace QSafe.Desktop; /// Reads the actual WLAN association; adapter/profile names and VPN adapters are not SSIDs. public sealed class HomeWifiNetwork : ILanNetwork { public static readonly HomeWifiNetwork Instance = new(); [DllImport("wlanapi.dll")] private static extern uint WlanOpenHandle(uint version, IntPtr reserved, out uint negotiated, out IntPtr handle); [DllImport("wlanapi.dll")] private static extern uint WlanCloseHandle(IntPtr handle, IntPtr reserved); [DllImport("wlanapi.dll")] private static extern uint WlanQueryInterface(IntPtr handle, ref Guid guid, uint opcode, IntPtr reserved, out uint size, out IntPtr data, out uint valueType); [DllImport("wlanapi.dll")] private static extern void WlanFreeMemory(IntPtr data); public LanBinding Current(Connection connection) { if (WlanOpenHandle(2, IntPtr.Zero, out _, out var handle) != 0) throw Offline(); try { foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces().Where(a => a.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 && a.OperationalStatus == OperationalStatus.Up)) { if (!Guid.TryParse(adapter.Id, out var guid)) continue; IntPtr raw = IntPtr.Zero; try { // WLAN_CONNECTION_ATTRIBUTES: state, mode, WCHAR profile[256], DOT11_SSID. if (WlanQueryInterface(handle, ref guid, 7, IntPtr.Zero, out var size, out raw, out _) != 0 || size < 556 || Marshal.ReadInt32(raw) != 1) continue; int length = Marshal.ReadInt32(raw, 520); if (length is < 1 or > 32) continue; var ssidBytes = new byte[length]; Marshal.Copy(IntPtr.Add(raw, 524), ssidBytes, 0, length); string ssid = new UTF8Encoding(false, true).GetString(ssidBytes); if (ssid != connection.HomeWifiSsid) continue; var properties = adapter.GetIPProperties(); int index = properties.GetIPv4Properties().Index; foreach (var address in properties.UnicastAddresses.Where(a => a.Address.AddressFamily == AddressFamily.InterNetwork)) { var binding = new LanBinding(ssid, true, address.Address, address.PrefixLength, index); try { LanPolicy.Check(connection, binding); return binding; } catch (IOException) { } } } finally { if (raw != IntPtr.Zero) WlanFreeMemory(raw); } } } finally { WlanCloseHandle(handle, IntPtr.Zero); } throw Offline(); } private static IOException Offline() => new("Автономный режим: домашний Wi-Fi не подтверждён. Синхронизация не выполняется. Если Windows скрывает SSID, проверьте разрешение доступа к имени Wi-Fi."); }