Get the Default Gateway

2019-01-11 13:08发布

问题:

I'm writing a program that shows the user their IP address, Subnet mask and Default gateway. I can get the first two, but for the last one, this is what I turned up:

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

That, of course, returns a collection of GatewayIPAddressInformation. So, if a computer has multiple gateways, how can I determine which is the default gateway?

In practice, I've only ever seen this collection contain a single entry, but since it's implemented as a collection, it stands to reason that some computers contain multiple gateways, none of which are marked as "Default". So is there a way to determine the default or is it all just guesswork?

回答1:

It should be the first valid and enabled gateway address of the first enabled network interface:

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

I've also added some further commented checks which have been pointed out as useful by other people here. You can check the AddressFamily one to distinguish between IPv4 and IPv6. The latter one can be used if you're having issues with a 0.0.0.0 address being returned.

That said, the recommended way to do this uses GetBestInterface to find an interface for routing to a specific IP address. If you have a destination IP address in mind already, then it's better to use this - and so I've also included an example of that below:

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


回答2:

The first IP address returned by traceroute command will be the gateway .You can also using this fact for getting gateway.You can find a nice implementation of tracerout here: TraceRoute and Ping in C#



回答3:

I know this is a slightly older question but, I had just come upon the need to retrieve the IPV4 address of the local gateway. The accepted answer doesn't quite fit the bill when it comes to my own system so, I modified it to suite and I'm sure others will be able to use this solution, too.

Since I don't yet have enough rep to comment, I'm forced to add this as a "question":

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


回答4:

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


回答5:

according to @midspace's comment on @caesay's answer this is a better answer:

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

I'm warning that it's not a complete solution, if your'e looking for the main interface responsible for the internet access, you should combine other approaches like using win32 API GetBestInterface to find the best interface to connect to a destination address.

you can find example usage here: http://www.pinvoke.net/default.aspx/iphlpapi.getbestinterface



回答6:

I've just come across this and will be using the following code - basically it looks for interfaces that aren't loopback and are up and have gateways and unicast addresses. From the interface I then get a non transient IPV4 address.

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


回答7:

I think that you should iterate over this collection and show all the Gateways, since if there are many gateways to an adapter they are all considered Default to that adapter