Obtenir la passerelle par défaut

J'écris un programme qui montre à l'utilisateur son adresse IP, son masque de sous-réseau et sa passerelle par défaut. Je peux obtenir les deux premiers, mais pour le dernier, c'est ce que j'ai trouvé:

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

Cela, bien sûr, renvoie une collection de GatewayIPAddressInformation. Donc, si un ordinateur a plusieurs passerelles, Comment puis-je déterminer quelle est la passerelle par défaut?

En pratique, je n'ai jamais vu cette collection contenir une seule entrée, mais comme elle est implémentée en tant que collection, cela va de soi que certains ordinateurs contiennent plusieurs passerelles, dont aucune n'est marquée comme "par défaut". Alors, y a-t-il un moyen de déterminer le par défaut ou est-ce juste une conjecture?

22
demandé sur Frecklefoot 0000-00-00 00:00:00

3 réponses

Il doit s'agir de la première adresse de passerelle valide et activée de la première interface réseau activée:

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

J'ai également ajouté d'autres vérifications commentées qui ont été signalées comme utiles par d'autres personnes ici. Vous pouvez vérifier le AddressFamily pour faire la distinction entre IPv4 et IPv6. Ce dernier peut être utilisé si vous rencontrez des problèmes avec une adresse 0.0.0.0 renvoyée.

Cela dit, la façon recommandée de le faire utilise GetBestInterface pour trouver une interface de routage vers un adresse IP spécifique. Si vous avez déjà une adresse IP de destination en tête, alors il est préférable de l'utiliser - et j'en ai également inclus un exemple ci-dessous:

[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;
}
30
répondu caesay 2018-03-15 15:47:37

La première adresse IP renvoyée par la commande traceroute sera la passerelle .Vous pouvez également utiliser ce fait pour obtenir la passerelle.Vous pouvez trouver une belle implémentation de tracerout ici: TraceRoute et Ping en C #

3
répondu harsini 2017-05-23 11:54:39

Je sais que c'est une question un peu plus ancienne mais, je venais de trouver la nécessité de récupérer l'adresse IPV4 de la passerelle locale. La réponse acceptée ne correspond pas tout à fait à la facture quand il s'agit de mon propre système, donc, je l'ai modifié en suite et je suis sûr que d'autres seront en mesure d'utiliser cette solution, aussi.

Comme je n'ai pas encore assez de représentants pour commenter, je suis obligé d'ajouter ceci comme une "question":

public static IPAddress 
2
répondu