获取默认网关(Get the Default Gateway)

2019-07-04 06:54发布

我正在写一个程序,显示用户的IP地址,子网掩码和默认网关。 我能得到前两个,但最后一个,这就是我打开了:

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

那当然,返回集合GatewayIPAddressInformation 。 因此,如果计算机有多个网关,我怎么能确定这是默认网关?

在实践中,我只看过这个系列包含一个条目,但因为它是作为一个集合实现的,按理说,有些计算机包含多个网关,其中没有一个被标记为“默认”。 那么,有没有一种方法来确定的默认还是这一切只是凭空猜测?

Answer 1:

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

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;
}


Answer 2:

通过返回的第一个IP地址traceroute命令会。你也可以使用这个事实,为获得gateway.You可以找到一个很好的实现网关tracerout这里: 路由跟踪和Ping在C#



Answer 3:

我知道这是一个稍微大一点的问题,而是,我刚刚临到需要检索本地网关的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;
    }


Answer 4:

一直在寻找一个怪异把戏来确定本地IP地址? 然而,做到这一点非常稳健与先前的方法呢?

[见端对响应于@caesay]

这可能是你在找什么。

using (var s = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp))
{
    s.Bind( new System.Net.IPEndPoint(System.Net.IPAddress.Any,0));
    s.Connect("google.com",0);

    var ipaddr = s.LocalEndPoint as System.Net.IPEndPoint;
    var addr = ipaddr.Address.ToString();
    Console.WriteLine(addr);
}

这将创建一个UDP套接字,但不会在其发送的数据。 然后,您可以看到本地接口和地址的套接字是必然。 您必须提供在这里我用google.com的IP地址或主机名,将由操作系统来确定哪个接口插座将被绑定到了,你会发现使用这种方法是什么IP地址。 对于IP地址,或者你使用主机名的99%+,你会得到界面+地址在缺省路由用于交通。

虽然这是一个有点钝,我怀疑这是比上面,人们使用的PInvoke呼叫,通过扫描结构,看看他们是否能找到接口中的方法更可靠。

当然,我发现它更强大的对我的3个双界面系统不是通过NetworkInterface.GetAllNetworkInterfaces()使用启发式方法来揣摩默认接口地址的扫描结果。

[更新/响应@caesay 2019年2月6日] @caesay曾在这里作出了一个极好点,所以我已经从使用UdpClient到套接字切换样品,并且明确地称为Socket.Connect()绑定()之后。 我还审查了connect()和LocalEndPoint框架的源代码,都立即致电其相应的Win32操作系统的系统调用,而不会减慢或懒惰有关调用到操作系统。 在Win32绑定页面上显示“应用程序可以调用bind学习地址和已分配到插座端口后使用getsockname。如果Internet地址等于INADDR_ANY或IN6ADDR_ANY,直到套接字getsockname不一定能提供地址连接的”。 这种情况现在已经明确处理,并审议了框架的源代码,IP地址应始终可用的connect()调用之后。



Answer 5:

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());


Answer 6:

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

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



Answer 7:

我刚刚碰到这个,将使用下面的代码 - 基本上它看起来没有回送,并已启动且有网关和单播地址的接口。 从接口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;
    }
}


Answer 8:

我认为你应该遍历这个收集和显示所有的网关,因为如果有很多网关适配器,他们都被认为是默认到该适配器



文章来源: Get the Default Gateway