diff options
author | Eric Caruso <ejcaruso@google.com> | 2016-04-20 17:31:38 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-04-20 17:31:38 +0000 |
commit | 8733437ffd3cde78e25b2e861dc6999ab1f72cb1 (patch) | |
tree | 670516d8c8943620797704c6b1899519983312ec | |
parent | ccca155e889ebe4136b87e1e82a59247834c8002 (diff) | |
parent | 30039ff068dacecc03e6a717bece58eb34d7f5b0 (diff) | |
download | shill-8733437ffd3cde78e25b2e861dc6999ab1f72cb1.tar.gz |
shill: Add MAC address randomization property
am: 30039ff
* commit '30039ff068dacecc03e6a717bece58eb34d7f5b0':
shill: Add MAC address randomization property
Change-Id: Id4a144307c75eb21cc962421817fb566ae8218f5
-rw-r--r-- | dbus/chromeos_supplicant_interface_proxy.cc | 23 | ||||
-rw-r--r-- | dbus/chromeos_supplicant_interface_proxy.h | 2 | ||||
-rw-r--r-- | dbus_bindings/supplicant-interface.dbus-xml | 5 | ||||
-rw-r--r-- | supplicant/mock_supplicant_interface_proxy.h | 3 | ||||
-rw-r--r-- | supplicant/supplicant_interface_proxy_interface.h | 2 | ||||
-rw-r--r-- | wifi/wifi.cc | 70 | ||||
-rw-r--r-- | wifi/wifi.h | 18 | ||||
-rw-r--r-- | wifi/wifi_unittest.cc | 99 |
8 files changed, 222 insertions, 0 deletions
diff --git a/dbus/chromeos_supplicant_interface_proxy.cc b/dbus/chromeos_supplicant_interface_proxy.cc index c93e4574..5b950d41 100644 --- a/dbus/chromeos_supplicant_interface_proxy.cc +++ b/dbus/chromeos_supplicant_interface_proxy.cc @@ -341,6 +341,29 @@ bool ChromeosSupplicantInterfaceProxy::SetHT40Enable(const string& network, return true; } +bool ChromeosSupplicantInterfaceProxy::EnableMACAddressRandomization( + const std::vector<unsigned char>& mask) { + SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; + brillo::ErrorPtr error; + if (!interface_proxy_->EnableMACAddressRandomization(mask, &error)) { + LOG(ERROR) << "Failed to enable MAC address randomization: " + << error->GetCode() << " " << error->GetMessage(); + return false; + } + return true; +} + +bool ChromeosSupplicantInterfaceProxy::DisableMACAddressRandomization() { + SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__; + brillo::ErrorPtr error; + if (!interface_proxy_->DisableMACAddressRandomization(&error)) { + LOG(ERROR) << "Failed to enable MAC address randomization: " + << error->GetCode() << " " << error->GetMessage(); + return false; + } + return true; +} + bool ChromeosSupplicantInterfaceProxy::TDLSDiscover(const string& peer) { SLOG(&interface_proxy_->GetObjectPath(), 2) << __func__ << ": " << peer; brillo::ErrorPtr error; diff --git a/dbus/chromeos_supplicant_interface_proxy.h b/dbus/chromeos_supplicant_interface_proxy.h index bee0ed29..5e90e10b 100644 --- a/dbus/chromeos_supplicant_interface_proxy.h +++ b/dbus/chromeos_supplicant_interface_proxy.h @@ -66,6 +66,8 @@ class ChromeosSupplicantInterfaceProxy bool TDLSStatus(const std::string& peer, std::string* status) override; bool TDLSTeardown(const std::string& peer) override; bool SetHT40Enable(const std::string& network, bool enable) override; + bool EnableMACAddressRandomization(const std::vector<unsigned char>& mask) override; + bool DisableMACAddressRandomization() override; // The below set functions will always return true, since PropertySet::Set // is an async method. Any failures will be logged in the callback. bool SetFastReauth(bool enabled) override; diff --git a/dbus_bindings/supplicant-interface.dbus-xml b/dbus_bindings/supplicant-interface.dbus-xml index 8235b83f..d111b38c 100644 --- a/dbus_bindings/supplicant-interface.dbus-xml +++ b/dbus_bindings/supplicant-interface.dbus-xml @@ -70,6 +70,11 @@ <arg name="network" type="o" direction="in"/> <arg name="enable" type="b" direction="in"/> </method> + <method name="EnableMACAddressRandomization"> + <arg name="mask" type="ay" direction="in"/> + </method> + <method name="DisableMACAddressRandomization"> + </method> <property name="Capabilities" type="a{sv}" access="read"/> <property name="State" type="s" access="read"/> <property name="Scanning" type="b" access="read"/> diff --git a/supplicant/mock_supplicant_interface_proxy.h b/supplicant/mock_supplicant_interface_proxy.h index f9db1bf4..5c507372 100644 --- a/supplicant/mock_supplicant_interface_proxy.h +++ b/supplicant/mock_supplicant_interface_proxy.h @@ -61,6 +61,9 @@ class MockSupplicantInterfaceProxy : public SupplicantInterfaceProxyInterface { MOCK_METHOD2(TDLSStatus, bool(const std::string& peer, std::string* status)); MOCK_METHOD1(TDLSTeardown, bool(const std::string& peer)); MOCK_METHOD2(SetHT40Enable, bool(const std::string& network, bool enable)); + MOCK_METHOD1(EnableMACAddressRandomization, + bool(const std::vector<unsigned char>& mask)); + MOCK_METHOD0(DisableMACAddressRandomization, bool()); private: DISALLOW_COPY_AND_ASSIGN(MockSupplicantInterfaceProxy); diff --git a/supplicant/supplicant_interface_proxy_interface.h b/supplicant/supplicant_interface_proxy_interface.h index e26279ee..8e4531e6 100644 --- a/supplicant/supplicant_interface_proxy_interface.h +++ b/supplicant/supplicant_interface_proxy_interface.h @@ -59,6 +59,8 @@ class SupplicantInterfaceProxyInterface { std::string* status) = 0; virtual bool TDLSTeardown(const std::string& peer) = 0; virtual bool SetHT40Enable(const std::string& network, bool enable) = 0; + virtual bool EnableMACAddressRandomization(const std::vector<unsigned char>& mask) = 0; + virtual bool DisableMACAddressRandomization() = 0; }; } // namespace shill diff --git a/wifi/wifi.cc b/wifi/wifi.cc index 1901c0e1..6a5b6428 100644 --- a/wifi/wifi.cc +++ b/wifi/wifi.cc @@ -117,6 +117,12 @@ const int WiFi::kPostScanFailedDelayMilliseconds = 10000; // Invalid 802.11 disconnect reason code. const int WiFi::kDefaultDisconnectReason = INT32_MAX; +// The default random MAC mask is FF:FF:FF:00:00:00. Bits which are a 1 in +// the mask stay the same during randomization, and bits which are 0 are +// randomized. This mask means the OUI will remain unchanged but the last +// three octets will be different. +const std::vector<unsigned char> WiFi::kRandomMACMask{255, 255, 255, 0, 0, 0}; + namespace { bool IsPrintableAsciiChar(char c) { return (c >= ' ' && c <= '~'); @@ -172,6 +178,8 @@ WiFi::WiFi(ControlInterface* control_interface, min_frequencies_to_scan_(kMinumumFrequenciesToScan), max_frequencies_to_scan_(std::numeric_limits<int>::max()), scan_all_frequencies_(true), + random_mac_supported_(false), + random_mac_enabled_(false), fraction_per_scan_(kDefaultFractionPerScan), scan_state_(kScanIdle), scan_method_(kScanMethodNone), @@ -203,6 +211,10 @@ WiFi::WiFi(ControlInterface* control_interface, kBgscanSignalThresholdProperty, &WiFi::GetBgscanSignalThreshold, &WiFi::SetBgscanSignalThreshold); + HelpRegisterDerivedBool(store, + kMACAddressRandomizationProperty, + &WiFi::GetRandomMACEnabled, + &WiFi::SetRandomMACEnabled); store->RegisterDerivedKeyValueStore( kLinkStatisticsProperty, @@ -749,6 +761,30 @@ bool WiFi::SetScanInterval(const uint16_t& seconds, Error* /*error*/) { return true; } +bool WiFi::GetRandomMACEnabled(Error* /*error*/) { + return random_mac_enabled_; +} + +bool WiFi::SetRandomMACEnabled(const bool& enabled, Error* error) { + if (!random_mac_supported_) { + Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, + "This WiFi device does not support MAC address randomization"); + return false; + } + if (random_mac_enabled_ == enabled) { + return false; + } + if ((enabled && + supplicant_interface_proxy_->EnableMACAddressRandomization( + kRandomMACMask)) || + (!enabled && + supplicant_interface_proxy_->DisableMACAddressRandomization())) { + random_mac_enabled_ = enabled; + return true; + } + return false; +} + void WiFi::ClearBgscanMethod(const int& /*argument*/, Error* /*error*/) { bgscan_method_.clear(); } @@ -1165,6 +1201,27 @@ bool WiFi::ParseWiphyIndex(const Nl80211Message& nl80211_message) { return true; } +void WiFi::ParseFeatureFlags(const Nl80211Message& nl80211_message) { + // Verify NL80211_CMD_NEW_WIPHY. + if (nl80211_message.command() != NewWiphyMessage::kCommand) { + LOG(ERROR) << "Received unexpected command: " << nl80211_message.command(); + return; + } + + uint32_t flags; + if (!nl80211_message.const_attributes()->GetU32AttributeValue( + NL80211_ATTR_FEATURE_FLAGS, &flags)) { + LOG(WARNING) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_FEATURE_FLAGS"; + return; + } + + random_mac_supported_ = + (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR) && + (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR); + SLOG(this, 7) << __func__ << ": " + << "Supports random MAC: " << random_mac_supported_; +} + void WiFi::OnScanStarted(const NetlinkMessage& netlink_message) { // We only handle scan triggers in this handler, which is are nl80211 messages // with the NL80211_CMD_TRIGGER_SCAN command. @@ -1736,6 +1793,16 @@ void WiFi::HelpRegisterDerivedUint16( Uint16Accessor(new CustomAccessor<WiFi, uint16_t>(this, get, set))); } +void WiFi::HelpRegisterDerivedBool( + PropertyStore* store, + const string& name, + bool(WiFi::*get)(Error* error), + bool(WiFi::*set)(const bool& value, Error* error)) { + store->RegisterDerivedBool( + name, + BoolAccessor(new CustomAccessor<WiFi, bool>(this, get, set))); +} + void WiFi::HelpRegisterConstDerivedBool( PropertyStore* store, const string& name, @@ -2317,6 +2384,9 @@ void WiFi::OnNewWiphy(const Nl80211Message& nl80211_message) { wake_on_wifi_->OnWiphyIndexReceived(wiphy_index_); } + // This checks NL80211_ATTR_FEATURE_FLAGS. + ParseFeatureFlags(nl80211_message); + // The attributes, for this message, are complicated. // NL80211_ATTR_BANDS contains an array of bands... AttributeListConstRefPtr wiphy_bands; diff --git a/wifi/wifi.h b/wifi/wifi.h index 14072c6a..be45052d 100644 --- a/wifi/wifi.h +++ b/wifi/wifi.h @@ -372,6 +372,9 @@ class WiFi : public Device, public SupplicantEventDelegateInterface { // Used to distinguish between a disconnect reason explicitly set by // supplicant and a default. static const int kDefaultDisconnectReason; + // Used when enabling MAC randomization to request that the OUI remain constant + // and the last three octets are randomized. + static const std::vector<unsigned char> kRandomMACMask; void GetPhyInfo(); void AppendBgscan(WiFiService* service, @@ -406,6 +409,9 @@ class WiFi : public Device, public SupplicantEventDelegateInterface { bool SetScanInterval(const uint16_t& seconds, Error* error); void ClearBgscanMethod(const int& argument, Error* error); + bool GetRandomMACEnabled(Error* error); + bool SetRandomMACEnabled(const bool& enabled, Error* error); + void CurrentBSSChanged(const std::string& new_bss); void DisconnectReasonChanged(const int32_t new_disconnect_reason); // Return the RPC identifier associated with the wpa_supplicant network @@ -458,6 +464,11 @@ class WiFi : public Device, public SupplicantEventDelegateInterface { const std::string& name, uint16_t(WiFi::*get)(Error* error), bool(WiFi::*set)(const uint16_t& value, Error* error)); + void HelpRegisterDerivedBool( + PropertyStore* store, + const std::string& name, + bool(WiFi::*get)(Error* error), + bool(WiFi::*set)(const bool& value, Error* error)); void HelpRegisterConstDerivedBool( PropertyStore* store, const std::string& name, @@ -602,6 +613,10 @@ class WiFi : public Device, public SupplicantEventDelegateInterface { // Returns true iff the wiphy index was parsed successfully, false otherwise. bool ParseWiphyIndex(const Nl80211Message& nl80211_message); + // Given a NL80211_CMD_NEW_WIPHY message |nl80211_message|, parses the + // feature flags and sets members of this WiFi class appropriately. + void ParseFeatureFlags(const Nl80211Message& nl80211_message); + // Callback invoked when the kernel broadcasts a notification that a scan has // started. virtual void OnScanStarted(const NetlinkMessage& netlink_message); @@ -691,6 +706,9 @@ class WiFi : public Device, public SupplicantEventDelegateInterface { size_t max_frequencies_to_scan_; bool scan_all_frequencies_; + bool random_mac_supported_; + bool random_mac_enabled_; + // Holds the list of scan results waiting to be processed and a cancelable // closure for processing the pending tasks in PendingScanResultsHandler(). std::unique_ptr<PendingScanResults> pending_scan_results_; diff --git a/wifi/wifi_unittest.cc b/wifi/wifi_unittest.cc index bf81af31..61545319 100644 --- a/wifi/wifi_unittest.cc +++ b/wifi/wifi_unittest.cc @@ -611,6 +611,12 @@ class WiFiObjectTest : public ::testing::TestWithParam<string> { .WillByDefault(Return(true)); ON_CALL(*supplicant_interface_proxy_.get(), Scan(_)) .WillByDefault(Return(true)); + ON_CALL(*supplicant_interface_proxy_.get(), + EnableMACAddressRandomization(_)) + .WillByDefault(Return(true)); + ON_CALL(*supplicant_interface_proxy_.get(), + DisableMACAddressRandomization()) + .WillByDefault(Return(true)); ON_CALL(*supplicant_network_proxy_.get(), SetEnabled(_)) .WillByDefault(Return(true)); @@ -1272,6 +1278,25 @@ class WiFiObjectTest : public ::testing::TestWithParam<string> { void SetWiphyIndex(uint32_t index) { wifi_->wiphy_index_ = index; } + void ParseFeatureFlags(const Nl80211Message& nl80211_message) { + wifi_->ParseFeatureFlags(nl80211_message); + } + + bool GetRandomMACSupported() { return wifi_->random_mac_supported_; } + + void SetRandomMACSupported(bool supported) { + wifi_->random_mac_supported_ = supported; + } + + bool GetRandomMACEnabled() { return wifi_->random_mac_enabled_; } + + void SetRandomMACEnabled(bool enabled) { + Error error; + wifi_->SetRandomMACEnabled(enabled, &error); + } + + std::vector<unsigned char> GetRandomMACMask() { return WiFi::kRandomMACMask; } + std::set<uint16_t>* GetAllScanFrequencies() { return &wifi_->all_scan_frequencies_; } @@ -4181,6 +4206,80 @@ TEST_F(WiFiMainTest, ParseWiphyIndex_Failure) { EXPECT_CALL(*wake_on_wifi_, OnWiphyIndexReceived(_)).Times(0); } +TEST_F(WiFiMainTest, ParseFeatureFlags_RandomMACSupport) { + NewWiphyMessage msg; + NetlinkPacket packet(kNewWiphyNlMsg, sizeof(kNewWiphyNlMsg)); + msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); + // Make sure the feature is marked unsupported + uint32_t flags; + msg.const_attributes()->GetU32AttributeValue( + NL80211_ATTR_FEATURE_FLAGS, &flags); + flags &= ~(NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR); + msg.attributes()->SetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, flags); + ParseFeatureFlags(msg); + EXPECT_FALSE(GetRandomMACSupported()); + + // Make sure the feature is marked supported + msg.const_attributes()->GetU32AttributeValue( + NL80211_ATTR_FEATURE_FLAGS, &flags); + flags |= (NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR); + msg.attributes()->SetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, flags); + ParseFeatureFlags(msg); + EXPECT_TRUE(GetRandomMACSupported()); +} + +TEST_F(WiFiMainTest, RandomMACProperty_Unsupported) { + StartWiFi(); + SetRandomMACSupported(false); + EXPECT_CALL(*GetSupplicantInterfaceProxy(), + EnableMACAddressRandomization(_)).Times(0); + SetRandomMACEnabled(true); + EXPECT_FALSE(GetRandomMACEnabled()); +} + +TEST_F(WiFiMainTest, RandomMACProperty_Supported) { + StartWiFi(); + SetRandomMACSupported(true); + + Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); + EXPECT_CALL(*GetSupplicantInterfaceProxy(), + EnableMACAddressRandomization(GetRandomMACMask())).Times(1); + SetRandomMACEnabled(true); + EXPECT_TRUE(GetRandomMACEnabled()); + + Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); + EXPECT_CALL(*GetSupplicantInterfaceProxy(), + DisableMACAddressRandomization()).Times(1); + SetRandomMACEnabled(false); + EXPECT_FALSE(GetRandomMACEnabled()); +} + +TEST_F(WiFiMainTest, RandomMACProperty_SupplicantFailed) { + StartWiFi(); + SetRandomMACSupported(true); + + // Test wpa_supplicant failing to enable random MAC. + Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); + EXPECT_CALL(*GetSupplicantInterfaceProxy(), + EnableMACAddressRandomization(GetRandomMACMask())) + .WillOnce(Return(false)); + SetRandomMACEnabled(true); + EXPECT_FALSE(GetRandomMACEnabled()); + + // Enable random MAC. + Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); + SetRandomMACEnabled(true); + + // Test wpa_supplicant failing to disable random MAC. + Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); + EXPECT_CALL(*GetSupplicantInterfaceProxy(), + DisableMACAddressRandomization()).WillOnce(Return(false)); + SetRandomMACEnabled(false); + EXPECT_TRUE(GetRandomMACEnabled()); +} + TEST_F(WiFiMainTest, OnScanStarted_ActiveScan) { SetWiphyIndex(kScanTriggerMsgWiphyIndex); TriggerScanMessage msg; |