Как определить MAC-адрес реальной физической сетевой карты, а не виртуальных сетевых интерфейсов, созданных VPN (.NET C #)
-
21-09-2019 - |
Вопрос
Предыстория
Я пытаюсь получить уникальный идентификатор с компьютера и хочу иметь возможность каждый раз надежно возвращать один и тот же MAC-адрес.Поверьте мне, у меня есть свои причины использовать MAC-адрес, и я прочитал много сообщений об альтернативных методах уникального идентификатора (и да, я рассматривал, нет ли у них сетевых карт).
Проблема
Проблема в .NET, я все равно не вижу способа определить, является ли конкретный сетевой интерфейс физической аппаратной сетевой картой из чего-то вроде "минипорта Nortel IPSECSHM Adapter - Packet Scheduler", который добавляется при подключении к определенным VPN или сетям WiFi.
Я знаю, как получить Mac-адреса, используя код, подобный этому:
foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
{
log.Debug("NIC " + nic.OperationalStatus + " " + nic.NetworkInterfaceType + " " + nic.Speed + " " + nic.GetPhysicalAddress() + " " + nic.Description);
}
Понятно, что нет 100% способа убедиться, что я получу внутреннюю сетевую карту, но я хотел бы выбрать MAC-адрес для возврата, который для данной машины с наименьшей вероятностью изменится.Независимо от таких факторов, как - подключен ли он к Wi-Fi...подключается через какой-либо тип тросового соединения...или они устанавливают какое-то новое программное обеспечение vpn, которое добавляет новый интерфейс.
Рассмотренные стратегии
1) Выберите первый интерфейс, который находится "Наверху".Это не удается на моем ноутбуке, потому что "Минипорт пакета" всегда включен.Кроме того, если я привязываю свой телефон к ноутбуку, это также отображается как первая карта.
2) Выберите наиболее подходящий тип...Это не удается, потому что в основном все отображается как "Ethernet", включая адаптеры Wi-Fi и подключение к Интернету для моего iPhone.
3) Выберите сетевую карту, у которой есть IP-адрес.Терпит неудачу по нескольким причинам:1) Сетевая карта может быть не подключена к локальной сети 2) Существует несколько сетевых адаптеров, которые могут иметь IP-адреса.
4) Просто отправьте все MAC-адреса...Проблема в том, что список будет меняться в зависимости от установленного программного обеспечения, и его будет трудно сравнить.
5) Выберите mac-адрес с максимально высокой скоростью.Я думаю, что это, вероятно, мой лучший выбор.Я думаю, можно с уверенностью сказать, что самый быстрый интерфейс обычно будет самым постоянным.
В качестве альтернативы, может существовать какой-то другой способ обнаружения физических карт в .NET, или я бы рассмотрел возможность вызова других вызовов 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-адреса - это идентификатор производителя.Вы могли бы занести в черный список определенные идентификаторы производителя, которые, как известно, не подходят для ваших целей, и игнорировать эти интерфейсы.
Полагаться на скорость вряд ли будет хорошей идеей, потому что нет никаких причин, по которым интерфейс VPN не мог бы сообщить о себе как о имеющем гигабитную скорость.
MAC-адреса - это физические аппаратные адреса.Я не могу протестировать на этом компьютере, но я не думаю, что вы получите новый MAC-адрес, если будет добавлено виртуальное соединение, потому что это не реальное аппаратное обеспечение.Это будет другое соединение, но не другой MAC-адрес.
Таким образом, гарантия того, что вы каждый раз получаете один и тот же MAC-адрес, зависит от того, что к компьютеру подключены одни и те же аппаратные средства и вы используете один и тот же алгоритм для выбора из этого оборудования.
Я также рассматривал эту проблему и считаю, что без постоянного состояния будет трудно поддерживать стабильный MAC.
Решение, с которым я играю, - это взять первый сетевой адаптер, найденный в заказе адаптеров, и использовать его и сохрани это.Затем при последующих поколениях 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<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));
}