mirror of
https://github.com/bolucat/Archive.git
synced 2025-10-09 18:11:20 +08:00
110 lines
3.9 KiB
C#
110 lines
3.9 KiB
C#
using System.Net.Sockets;
|
|
using System.Runtime.InteropServices;
|
|
using Windows.Win32.Foundation;
|
|
using Windows.Win32.Networking.WinSock;
|
|
using Windows.Win32.NetworkManagement.IpHelper;
|
|
using static Windows.Win32.PInvoke;
|
|
|
|
namespace Netch.Interops;
|
|
|
|
public static unsafe class RouteHelper
|
|
{
|
|
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern ulong ConvertLuidToIndex(ulong id);
|
|
|
|
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern bool CreateIPv4(string address, string netmask, ulong index);
|
|
|
|
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern bool CreateUnicastIP(AddressFamily inet, string address, byte cidr, ulong index);
|
|
|
|
public static bool CreateUnicastIPCS(AddressFamily inet, string address, byte cidr, ulong index)
|
|
{
|
|
MIB_UNICASTIPADDRESS_ROW addr;
|
|
InitializeUnicastIpAddressEntry(&addr);
|
|
|
|
addr.InterfaceIndex = (uint)index;
|
|
addr.OnLinkPrefixLength = cidr;
|
|
|
|
if (inet == AddressFamily.InterNetwork)
|
|
{
|
|
addr.Address.Ipv4.sin_family = (ushort)ADDRESS_FAMILY.AF_INET;
|
|
if (inet_pton((int)inet, address, &addr.Address.Ipv4.sin_addr) == 0)
|
|
return false;
|
|
}
|
|
else if (inet == AddressFamily.InterNetworkV6)
|
|
{
|
|
addr.Address.Ipv6.sin6_family = (ushort)ADDRESS_FAMILY.AF_INET6;
|
|
if (inet_pton((int)inet, address, &addr.Address.Ipv6.sin6_addr) == 0)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-createunicastipaddressentry#remarks
|
|
|
|
HANDLE handle = default;
|
|
using var obj = new Semaphore(0, 1);
|
|
|
|
void Callback(void* context, MIB_UNICASTIPADDRESS_ROW* row, MIB_NOTIFICATION_TYPE type)
|
|
{
|
|
if (type != MIB_NOTIFICATION_TYPE.MibInitialNotification)
|
|
{
|
|
NTSTATUS state;
|
|
if ((state = GetUnicastIpAddressEntry(row)) != 0)
|
|
{
|
|
Log.Error("GetUnicastIpAddressEntry failed: {State}", state.Value);
|
|
return;
|
|
}
|
|
|
|
if (row -> DadState == NL_DAD_STATE.IpDadStatePreferred)
|
|
{
|
|
try
|
|
{
|
|
obj.Release();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// i don't trust win32 api
|
|
Log.Error(e, "semaphore disposed");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NotifyUnicastIpAddressChange((ushort)ADDRESS_FAMILY.AF_INET, Callback, null, new BOOLEAN(byte.MaxValue), ref handle);
|
|
|
|
try
|
|
{
|
|
NTSTATUS state;
|
|
if ((state = CreateUnicastIpAddressEntry(&addr)) != 0)
|
|
{
|
|
Log.Error("CreateUnicastIpAddressEntry failed: {State}", state.Value);
|
|
return false;
|
|
}
|
|
|
|
if (!obj.WaitOne(TimeSpan.FromSeconds(10)))
|
|
{
|
|
Log.Error("Wait unicast IP usable timeout");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
finally
|
|
{
|
|
CancelMibChangeNotify2(handle);
|
|
}
|
|
}
|
|
|
|
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern bool RefreshIPTable(AddressFamily inet, ulong index);
|
|
|
|
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern bool CreateRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
|
|
|
[DllImport("RouteHelper.bin", CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern bool DeleteRoute(AddressFamily inet, string address, byte cidr, string gateway, ulong index, int metric);
|
|
} |