Как определить MAC-адрес фактической физической сетевой карты - не виртуальные сетевые интерфейсы, созданные VPN (.NET С#)
Фон
Я пытаюсь получить уникальный идентификатор из компьютера и хочу иметь возможность надежно возвращать один и тот же MAC-адрес каждый раз. Поверьте мне, у меня есть причины использовать MAC-адрес и прочитали много сообщений об альтернативных уникальных методах id (и да, я подумал, нет ли у них сетевых карт).
Проблема
Проблема в .NET. Я не вижу в любом случае, чтобы определить, является ли конкретная NetworkInterface физическая аппаратная сетевая карта от чего-то вроде "Nortel IPSECSHM Adapter - Miniport 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) Выберите первый интерфейс "Вверх". Это не удается на моем ноутбуке, потому что "Packet Miniport" всегда вверх. Кроме того, если я привяжу свой телефон к своему ноутбуку, это также отобразится как первая карта.
2) Выберите наиболее подходящий тип... Это не работает b/c, в основном все отображается как "Ethernet", включая адаптеры WiFi и модемное подключение к 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
Ответы
Ответ 1
Это мой метод:
он использует тот факт, что физическая карта подключена к интерфейсу 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;
}
}
Ответ 2
Первые три байта MAC-адреса являются идентификатором производителя. Вы можете использовать черный список определенных идентификаторов производителей, которые, как известно, непригодны для ваших целей, и игнорировать эти интерфейсы.
Опора на скорость вряд ли будет хорошей идеей, потому что нет никакой причины, по которой интерфейс VPN не мог бы сообщить о себе как о гигабитной скорости.
Ответ 3
MAC-адреса - это физические аппаратные адреса. Я не могу протестировать этот компьютер, но я не думаю, что вы получите новый MAC-адрес, если добавлено виртуальное соединение, потому что оно не является фактическим аппаратным обеспечением. Это будет другое соединение, но не другой MAC-адрес.
Таким образом, гарантируя, что вы получаете один и тот же MAC-адрес, каждый раз зависит от того, какие аппаратные средства подключаются к аппарату, и вы используете тот же алгоритм для выбора из этого оборудования.
Ответ 4
Я тоже рассматривал эту проблему и считаю, что без постоянного состояния будет трудно поддерживать стабильный MAC.
Решение, с которым я работаю, - это взять первый сетевой адаптер, указанный в заказе адаптера, и использовать его и сохранить. Затем в последующих поколениях UUID используйте сохраненный MAC, если он найден в любом месте стека, даже если не первый. Таким образом, заказ адаптера может перемещаться, и мы не беспокоимся о том, чтобы взорвать все, что зависит от стабильного MAC (например, модуля лицензирования).
Если сохраненный MAC не найден в стеке, он отбрасывается, и мы просто используем первый MAC в порядке привязки и начинаем.
Ответ 5
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));
}