Files

50 lines
3.1 KiB
C#

using System.IO;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using QSafe.Core;
namespace QSafe.Desktop;
/// <summary>Reads the actual WLAN association; adapter/profile names and VPN adapters are not SSIDs.</summary>
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.");
}