Home | History | Annotate | Download | only in tracked
      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.
      4 
      5 #include "chrome/browser/prefs/tracked/pref_hash_calculator_helper.h"
      6 
      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).
     10 
     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.
     14 #include <winsock2.h>
     15 #include <ws2def.h>
     16 #include <ws2ipdef.h>
     17 #include <iphlpapi.h>
     18 
     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"
     27 
     28 namespace {
     29 
     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 {
     34       size_t size;
     35       unsigned char address[MAC_LENGTH];
     36   };
     37 
     38   // VPN, virtualization, tethering, bluetooth, etc.
     39   static const InvalidMacEntry kInvalidAddresses[] = {
     40     // Empty address
     41     {MAC_LENGTH, {0, 0, 0, 0, 0, 0}},
     42     // VMware
     43     {OUI_LENGTH, {0x00, 0x50, 0x56}},
     44     {OUI_LENGTH, {0x00, 0x05, 0x69}},
     45     {OUI_LENGTH, {0x00, 0x0c, 0x29}},
     46     {OUI_LENGTH, {0x00, 0x1c, 0x14}},
     47     // VirtualBox
     48     {OUI_LENGTH, {0x08, 0x00, 0x27}},
     49     // PdaNet
     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.
     59     {2, {0x00, 0xff}},
     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}},
     64     // RAS Async Adapter
     65     {MAC_LENGTH, {0x20, 0x41, 0x53, 0x59, 0x4e, 0xff}},
     66     // Qualcomm USB ethernet adapter
     67     {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}},
     68     // Windows VPN
     69     {MAC_LENGTH, {0x00, 0x53, 0x45, 0x00, 0x00, 0x00}},
     70     // Bluetooth
     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}},
     77     // Ceton TV tuner
     78     {MAC_LENGTH, {0x00, 0x22, 0x2c, 0xff, 0xff, 0xff}},
     79     // Check Point VPN
     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}},
     83     // Cisco VPN
     84     {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}},
     85     // Cisco VPN
     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}},
     91     // Nortel VPN
     92     {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x42, 0x00}},
     93     // AEP VPN
     94     {MAC_LENGTH, {0x00, 0x30, 0x70, 0x00, 0x00, 0x01}},
     95     // Positive VPN
     96     {MAC_LENGTH, {0x00, 0x02, 0x03, 0x04, 0x05, 0x06}},
     97     // Bluetooth
     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}},
    103     // FRITZ!web DSL
    104     {MAC_LENGTH, {0x00, 0x04, 0x0E, 0xFF, 0xFF, 0xFF}},
    105     // VirtualPC
    106     {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}},
    107     // Bluetooth
    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}},
    112     // Huawei cell modem
    113     {MAC_LENGTH, {0x58, 0x2C, 0x80, 0x13, 0x92, 0x63}},
    114     // Fortinet VPN
    115     {OUI_LENGTH, {0x00, 0x09, 0x0F}},
    116     // Realtek
    117     {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x30}},
    118     // Other rare dupes.
    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
    130   };
    131 
    132   if (size != MAC_LENGTH) {
    133     return false;
    134   }
    135 
    136   if (static_cast<const unsigned char *>(bytes)[0] & 0x02) {
    137     // Locally administered.
    138     return false;
    139   }
    140 
    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) {
    146         return false;
    147     }
    148   }
    149   return true;
    150 }
    151 
    152 class MacAddressProcessor {
    153  public:
    154   MacAddressProcessor() : found_index_(ULONG_MAX) {}
    155 
    156   // Iterate through the interfaces, looking for the valid MAC address with the
    157   // lowest IfIndex.
    158   void ProcessAdapterAddress(PIP_ADAPTER_ADDRESSES address) {
    159     if (address->IfType == IF_TYPE_TUNNEL)
    160       return;
    161 
    162     ProcessPhysicalAddress(address->IfIndex,
    163                            address->PhysicalAddress,
    164                            address->PhysicalAddressLength);
    165   }
    166 
    167   void ProcessInterfaceRow(const PMIB_IF_ROW2 row) {
    168     if (row->Type == IF_TYPE_TUNNEL ||
    169         !row->InterfaceAndOperStatusFlags.HardwareInterface) {
    170       return;
    171     }
    172 
    173     ProcessPhysicalAddress(row->InterfaceIndex,
    174                            row->PhysicalAddress,
    175                            row->PhysicalAddressLength);
    176   }
    177 
    178   std::string mac_address() const { return found_mac_address_; }
    179 
    180  private:
    181   void ProcessPhysicalAddress(NET_IFINDEX index,
    182                               const void* bytes,
    183                               size_t size) {
    184     if (index >= found_index_ || size == 0)
    185       return;
    186 
    187     if (!IsValidMacAddress(bytes, size))
    188       return;
    189 
    190     found_mac_address_ = StringToLowerASCII(base::HexEncode(bytes, size));
    191     found_index_ = index;
    192   }
    193 
    194   std::string found_mac_address_;
    195   NET_IFINDEX found_index_;
    196 };
    197 
    198 std::string GetMacAddressFromGetAdaptersAddresses() {
    199   base::ThreadRestrictions::AssertIOAllowed();
    200 
    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());
    210 
    211   DWORD result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
    212                                       adapterAddresses, &bufferSize);
    213   if (result == ERROR_BUFFER_OVERFLOW) {
    214     buffer.resize(bufferSize);
    215     adapterAddresses =
    216         reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front());
    217     result = GetAdaptersAddresses(AF_UNSPEC, flags, 0,
    218                                   adapterAddresses, &bufferSize);
    219   }
    220 
    221   if (result != NO_ERROR) {
    222     VLOG(ERROR) << "GetAdapatersAddresses failed with error " << result;
    223     return "";
    224   }
    225 
    226   MacAddressProcessor processor;
    227   for (; adapterAddresses != NULL; adapterAddresses = adapterAddresses->Next) {
    228     processor.ProcessAdapterAddress(adapterAddresses);
    229   }
    230   return processor.mac_address();
    231 }
    232 
    233 std::string GetMacAddressFromGetIfTable2() {
    234   base::ThreadRestrictions::AssertIOAllowed();
    235 
    236   // This is available on Vista+ only.
    237   base::ScopedNativeLibrary library(base::FilePath(L"Iphlpapi.dll"));
    238 
    239   typedef DWORD (NETIOAPI_API_ *GetIfTablePtr)(PMIB_IF_TABLE2*);
    240   typedef void (NETIOAPI_API_ *FreeMibTablePtr)(PMIB_IF_TABLE2);
    241 
    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.";
    248     return "";
    249   }
    250 
    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;
    255     return "";
    256   }
    257 
    258   MacAddressProcessor processor;
    259   for (size_t i = 0; i < ifTable->NumEntries; i++) {
    260     processor.ProcessInterfaceRow(&(ifTable->Table[i]));
    261   }
    262 
    263   if (ifTable != NULL) {
    264     freeMibTablePtr(ifTable);
    265     ifTable = NULL;
    266   }
    267   return processor.mac_address();
    268 }
    269 
    270 }  // namespace
    271 
    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();
    284 
    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.
    288 
    289   if (modern_device_id.empty())
    290     return std::string();
    291 
    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();
    300   }
    301 
    302   return mac_address + modern_device_id;
    303 }
    304