Como determinar o endereço MAC da placa de rede física real - não interfaces de rede virtual criadas pelo VPN's (.NET C#)

StackOverflow https://stackoverflow.com/questions/1567377

Pergunta

Fundo

Estou tentando obter um identificador exclusivo de um computador e quero poder retornar com segurança o mesmo endereço MAC a cada vez. Confie em mim, tenho minhas razões para usar o endereço MAC e li muitas postagens sobre métodos de identificação exclusivos alternativos (e sim, eu considerei se eles não tiverem cartões de rede).

Problema

O problema está no .NET que não vejo de qualquer maneira para dizer se uma rede de rede específica é uma placa de rede de hardware física de algo como um "adaptador Nortel Ipsecshm - MiniPort Scheduler Packet Scheduler" que é adicionado quando você se conecta a determinadas VPNs ou redes WiFi.

Eu sei como obter os endereços MAC usando código semelhante a este:

    foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
    {
        log.Debug("NIC " + nic.OperationalStatus + " " + nic.NetworkInterfaceType + " " + nic.Speed + " " + nic.GetPhysicalAddress() + " " + nic.Description);
    }

Compreensivelmente não há 100% de maneira de garantir que eu esteja recebendo uma placa de rede interna, mas Eu gostaria de escolher o endereço MAC para retornar que para uma determinada máquina, com menos probabilidade de mudar. Independente de fatores como - se está conectado ao WiFi ... é conectado por meio de algum tipo de conexão de corda ... ou eles instalam um novo software VPN que adiciona uma nova interface.

Estratégias consideradas

1) Escolha a primeira interface que é "para cima". Isso falha no meu laptop porque o "Packet Miniport" está sempre em alta. Além disso, se eu amarrar meu telefone ao meu laptop, isso também aparecer como o primeiro cartão.

2) Escolha o tipo mais apropriado ... Isso falha B/C Basicamente, tudo aparece como "Ethernet", incluindo adaptadores Wi -Fi e minha conexão com a Internet com amarração do iPhone.

3) Escolha o NIC que possui um endereço IP. Falha por vários motivos: 1) A placa de rede pode não estar conectada à LAN 2) Existem várias NICs que podem ter endereços IP.

4) Basta enviar todos os endereços MAC ... O problema é que a lista mudaria com base no software instalado e será difícil comparar.

5) Escolha o endereço MAC com a velocidade mais rápida. Eu acho que esta é provavelmente a minha melhor aposta. Eu acho que é seguro dizer que a interface mais rápida geralmente será a mais permanente.

Como alternativa, pode haver outra maneira de detectar cartões físicos no .NET ou eu consideraria invocar outras chamadas da API se você pudesse recomendar uma que forneça informações diferentes.

Alguma outra idéia?

Para demonstrar aqui, é a saída do meu código de amostra acima quando tenho o meu iPhone amarrado:

DEBUG - NIC Down Ethernet 500000     0021E98BFBEF Apple Mobile Device Ethernet - Packet Scheduler Miniport
DEBUG - NIC Up   Ethernet 10000000   444553544200 Nortel IPSECSHM Adapter - Packet Scheduler Miniport
DEBUG - NIC Down Ethernet 54000000   00166FAC94C7 Intel(R) PRO/Wireless 2200BG Network Connection - Packet Scheduler Miniport
DEBUG - NIC Down Ethernet 1000000000 0016D326E957 Broadcom NetXtreme Gigabit Ethernet - Packet Scheduler Miniport
DEBUG - NIC Up   Loopback 10000000  MS TCP Loopback interface

Sem iPhone conectado:

DEBUG - NIC Up   Ethernet 10000000   444553544200 Nortel IPSECSHM Adapter - Packet Scheduler Miniport
DEBUG - NIC Down Ethernet 54000000   00166FAC94C7 Intel(R) PRO/Wireless 2200BG Network Connection - Packet Scheduler Miniport
DEBUG - NIC Down Ethernet 1000000000 0016D326E957 Broadcom NetXtreme Gigabit Ethernet - Packet Scheduler Miniport
DEBUG - NIC Up   Loopback 10000000  MS TCP Loopback interface
Foi útil?

Solução

Este é o meu método: ele usa o fato de que o cartão físico está conectado à interface PCI

ManagementObjectSearcher searcher = new ManagementObjectSearcher
    ("Select MACAddress,PNPDeviceID FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL AND PNPDeviceID IS NOT NULL");
ManagementObjectCollection mObject = searcher.Get();

foreach (ManagementObject obj in mObject)
{
    string pnp = obj["PNPDeviceID"].ToString();
    if (pnp.Contains("PCI\\"))
    {
        string mac = obj["MACAddress"].ToString();
        mac = mac.Replace(":", string.Empty);
        return mac;
    }
}

Outras dicas

Os três primeiros bytes do endereço MAC são um ID do fabricante. Você pode ser uma lista negra de certos IDs do fabricante conhecidos por serem inadequados para seus propósitos e ignorar essas interfaces.

Não é provável que confiar na velocidade não seja uma boa ideia, porque não há razão para que uma interface VPN não possa se denunciar como tendo velocidade de gigabit.

Os endereços MAC são endereços de hardware físico. Não posso testar neste PC, mas acho que você não receberá um novo endereço MAC se uma conexão virtual for adicionada porque não é uma peça de hardware real. Será outra conexão, mas não outro endereço MAC.

Portanto, garantir que você obtenha o mesmo endereço MAC toda vez que depende das mesmas peças de hardware que estão sendo anexadas à máquina e você usando o mesmo algoritmo para escolher desse hardware.

Também tenho analisado esse problema e acredito que, sem estado persistente, será difícil manter um Mac estável.

A solução com a qual estou brincando é pegar a primeira NIC encontrada na ordem do adaptador e usar isso e salve. Em seguida, nas gerações subsequentes UUID, use o Mac salvo se for encontrado em qualquer lugar da pilha, mesmo que não seja a primeira. Dessa forma, a ordem do adaptador pode se mover e não nos preocupamos em explodir o que depende do Mac estável (como um módulo de licenciamento).

Se o Mac salvo não for encontrado na pilha, ela será descartada e nós apenas usamos o primeiro Mac na ordem de ligação e comece de novo.

 public static string GetMacAddressPhysicalNetworkInterface()
    {

        ManagementObjectSearcher searcher = new ManagementObjectSearcher
        ("Select MACAddress,PNPDeviceID FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL AND" +
         " PNPDeviceID IS NOT NULL AND" +
         " PhysicalAdapter = true");
        ManagementObjectCollection mObject = searcher.Get();

        string macs = (from ManagementObject obj in mObject
                let pnp = obj["PNPDeviceID"].ToString()
                where !(pnp.Contains("ROOT\\"))
                //where  pnp.Contains("PCI\\")  || pnp.Contains("USB\\")
                select obj).Select(obj => obj["MACAddress"].ToString())
            .Aggregate<string, string>(null, (mac, currentMac) => mac + currentMac.Replace(":", string.Empty) + ",");

        return !string.IsNullOrEmpty(macs) ? macs.Substring(0, macs.Length - 1) : macs;
    }

    public static NetworkInterface GetPhysicalNetworkInterface(string macAddressPhysicalNetworkInterface)
    {
        return NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault(currentNetworkInterface => string.Equals(currentNetworkInterface.GetPhysicalAddress().ToString(), macAddressPhysicalNetworkInterface, StringComparison.CurrentCultureIgnoreCase));
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top