1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/prefs/tracked/pref_hash_calculator_helper.h"
7 // Implementation fully duplicated from
8 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc (see
9 // pref_hash_calculator_helper_win.h for motivation).
11 // Note: The order of header includes is important, as we want both pre-Vista
12 // and post-Vista data structures to be defined, specifically
13 // PIP_ADAPTER_ADDRESSES and PMIB_IF_ROW2.
19 #include "base/files/file_path.h"
20 #include "base/logging.h"
21 #include "base/macros.h"
22 #include "base/scoped_native_library.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_util.h"
25 #include "base/threading/thread_restrictions.h"
26 #include "net/base/net_util.h"
30 bool IsValidMacAddress(const void* bytes
, size_t size
) {
31 const size_t MAC_LENGTH
= 6;
32 const size_t OUI_LENGTH
= 3;
33 struct InvalidMacEntry
{
35 unsigned char address
[MAC_LENGTH
];
38 // VPN, virtualization, tethering, bluetooth, etc.
39 static const InvalidMacEntry kInvalidAddresses
[] = {
41 {MAC_LENGTH
, {0, 0, 0, 0, 0, 0}},
43 {OUI_LENGTH
, {0x00, 0x50, 0x56}},
44 {OUI_LENGTH
, {0x00, 0x05, 0x69}},
45 {OUI_LENGTH
, {0x00, 0x0c, 0x29}},
46 {OUI_LENGTH
, {0x00, 0x1c, 0x14}},
48 {OUI_LENGTH
, {0x08, 0x00, 0x27}},
50 {MAC_LENGTH
, {0x00, 0x26, 0x37, 0xbd, 0x39, 0x42}},
51 // Cisco AnyConnect VPN
52 {MAC_LENGTH
, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
53 // Marvell sometimes uses this as a dummy address
54 {MAC_LENGTH
, {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
55 // Apple uses this across machines for Bluetooth ethernet adapters.
56 {MAC_LENGTH
-1, {0x65, 0x90, 0x07, 0x42, 0xf1}},
57 // Juniper uses this for their Virtual Adapter, the other 4 bytes are
58 // reassigned at every boot. 00-ff-xx is not assigned to anyone.
60 // T-Mobile Wireless Ethernet
61 {MAC_LENGTH
, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
62 // Generic Bluetooth device
63 {MAC_LENGTH
, {0x00, 0x15, 0x83, 0x3d, 0x0a, 0x57}},
65 {MAC_LENGTH
, {0x20, 0x41, 0x53, 0x59, 0x4e, 0xff}},
66 // Qualcomm USB ethernet adapter
67 {MAC_LENGTH
, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
69 {MAC_LENGTH
, {0x00, 0x53, 0x45, 0x00, 0x00, 0x00}},
71 {MAC_LENGTH
, {0x00, 0x1f, 0x81, 0x00, 0x08, 0x30}},
72 {MAC_LENGTH
, {0x00, 0x1b, 0x10, 0x00, 0x2a, 0xec}},
73 {MAC_LENGTH
, {0x00, 0x15, 0x83, 0x15, 0xa3, 0x10}},
74 {MAC_LENGTH
, {0x00, 0x15, 0x83, 0x07, 0xC6, 0x5A}},
75 {MAC_LENGTH
, {0x00, 0x1f, 0x81, 0x00, 0x02, 0x00}},
76 {MAC_LENGTH
, {0x00, 0x1f, 0x81, 0x00, 0x02, 0xdd}},
78 {MAC_LENGTH
, {0x00, 0x22, 0x2c, 0xff, 0xff, 0xff}},
80 {MAC_LENGTH
, {0x54, 0x55, 0x43, 0x44, 0x52, 0x09}},
81 {MAC_LENGTH
, {0x54, 0xEF, 0x14, 0x71, 0xE4, 0x0E}},
82 {MAC_LENGTH
, {0x54, 0xBA, 0xC6, 0xFF, 0x74, 0x10}},
84 {MAC_LENGTH
, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
86 {MAC_LENGTH
, {0x00, 0x05, 0x9a, 0x3c, 0x78, 0x00}},
87 // Intel USB cell modem
88 {MAC_LENGTH
, {0x00, 0x1e, 0x10, 0x1f, 0x00, 0x01}},
89 // Microsoft tethering
90 {MAC_LENGTH
, {0x80, 0x00, 0x60, 0x0f, 0xe8, 0x00}},
92 {MAC_LENGTH
, {0x44, 0x45, 0x53, 0x54, 0x42, 0x00}},
94 {MAC_LENGTH
, {0x00, 0x30, 0x70, 0x00, 0x00, 0x01}},
96 {MAC_LENGTH
, {0x00, 0x02, 0x03, 0x04, 0x05, 0x06}},
98 {MAC_LENGTH
, {0x00, 0x15, 0x83, 0x0B, 0x13, 0xC0}},
99 // Kerio Virtual Network Adapter
100 {MAC_LENGTH
, {0x44, 0x45, 0x53, 0x54, 0x4f, 0x53}},
101 // Sierra Wireless cell modems.
102 {OUI_LENGTH
, {0x00, 0xA0, 0xD5}},
104 {MAC_LENGTH
, {0x00, 0x04, 0x0E, 0xFF, 0xFF, 0xFF}},
106 {MAC_LENGTH
, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
108 {MAC_LENGTH
, {0x00, 0x1F, 0x81, 0x00, 0x01, 0x00}},
109 {MAC_LENGTH
, {0x00, 0x30, 0x91, 0x10, 0x00, 0x26}},
110 {MAC_LENGTH
, {0x00, 0x25, 0x00, 0x5A, 0xC3, 0xD0}},
111 {MAC_LENGTH
, {0x00, 0x15, 0x83, 0x0C, 0xBF, 0xEB}},
113 {MAC_LENGTH
, {0x58, 0x2C, 0x80, 0x13, 0x92, 0x63}},
115 {OUI_LENGTH
, {0x00, 0x09, 0x0F}},
117 {MAC_LENGTH
, {0x00, 0x00, 0x00, 0x00, 0x00, 0x30}},
119 {MAC_LENGTH
, {0x00, 0x11, 0xf5, 0x0d, 0x8a, 0xe8}}, // Atheros
120 {MAC_LENGTH
, {0x00, 0x20, 0x07, 0x01, 0x16, 0x06}}, // Atheros
121 {MAC_LENGTH
, {0x0d, 0x0b, 0x00, 0x00, 0xe0, 0x00}}, // Atheros
122 {MAC_LENGTH
, {0x90, 0x4c, 0xe5, 0x0b, 0xc8, 0x8e}}, // Atheros
123 {MAC_LENGTH
, {0x00, 0x1c, 0x23, 0x38, 0x49, 0xa4}}, // Broadcom
124 {MAC_LENGTH
, {0x00, 0x12, 0x3f, 0x82, 0x7c, 0x32}}, // Broadcom
125 {MAC_LENGTH
, {0x00, 0x11, 0x11, 0x32, 0xc3, 0x77}}, // Broadcom
126 {MAC_LENGTH
, {0x00, 0x24, 0xd6, 0xae, 0x3e, 0x39}}, // Microsoft
127 {MAC_LENGTH
, {0x00, 0x0f, 0xb0, 0x3a, 0xb4, 0x80}}, // Realtek
128 {MAC_LENGTH
, {0x08, 0x10, 0x74, 0xa1, 0xda, 0x1b}}, // Realtek
129 {MAC_LENGTH
, {0x00, 0x21, 0x9b, 0x2a, 0x0a, 0x9c}}, // Realtek
132 if (size
!= MAC_LENGTH
) {
136 if (static_cast<const unsigned char *>(bytes
)[0] & 0x02) {
137 // Locally administered.
141 // Note: Use ARRAYSIZE_UNSAFE() instead of arraysize() because InvalidMacEntry
142 // is declared inside this function.
143 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(kInvalidAddresses
); ++i
) {
144 size_t count
= kInvalidAddresses
[i
].size
;
145 if (memcmp(kInvalidAddresses
[i
].address
, bytes
, count
) == 0) {
152 class MacAddressProcessor
{
154 MacAddressProcessor() : found_index_(ULONG_MAX
) {}
156 // Iterate through the interfaces, looking for the valid MAC address with the
158 void ProcessAdapterAddress(PIP_ADAPTER_ADDRESSES address
) {
159 if (address
->IfType
== IF_TYPE_TUNNEL
)
162 ProcessPhysicalAddress(address
->IfIndex
,
163 address
->PhysicalAddress
,
164 address
->PhysicalAddressLength
);
167 void ProcessInterfaceRow(const PMIB_IF_ROW2 row
) {
168 if (row
->Type
== IF_TYPE_TUNNEL
||
169 !row
->InterfaceAndOperStatusFlags
.HardwareInterface
) {
173 ProcessPhysicalAddress(row
->InterfaceIndex
,
174 row
->PhysicalAddress
,
175 row
->PhysicalAddressLength
);
178 std::string
mac_address() const { return found_mac_address_
; }
181 void ProcessPhysicalAddress(NET_IFINDEX index
,
184 if (index
>= found_index_
|| size
== 0)
187 if (!IsValidMacAddress(bytes
, size
))
190 found_mac_address_
= StringToLowerASCII(base::HexEncode(bytes
, size
));
191 found_index_
= index
;
194 std::string found_mac_address_
;
195 NET_IFINDEX found_index_
;
198 std::string
GetMacAddressFromGetAdaptersAddresses() {
199 base::ThreadRestrictions::AssertIOAllowed();
201 // MS recommends a default size of 15k.
202 ULONG bufferSize
= 15 * 1024;
203 // Disable as much as we can, since all we want is MAC addresses.
204 ULONG flags
= GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_DNS_SERVER
|
205 GAA_FLAG_SKIP_FRIENDLY_NAME
| GAA_FLAG_SKIP_MULTICAST
|
206 GAA_FLAG_SKIP_UNICAST
;
207 std::vector
<unsigned char> buffer(bufferSize
);
208 PIP_ADAPTER_ADDRESSES adapterAddresses
=
209 reinterpret_cast<PIP_ADAPTER_ADDRESSES
>(&buffer
.front());
211 DWORD result
= GetAdaptersAddresses(AF_UNSPEC
, flags
, 0,
212 adapterAddresses
, &bufferSize
);
213 if (result
== ERROR_BUFFER_OVERFLOW
) {
214 buffer
.resize(bufferSize
);
216 reinterpret_cast<PIP_ADAPTER_ADDRESSES
>(&buffer
.front());
217 result
= GetAdaptersAddresses(AF_UNSPEC
, flags
, 0,
218 adapterAddresses
, &bufferSize
);
221 if (result
!= NO_ERROR
) {
222 VLOG(ERROR
) << "GetAdapatersAddresses failed with error " << result
;
226 MacAddressProcessor processor
;
227 for (; adapterAddresses
!= NULL
; adapterAddresses
= adapterAddresses
->Next
) {
228 processor
.ProcessAdapterAddress(adapterAddresses
);
230 return processor
.mac_address();
233 std::string
GetMacAddressFromGetIfTable2() {
234 base::ThreadRestrictions::AssertIOAllowed();
236 // This is available on Vista+ only.
237 base::ScopedNativeLibrary
library(base::FilePath(L
"Iphlpapi.dll"));
239 typedef DWORD (NETIOAPI_API_
*GetIfTablePtr
)(PMIB_IF_TABLE2
*);
240 typedef void (NETIOAPI_API_
*FreeMibTablePtr
)(PMIB_IF_TABLE2
);
242 GetIfTablePtr getIfTable
= reinterpret_cast<GetIfTablePtr
>(
243 library
.GetFunctionPointer("GetIfTable2"));
244 FreeMibTablePtr freeMibTablePtr
= reinterpret_cast<FreeMibTablePtr
>(
245 library
.GetFunctionPointer("FreeMibTable"));
246 if (getIfTable
== NULL
|| freeMibTablePtr
== NULL
) {
247 VLOG(ERROR
) << "Could not get proc addresses for machine identifier.";
251 PMIB_IF_TABLE2 ifTable
= NULL
;
252 DWORD result
= getIfTable(&ifTable
);
253 if (result
!= NO_ERROR
|| ifTable
== NULL
) {
254 VLOG(ERROR
) << "GetIfTable failed with error " << result
;
258 MacAddressProcessor processor
;
259 for (size_t i
= 0; i
< ifTable
->NumEntries
; i
++) {
260 processor
.ProcessInterfaceRow(&(ifTable
->Table
[i
]));
263 if (ifTable
!= NULL
) {
264 freeMibTablePtr(ifTable
);
267 return processor
.mac_address();
272 // Returns the legacy device ID which was used involuntarily to generate hashes
273 // in M33 (crbug.com/350028). The algorithm to compute the legacy device ID was
274 // duplicated from the Windows implementation of GetRawDeviceId() inside
275 // extensions::api::GetDeviceId() for M33 where it originated from. It was
276 // deemed undesirable to move the code to a common path for re-use in this code
277 // as GetLegacyDeviceId() is meant to forever reproduce the ID that was
278 // generated on M33 and shouldn't otherwise evolve with the implementation of
279 // extensions::api::GetDeviceId() on trunk.
280 // TODO(gab): Delete this method when the vast majority of the population has
281 // migrated over to hashes based on the modern ID.
282 std::string
GetLegacyDeviceId(const std::string
& modern_device_id
) {
283 base::ThreadRestrictions::AssertIOAllowed();
285 // Just as in extensions::api::GetMacAddressCallback(), return the
286 // concatenation of |mac_address| and |modern_device_id|. Return the empty
287 // string if either of them is empty.
289 if (modern_device_id
.empty())
290 return std::string();
292 // Get MAC address as in extensions::api::GetMacAddressCallback(): prefering
293 // GetMacAddressFromGetAdaptersAddresses() over
294 // GetMacAddressFromGetIfTable2() if the former can find a valid MAC address.
295 std::string mac_address
= GetMacAddressFromGetAdaptersAddresses();
296 if (mac_address
.empty()) {
297 mac_address
= GetMacAddressFromGetIfTable2();
298 if (mac_address
.empty())
299 return std::string();
302 return mac_address
+ modern_device_id
;