From 71687c1da65e4eb7b1251697f2359dfaf5a07061 Mon Sep 17 00:00:00 2001 From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com> Date: Wed, 7 Oct 2020 19:17:49 +0800 Subject: [PATCH] Revert "Use GetLocalEndPoint to replace GetBestRoute" This reverts commit 801e8e3b8a35537f92966d78175be5831d234c19. --- Netch/Utils/Utils.cs | 35 ++--- Netch/Win32Native.cs | 338 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 350 insertions(+), 23 deletions(-) diff --git a/Netch/Utils/Utils.cs b/Netch/Utils/Utils.cs index b661ab5d..79a20942 100644 --- a/Netch/Utils/Utils.cs +++ b/Netch/Utils/Utils.cs @@ -126,47 +126,38 @@ namespace Netch.Utils public static string GetFileVersion(string file) => File.Exists(file) ? FileVersionInfo.GetVersionInfo(file).FileVersion : string.Empty; - public static bool SearchOutboundAdapter(bool log = true) + public static bool SearchOutboundAdapter(bool logging = true) { - IPAddress localEnd; - try - { - localEnd = WebUtil.BestLocalEndPoint(new IPEndPoint(0x72727272, 53)).Address; - } - catch + // 寻找出口适配器 + if (Win32Native.GetBestRoute(BitConverter.ToUInt32(IPAddress.Parse("114.114.114.114").GetAddressBytes(), 0), + 0, out var pRoute) != 0) { + Logging.Error("GetBestRoute 搜索失败"); return false; } + Global.Outbound.Index = pRoute.dwForwardIfIndex; + // 根据 IP Index 寻找 出口适配器 try { - // 根据 IP 寻找 出口适配器 - Global.Outbound.Adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ => + var adapter = NetworkInterface.GetAllNetworkInterfaces().First(_ => { try { - return _.GetIPProperties().UnicastAddresses.Any(ip => - { - if (ip.Address.AddressFamily == AddressFamily.InterNetwork && ip.Address.ToString().Equals(localEnd.ToString())) - { - Global.Outbound.Index = _.GetIPProperties().GetIPv4Properties().Index; - return true; - } - - return false; - }); + return _.GetIPProperties().GetIPv4Properties().Index == Global.Outbound.Index; } catch { return false; } }); - Global.Outbound.Gateway = Global.Outbound.Adapter.GetIPProperties().GatewayAddresses[0].Address; - if (log) + Global.Outbound.Adapter = adapter; + Global.Outbound.Gateway = new IPAddress(pRoute.dwForwardNextHop); + if (logging) { Logging.Info($"出口 IPv4 地址:{Global.Outbound.Address}"); Logging.Info($"出口 网关 地址:{Global.Outbound.Gateway}"); - Logging.Info($"出口适配器:{Global.Outbound.Adapter.Name} {Global.Outbound.Adapter.Id} {Global.Outbound.Adapter.Description}, index: {Global.Outbound.Index}"); + Logging.Info($"出口适配器:{adapter.Name} {adapter.Id} {adapter.Description}, index: {Global.Outbound.Index}"); } return true; diff --git a/Netch/Win32Native.cs b/Netch/Win32Native.cs index cb7da4e4..46dbd8f5 100644 --- a/Netch/Win32Native.cs +++ b/Netch/Win32Native.cs @@ -1,11 +1,347 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; using System.Runtime.InteropServices; +using System.Text; namespace Netch { public static class Win32Native { + public enum ForwardType + { + Other = 1, + Invalid = 2, + Direct = 3, + Indirect = 4 + } + + public enum ForwardProtocol + { + Other = 1, + Local = 2, + NetMGMT = 3, + ICMP = 4, + EGP = 5, + GGP = 6, + Hello = 7, + RIP = 8, + IS_IS = 9, + ES_IS = 10, // 0x0000000A + CISCO = 11, // 0x0000000B + BBN = 12, // 0x0000000C + OSPF = 13, // 0x0000000D + BGP = 14, // 0x0000000E + NT_AUTOSTATIC = 10002, // 0x00002712 + NT_STATIC = 10006, // 0x00002716 + NT_STATIC_NON_DOD = 10007 // 0x00002717 + } + + public class RouteEntry + { + internal MIB_IPFORWARDROW _ipFwdNative; + private int _metric1; + private int _metric2; + private int _metric3; + private int _metric4; + private int _metric5; + private IPAddress _destination; + private IPAddress _mask; + private int _policy; + private IPAddress _nextHop; + private NetworkInterface _interface; + private ForwardProtocol _protocol; + private ForwardType _type; + private int _nextHopAS; + private int _age; + private int _index; + + public int Index + { + get => _index; + set => _index = value; + } + + public IPAddress Destination + { + get => _destination; + set => _destination = value; + } + + public IPAddress Mask + { + get => _mask; + set => _mask = value; + } + + public int Policy + { + get => _policy; + set => _policy = value; + } + + public IPAddress NextHop + { + get => _nextHop; + set => _nextHop = value; + } + + public NetworkInterface RelatedInterface => _interface; + + public string InterfaceName + { + get + { + if (RelatedInterface == null) + return string.Empty; + return RelatedInterface.Name; + } + } + + public ForwardType ForwardType + { + get => _type; + set => _type = value; + } + + public ForwardProtocol Protocol + { + get => _protocol; + set => _protocol = value; + } + + public int Age + { + get => _age; + set => _age = value; + } + + public int NextHopAS + { + get => _nextHopAS; + set => _nextHopAS = value; + } + + public int Metric1 + { + get => _metric1; + set => _metric1 = value; + } + + public int Metric2 + { + get => _metric2; + set => _metric2 = value; + } + + public int Metric3 + { + get => _metric3; + set => _metric3 = value; + } + + public int Metric4 + { + get => _metric4; + set => _metric4 = value; + } + + public int Metric5 + { + get => _metric5; + set => _metric5 = value; + } + + public RouteEntry( + uint destination, + uint mask, + int policy, + uint nextHop, + NetworkInterface intf, + ForwardType type, + ForwardProtocol proto, + int age, + int nextHopAS, + int metric1, + int metric2, + int metric3, + int metric4, + int metric5, + int idx) + { + _age = age; + _policy = policy; + _protocol = proto; + _type = type; + _destination = new IPAddress(destination); + _mask = new IPAddress(mask); + _nextHop = new IPAddress(nextHop); + _nextHopAS = nextHopAS; + _interface = intf; + _metric1 = metric1; + _metric2 = metric2; + _metric3 = metric3; + _metric4 = metric4; + _metric5 = metric5; + _index = idx; + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct MIB_IFROW + { + private const int MAX_INTERFACE_NAME_LEN = 256; + private const int MAXLEN_IFDESCR = 256; + private const int MAXLEN_PHYSADDR = 8; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string wszName; + public int dwIndex; + public int dwType; + public int dwMtu; + public int dwSpeed; + public int dwPhysAddrLen; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] bPhysAddr; + public int dwAdminStatus; + public int dwOperStatus; + public int dwLastChange; + public int dwInOctets; + public int dwInUcastPkts; + public int dwInNUcastPkts; + public int dwInDiscards; + public int dwInErrors; + public int dwInUnknownProtos; + public int dwOutOctets; + public int dwOutUcastPkts; + public int dwOutNUcastPkts; + public int dwOutDiscards; + public int dwOutErrors; + public int dwOutQLen; + public int dwDescrLen; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public byte[] bDescr; + } + + public class AdaptersTable + { + private Dictionary _adapters = new Dictionary(); + + public IDictionary GetAdapters() + { + return _adapters; + } + + public NetworkInterface GetAdapter(int interfaceIndex) + { + NetworkInterface networkInterface = null; + _adapters.TryGetValue(interfaceIndex, out networkInterface); + return networkInterface; + } + + public int GetAdapterIndex(NetworkInterface networkInterface) + { + return _adapters.First(a => a.Value == networkInterface).Key; + } + + public AdaptersTable() + { + var num1 = IntPtr.Zero; + var pdwSize = 0; + var num2 = 0; + num2 = GetIfTable(IntPtr.Zero, ref pdwSize, true); + var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); + try + { + num1 = Marshal.AllocHGlobal(pdwSize); + if (GetIfTable(num1, ref pdwSize, true) != 0) + return; + var num3 = Marshal.ReadInt32(num1); + var ptr = new IntPtr(num1.ToInt32() + 4); + for (var index = 0; index < num3; ++index) + { + var structure = (MIB_IFROW)Marshal.PtrToStructure(ptr, typeof(MIB_IFROW)); + var pIfRow = new MIB_IFROW(); + pIfRow.dwIndex = structure.dwIndex; + if (GetIfEntry(ref pIfRow) == 0) + { + var str = Encoding.ASCII.GetString(structure.bDescr, 0, pIfRow.dwDescrLen - 1); + foreach (var networkInterface in networkInterfaces) + { + if (networkInterface.Description == str) + { + _adapters.Add(structure.dwIndex, networkInterface); + break; + } + } + } + ptr = new IntPtr(ptr.ToInt32() + Marshal.SizeOf(typeof(MIB_IFROW))); + } + } + catch (Exception) + { + // ignored + } + finally + { + Marshal.FreeHGlobal(num1); + } + } + } + + public struct MIB_IPFORWARDROW + { + public uint dwForwardDest; + public uint dwForwardMask; + public int dwForwardPolicy; + public uint dwForwardNextHop; + public int dwForwardIfIndex; + public ForwardType dwForwardType; + public ForwardProtocol dwForwardProto; + public int dwForwardAge; + public int dwForwardNextHopAS; + public int dwForwardMetric1; + public int dwForwardMetric2; + public int dwForwardMetric3; + public int dwForwardMetric4; + public int dwForwardMetric5; + + public static implicit operator MIB_IPFORWARDROW(RouteEntry value) + { + var mibIpforwardrow = new MIB_IPFORWARDROW(); + mibIpforwardrow.dwForwardAge = value.Age; + mibIpforwardrow.dwForwardDest = BitConverter.ToUInt32(value.Destination.GetAddressBytes(), 0); + mibIpforwardrow.dwForwardMask = BitConverter.ToUInt32(value.Mask.GetAddressBytes(), 0); + mibIpforwardrow.dwForwardMetric1 = value.Metric1; + mibIpforwardrow.dwForwardMetric2 = value.Metric2; + mibIpforwardrow.dwForwardMetric3 = value.Metric3; + mibIpforwardrow.dwForwardMetric4 = value.Metric4; + mibIpforwardrow.dwForwardMetric5 = value.Metric5; + mibIpforwardrow.dwForwardNextHop = BitConverter.ToUInt32(value.NextHop.GetAddressBytes(), 0); + mibIpforwardrow.dwForwardNextHopAS = value.NextHopAS; + mibIpforwardrow.dwForwardPolicy = value.Policy; + mibIpforwardrow.dwForwardProto = value.Protocol; + mibIpforwardrow.dwForwardType = value.ForwardType; + var adaptersTable = new AdaptersTable(); + mibIpforwardrow.dwForwardIfIndex = adaptersTable.GetAdapterIndex(value.RelatedInterface); + return mibIpforwardrow; + } + } + + [DllImport("iphlpapi", SetLastError = true)] + public static extern int GetIfTable(IntPtr pIfTable, ref int pdwSize, bool bOrder); + + [DllImport("iphlpapi", SetLastError = true)] + public static extern int GetIfEntry(ref MIB_IFROW pIfRow); + + [DllImport("iphlpapi", SetLastError = true)] + public static extern int GetBestRoute(uint dwDestAddr, int dwSourceAddr, out MIB_IPFORWARDROW pRoute); + [DllImport("User32", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern IntPtr GetForegroundWindow(); + + [DllImport("WinINet")] + public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); } -} \ No newline at end of file +}