获取默认网关

我正在编写一个程序,向用户显示他们的IP地址,子网掩码和默认网关。 我可以得到前两个,但对于最后一个,这就是我出现的:

GatewayIPAddressInformationCollection gwc = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0].GetIPProperties().GatewayAddresses; 

当然,这会返回一个GatewayIPAddressInformation的集合。 因此,如果计算机有多个网关,我如何确定哪个是默认网关?

在实践中,我只见过这个集合包含一个条目,但由于它是作为集合实现的,因此有些计算机包含多个网关,其中没有一个被标记为“默认”。 那么有没有办法确定默认值还是只是猜测?

它应该是第一个启用的网络接口的第一个有效和启用的网关地址:

 public static IPAddress GetDefaultGateway() { return NetworkInterface .GetAllNetworkInterfaces() .Where(n => n.OperationalStatus == OperationalStatus.Up) .Where(n => n.NetworkInterfaceType != NetworkInterfaceType.Loopback) .SelectMany(n => n.GetIPProperties()?.GatewayAddresses) .Select(g => g?.Address) .Where(a => a != null) // .Where(a => a.AddressFamily == AddressFamily.InterNetwork) // .Where(a => Array.FindIndex(a.GetAddressBytes(), b => b != 0) >= 0) .FirstOrDefault(); } 

我还添加了一些进一步评论的检查,这些检查在这里被其他人指出是有用的。 您可以检查AddressFamily以区分IPv4和IPv6。 如果您遇到返回0.0.0.0地址的问题,可以使用后者。

也就是说,推荐的方法是使用GetBestInterface查找路由到特定IP地址的接口。 如果您已经考虑了目标IP地址,那么最好使用它 – 所以我还包括以下示例:

 [DllImport("iphlpapi.dll", CharSet = CharSet.Auto)] private static extern int GetBestInterface(UInt32 destAddr, out UInt32 bestIfIndex); public static IPAddress GetGatewayForDestination(IPAddress destinationAddress) { UInt32 destaddr = BitConverter.ToUInt32(destinationAddress.GetAddressBytes(), 0); uint interfaceIndex; int result = GetBestInterface(destaddr, out interfaceIndex); if (result != 0) throw new Win32Exception(result); foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) { var niprops = ni.GetIPProperties(); if (niprops == null) continue; var gateway = niprops.GatewayAddresses?.FirstOrDefault()?.Address; if (gateway == null) continue; if (ni.Supports(NetworkInterfaceComponent.IPv4)) { var v4props = niprops.GetIPv4Properties(); if (v4props == null) continue; if (v4props.Index == interfaceIndex) return gateway; } if (ni.Supports(NetworkInterfaceComponent.IPv6)) { var v6props = niprops.GetIPv6Properties(); if (v6props == null) continue; if (v6props.Index == interfaceIndex) return gateway; } } return null; } 

traceroute命令返回的第一个IP地址将是网关。你也可以使用这个事实来获取网关。你可以在这里找到一个很好的tracerout实现: TraceRoute和C#中的Ping

我知道这是一个稍微陈旧的问题,但我刚刚发现需要检索本地网关的IPV4地址。 当涉及到我自己的系统时,接受的答案并不符合要求,因此,我将其修改为套件,我相信其他人也可以使用此解决方案。

由于我还没有足够的评论来评论,我不得不将其添加为“问题”:

 public static IPAddress GetDefaultGateway() { IPAddress result = null; var cards = NetworkInterface.GetAllNetworkInterfaces().ToList(); if (cards.Any()) { foreach (var card in cards) { var props = card.GetIPProperties(); if (props == null) continue; var gateways = props.GatewayAddresses; if (!gateways.Any()) continue; var gateway = gateways.FirstOrDefault(g => g.Address.AddressFamily.ToString() == "InterNetwork"); if (gateway == null) continue; result = gateway.Address; break; }; } return result; } 
 NetworkInterface[] allNICs = NetworkInterface.GetAllNetworkInterfaces(); foreach (var nic in allNICs) { var ipProp = nic.GetIPProperties(); var gwAddresses = ipProp.GatewayAddresses; if (gwAddresses.Count > 0 && gwAddresses.FirstOrDefault(g => g.Address.AddressFamily == AddressFamily.InterNetwork) != null) { localIP = ipProp.UnicastAddresses.First(d => d.Address.AddressFamily == AddressFamily.InterNetwork).Address; } } Debug.Print(localIP.ToString()); 

根据@ midspace对@caesay答案的评论,这是一个更好的答案:

 public static IPAddress GetDefaultGateway() { var gateway_address = NetworkInterface.GetAllNetworkInterfaces() .Where(e => e.OperationalStatus == OperationalStatus.Up) .SelectMany(e => e.GetIPProperties().GatewayAddresses) .FirstOrDefault(); if (gateway_address == null) return null; return gateway_address.Address; } 

我警告说这不是一个完整的解决方案,如果你正在寻找负责互联网访问的主界面,你应该结合其他方法,比如使用win32 API GetBestInterface来找到连接到目标地址的最佳界面。

你可以在这里找到示例用法: http : //www.pinvoke.net/default.aspx/iphlpapi.getbestinterface

我刚刚遇到这个并将使用以下代码 – 基本上它寻找的不是环回的接口,并且具有网关和单播地址。 然后从接口I获得非瞬态IPV4地址。

 public static class NetworkInterfaces { public static NetworkInterface GetDefaultInterface() { var interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); foreach (var intf in interfaces) { if (intf.OperationalStatus != OperationalStatus.Up) { continue; } if (intf.NetworkInterfaceType == NetworkInterfaceType.Loopback) { continue; } var properties = intf.GetIPProperties(); if (properties == null) { continue; } var gateways = properties.GatewayAddresses; if ((gateways == null) || (gateways.Count == 0)) { continue; } var addresses = properties.UnicastAddresses; if ((addresses == null) || (addresses.Count == 0)) { continue; } return intf; } return null; } public static IPAddress GetDefaultIPV4Address(NetworkInterface intf) { if (intf == null) { return null; } foreach (var address in intf.GetIPProperties().UnicastAddresses) { if (address.Address.AddressFamily != AddressFamily.InterNetwork) { continue; } if (address.IsTransient) { continue; } return address.Address; } return null; } } 

我认为你应该迭代这个集合并显示所有的网关,因为如果有许多网关到适配器,他们都被认为默认为该适配器