1、 常见虚拟网卡MAC (first 6 characters)
"00:05:69"; // vmware 1
"00:0C:29"; // vmware 2
"00:50:56"; // vmware 3
"00:1C:14"; // vmware 4
"00:1C:42"; // parallels 1
"00:03:FF"; // microsoft virtual pc
"00:0F:4B"; // virtual iron 4
"00:16:3E"; // red hat xen, oracle vm, xen source, novell xen
"08:00:27"; // virtualbox
2、 coffer.com/mac_find/ 的 17 个 virtual MAC prefix
http://coffer.com/mac_find/?string=virtual
Prefix Vendor
------ ----------------------------------------------------
000F4B Virtual Iron Software, Inc. (was: Katana Technology)
001307 Paravirtual Corporation (was: Accenia, Inc.)
0013BE Virtual Conexions
0021F6 Virtual Iron Software
00240B Virtual Computer Inc.
00A0B1 First Virtual Corporation
00E0C8 virtual access, ltd.
545200 linux kernal virtual machine (kvm)
000F4B Virtual Iron Software, Inc. (was: Katana Technology)
001307 Paravirtual Corporation (was: Accenia, Inc.)
0013BE Virtual Conexions
0021F6 Oracle Corporation (was: Virtual Iron Software)
00240B Virtual Computer Inc.
00A0B1 First Virtual Corporation
00E0C8 virtual access, ltd.
18922C Virtual Instruments
3CF392 Virtualtek. Co. Ltd
3、github 一个关于虚拟网卡分类的接口实现
https://github.com/LeMaker/android-actions/blob/6960890188f877ee2cd5d6dbf52b7de25be64085/android/external/chromium_org/chrome/browser/prefs/tracked/pref_hash_calculator_helper_win.cc
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/prefs/tracked/pref_hash_calculator_helper.h"
// Implementation fully duplicated from
// chrome/browser/extensions/api/music_manager_private/device_id_win.cc (see
// pref_hash_calculator_helper_win.h for motivation).
// Note: The order of header includes is important, as we want both pre-Vista
// and post-Vista data structures to be defined, specifically
// PIP_ADAPTER_ADDRESSES and PMIB_IF_ROW2.
#include <winsock2.h>
#include <ws2def.h>
#include <ws2ipdef.h>
#include <iphlpapi.h>
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/scoped_native_library.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "net/base/net_util.h"
namespace {
bool IsValidMacAddress(const void* bytes, size_t size) {
const size_t MAC_LENGTH = 6;
const size_t OUI_LENGTH = 3;
struct InvalidMacEntry {
size_t size;
unsigned char address[MAC_LENGTH];
};
// VPN, virtualization, tethering, bluetooth, etc.
static const InvalidMacEntry kInvalidAddresses[] = {
// Empty address
{MAC_LENGTH, {0, 0, 0, 0, 0, 0}},
// VMware
{OUI_LENGTH, {0x00, 0x50, 0x56}},
{OUI_LENGTH, {0x00, 0x05, 0x69}},
{OUI_LENGTH, {0x00, 0x0c, 0x29}},
{OUI_LENGTH, {0x00, 0x1c, 0x14}},
// VirtualBox
{OUI_LENGTH, {0x08, 0x00, 0x27}},
// PdaNet
{MAC_LENGTH, {0x00, 0x26, 0x37, 0xbd, 0x39, 0x42}},
// Cisco AnyConnect VPN
{MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
// Marvell sometimes uses this as a dummy address
{MAC_LENGTH, {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
// Apple uses this across machines for Bluetooth ethernet adapters.
{MAC_LENGTH-1, {0x65, 0x90, 0x07, 0x42, 0xf1}},
// Juniper uses this for their Virtual Adapter, the other 4 bytes are
// reassigned at every boot. 00-ff-xx is not assigned to anyone.
{2, {0x00, 0xff}},
// T-Mobile Wireless Ethernet
{MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
// Generic Bluetooth device
{MAC_LENGTH, {0x00, 0x15, 0x83, 0x3d, 0x0a, 0x57}},
// RAS Async Adapter
{MAC_LENGTH, {0x20, 0x41, 0x53, 0x59, 0x4e, 0xff}},
// Qualcomm USB ethernet adapter
{MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
// Windows VPN
{MAC_LENGTH, {0x00, 0x53, 0x45, 0x00, 0x00, 0x00}},
// Bluetooth
{MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x08, 0x30}},
{MAC_LENGTH, {0x00, 0x1b, 0x10, 0x00, 0x2a, 0xec}},
{MAC_LENGTH, {0x00, 0x15, 0x83, 0x15, 0xa3, 0x10}},
{MAC_LENGTH, {0x00, 0x15, 0x83, 0x07, 0xC6, 0x5A}},
{MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0x00}},
{MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0xdd}},
// Ceton TV tuner
{MAC_LENGTH, {0x00, 0x22, 0x2c, 0xff, 0xff, 0xff}},
// Check Point VPN
{MAC_LENGTH, {0x54, 0x55, 0x43, 0x44, 0x52, 0x09}},
{MAC_LENGTH, {0x54, 0xEF, 0x14, 0x71, 0xE4, 0x0E}},
{MAC_LENGTH, {0x54, 0xBA, 0xC6, 0xFF, 0x74, 0x10}},
// Cisco VPN
{MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
// Cisco VPN
{MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x78, 0x00}},
// Intel USB cell modem
{MAC_LENGTH, {0x00, 0x1e, 0x10, 0x1f, 0x00, 0x01}},
// Microsoft tethering
{MAC_LENGTH, {0x80, 0x00, 0x60, 0x0f, 0xe8, 0x00}},
// Nortel VPN
{MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x42, 0x00}},
// AEP VPN
{MAC_LENGTH, {0x00, 0x30, 0x70, 0x00, 0x00, 0x01}},
// Positive VPN
{MAC_LENGTH, {0x00, 0x02, 0x03, 0x04, 0x05, 0x06}},
// Bluetooth
{MAC_LENGTH, {0x00, 0x15, 0x83, 0x0B, 0x13, 0xC0}},
// Kerio Virtual Network Adapter
{MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x4f, 0x53}},
// Sierra Wireless cell modems.
{OUI_LENGTH, {0x00, 0xA0, 0xD5}},
// FRITZ!web DSL
{MAC_LENGTH, {0x00, 0x04, 0x0E, 0xFF, 0xFF, 0xFF}},
// VirtualPC
{MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
// Bluetooth
{MAC_LENGTH, {0x00, 0x1F, 0x81, 0x00, 0x01, 0x00}},
{MAC_LENGTH, {0x00, 0x30, 0x91, 0x10, 0x00, 0x26}},
{MAC_LENGTH, {0x00, 0x25, 0x00, 0x5A, 0xC3, 0xD0}},
{MAC_LENGTH, {0x00, 0x15, 0x83, 0x0C, 0xBF, 0xEB}},
// Huawei cell modem
{MAC_LENGTH, {0x58, 0x2C, 0x80, 0x13, 0x92, 0x63}},
// Fortinet VPN
{OUI_LENGTH, {0x00, 0x09, 0x0F}},
// Realtek
{MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x30}},
// Other rare dupes.
{MAC_LENGTH, {0x00, 0x11, 0xf5, 0x0d, 0x8a, 0xe8}}, // Atheros
{MAC_LENGTH, {0x00, 0x20, 0x07, 0x01, 0x16, 0x06}}, // Atheros
{MAC_LENGTH, {0x0d, 0x0b, 0x00, 0x00, 0xe0, 0x00}}, // Atheros
{MAC_LENGTH, {0x90, 0x4c, 0xe5, 0x0b, 0xc8, 0x8e}}, // Atheros
{MAC_LENGTH, {0x00, 0x1c, 0x23, 0x38, 0x49, 0xa4}}, // Broadcom
{MAC_LENGTH, {0x00, 0x12, 0x3f, 0x82, 0x7c, 0x32}}, // Broadcom
{MAC_LENGTH, {0x00, 0x11, 0x11, 0x32, 0xc3, 0x77}}, // Broadcom
{MAC_LENGTH, {0x00, 0x24, 0xd6, 0xae, 0x3e, 0x39}}, // Microsoft
{MAC_LENGTH, {0x00, 0x0f, 0xb0, 0x3a, 0xb4, 0x80}}, // Realtek
{MAC_LENGTH, {0x08, 0x10, 0x74, 0xa1, 0xda, 0x1b}}, // Realtek
{MAC_LENGTH, {0x00, 0x21, 0x9b, 0x2a, 0x0a, 0x9c}}, // Realtek
};
if (size != MAC_LENGTH) {
return false;
}
if (static_cast<const unsigned char *>(bytes)[0] & 0x02) {
// Locally administered.
return false;
}
// Note: Use ARRAYSIZE_UNSAFE() instead of arraysize() because InvalidMacEntry
// is declared inside this function.
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidAddresses); ++i) {
size_t count = kInvalidAddresses[i].size;
if (memcmp(kInvalidAddresses[i].address, bytes, count) == 0) {
return false;
}
}
return true;
}
class MacAddressProcessor {
public:
MacAddressProcessor() : found_index_(ULONG_MAX) {}
// Iterate through the interfaces, looking for the valid MAC address with the
// lowest IfIndex.
void ProcessAdapterAddress(PIP_ADAPTER_ADDRESSES address) {
if (address->IfType == IF_TYPE_TUNNEL)
return;
ProcessPhysicalAddress(address->IfIndex,
address->PhysicalAddress,
address->PhysicalAddressLength);
}
void ProcessInterfaceRow(const PMIB_IF_ROW2 row) {
if (row->Type == IF_TYPE_TUNNEL ||
!row->InterfaceAndOperStatusFlags.HardwareInterface) {
return;
}
ProcessPhysicalAddress(row->InterfaceIndex,
row->PhysicalAddress,
row->PhysicalAddressLength);
}
std::string mac_address() const { return found_mac_address_; }
private:
void ProcessPhysicalAddress(NET_IFINDEX index,
const void* bytes,
size_t size) {
if (index >= found_index_ || size == 0)
return;
if (!IsValidMacAddress(bytes, size))
return;
found_mac_address_ = StringToLowerASCII(base::HexEncode(bytes, size));
found_index_ = index;
}
std::string found_mac_address_;
NET_IFINDEX found_index_;
};
std::string GetMacAddressFromGetAdaptersAddresses() {
base::ThreadRestrictions::AssertIOAllowed();
// MS recommends a default size of 15k.
ULONG bufferSize = 15 * 1024;
// Disable as much as we can, since all we want is MAC addresses.
ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_UNICAST;
std::vector<unsigned char> buffer(bufferSize);
PIP_ADAPTER_ADDRESSES adapterAddresses =
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
DWORD result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
adapterAddresses, &bufferSize);
if (result == ERROR_BUFFER_OVERFLOW) {
buffer.resize(bufferSize);
adapterAddresses =
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
adapterAddresses, &bufferSize);
}
if (result != NO_ERROR) {
VLOG(ERROR) << "GetAdapatersAddresses failed with error " << result;
return "";
}
MacAddressProcessor processor;
for (; adapterAddresses != NULL; adapterAddresses = adapterAddresses->Next) {
processor.ProcessAdapterAddress(adapterAddresses);
}
return processor.mac_address();
}
std::string GetMacAddressFromGetIfTable2() {
base::ThreadRestrictions::AssertIOAllowed();
// This is available on Vista+ only.
base::ScopedNativeLibrary library(base::FilePath(L"Iphlpapi.dll"));
typedef DWORD (NETIOAPI_API_ *GetIfTablePtr)(PMIB_IF_TABLE2*);
typedef void (NETIOAPI_API_ *FreeMibTablePtr)(PMIB_IF_TABLE2);
GetIfTablePtr getIfTable = reinterpret_cast<GetIfTablePtr>(
library.GetFunctionPointer("GetIfTable2"));
FreeMibTablePtr freeMibTablePtr = reinterpret_cast<FreeMibTablePtr>(
library.GetFunctionPointer("FreeMibTable"));
if (getIfTable == NULL || freeMibTablePtr == NULL) {
VLOG(ERROR) << "Could not get proc addresses for machine identifier.";
return "";
}
PMIB_IF_TABLE2 ifTable = NULL;
DWORD result = getIfTable(&ifTable);
if (result != NO_ERROR || ifTable == NULL) {
VLOG(ERROR) << "GetIfTable failed with error " << result;
return "";
}
MacAddressProcessor processor;
for (size_t i = 0; i < ifTable->NumEntries; i++) {
processor.ProcessInterfaceRow(&(ifTable->Table[i]));
}
if (ifTable != NULL) {
freeMibTablePtr(ifTable);
ifTable = NULL;
}
return processor.mac_address();
}
} // namespace
// Returns the legacy device ID which was used involuntarily to generate hashes
// in M33 (crbug.com/350028). The algorithm to compute the legacy device ID was
// duplicated from the Windows implementation of GetRawDeviceId() inside
// extensions::api::GetDeviceId() for M33 where it originated from. It was
// deemed undesirable to move the code to a common path for re-use in this code
// as GetLegacyDeviceId() is meant to forever reproduce the ID that was
// generated on M33 and shouldn't otherwise evolve with the implementation of
// extensions::api::GetDeviceId() on trunk.
// TODO(gab): Delete this method when the vast majority of the population has
// migrated over to hashes based on the modern ID.
std::string GetLegacyDeviceId(const std::string& modern_device_id) {
base::ThreadRestrictions::AssertIOAllowed();
// Just as in extensions::api::GetMacAddressCallback(), return the
// concatenation of |mac_address| and |modern_device_id|. Return the empty
// string if either of them is empty.
if (modern_device_id.empty())
return std::string();
// Get MAC address as in extensions::api::GetMacAddressCallback(): prefering
// GetMacAddressFromGetAdaptersAddresses() over
// GetMacAddressFromGetIfTable2() if the former can find a valid MAC address.
std::string mac_address = GetMacAddressFromGetAdaptersAddresses();
if (mac_address.empty()) {
mac_address = GetMacAddressFromGetIfTable2();
if (mac_address.empty())
return std::string();
}
return mac_address + modern_device_id;
}