如何确定实际物理网卡的MAC地址 - 而不是VPN创建的虚拟网络接口(.NET C#)

时间:2009-10-14 16:13:04

标签: c# .net networking uniqueidentifier mac-address

背景

我正在尝试从计算机中获取唯一标识符,并希望每次都可以可靠地返回相同的MAC地址。相信我,我有使用MAC地址的原因,并阅读了许多关于备用唯一ID方法的帖子(是的,如果他们没有任何网卡,我会考虑)。

问题

问题出在.NET中我无论如何都不知道特定的NetworkInterface是否是来自“Nortel IPSECSHM适配器 - 数据包调度程序微型端口”的物理硬件网卡,当您连接到某些VPN或WiFi网络。

我知道如何使用与此类似的代码获取Mac地址:

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

可以理解的是,没有100%的方法可以确保我获得内部网卡,但是我想选择MAC地址来返回哪个最不可能改变的给定机器。独立于诸如以下因素 - 无论是否连接到wifi ...通过某种类型的系绳连接进行连接......或者他们安装了一些新的vpn软件,增加了新的界面。

考虑的策略

1)选择第一个“Up”界面。这在我的笔记本电脑上失败了,因为“Packet Miniport”总是在运行。此外,如果我将手机连接到笔记本电脑,这也会显示为第一张卡。

2)选择最合适的类型......这个失败b / c基本上所有东西都显示为“以太网”,包括WiFi适配器和我的iPHone网络连接。

3)选择具有IP地址的NIC。由于以下几个原因导致失败:1)网卡可能未连接到LAN 2)有多个可能有IP地址的网卡。

4)只需发送所有MAC地址......问题是列表会根据安装的软件而改变,并且很难比较。

5)以最快的速度选择mac地址。我想这可能是我最好的选择。我认为可以说最快的界面通常是最永久的。

或者,可能还有其他方法可以检测.NET中的物理卡,或者如果您可以推荐一个提供不同信息的API调用,我会考虑调用其他API调用。

还有其他想法吗?

这里演示的是当我的iPhone连接时上面的示例代码的输出:

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

没有Iphone连接:

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

5 个答案:

答案 0 :(得分:12)

这是我的方法: 它使用物理卡连接到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;
    }
}

答案 1 :(得分:2)

MAC地址的前三个字节是制造商ID。您可以将已知不适合您的某些制造商ID列入黑名单,并忽略这些接口。

依靠速度不太可能是一个好主意,因为没有理由说VPN接口无法将自己报告为具有千兆位速度。

答案 2 :(得分:0)

MAC地址是物理硬件地址。我无法在这台电脑上进行测试,但如果添加虚拟连接,我认为你不会得到新的MAC地址,因为它不是真正的硬件。它将是另一个连接,但不是另一个MAC地址。

因此,保证每次都获得相同的MAC地址取决于连接到机器的相同硬件,并使用相同的算法从该硬件中选择。

答案 3 :(得分:0)

我一直在关注这个问题,并且相信如果没有持久状态,维持稳定的MAC将会很困难。

我正在使用的解决方案是使用适配器顺序中找到的第一个NIC并使用并保存。然后在随后的UUID代中,如果在堆栈中的任何位置找到它,则使用保存的MAC,即使不是第一个。通过这种方式,适配器顺序可以四处移动,我们也不用担心会因为稳定的MAC(例如许可模块)而发生任何问题。

如果在堆栈中找不到保存的MAC,它将被丢弃,我们只需使用绑定顺序中的第一个MAC并重新开始。

答案 4 :(得分:0)

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