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

背景

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

问题

问题出在.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 

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

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

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

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

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

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

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

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

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