You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
6.6 KiB
176 lines
6.6 KiB
/* |
|
* Copyright (C) 2017 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <gmock/gmock.h> |
|
#include <gtest/gtest.h> |
|
|
|
#include <netdutils/MockSyscalls.h> |
|
|
|
#include "InterfaceController.h" |
|
|
|
using testing::ByMove; |
|
using testing::Invoke; |
|
using testing::Return; |
|
using testing::StrictMock; |
|
using testing::_; |
|
|
|
namespace android { |
|
namespace net { |
|
namespace { |
|
|
|
using netdutils::Fd; |
|
using netdutils::ScopedMockSyscalls; |
|
using netdutils::Slice; |
|
using netdutils::Status; |
|
using netdutils::StatusOr; |
|
using netdutils::UniqueFd; |
|
using netdutils::makeSlice; |
|
using netdutils::status::ok; |
|
using netdutils::statusFromErrno; |
|
|
|
constexpr Fd kDevRandomFd(777); |
|
constexpr Fd kStableSecretFd(9999); |
|
const char kDevRandomPath[] = "/dev/random"; |
|
const char kTestIface[] = "wlan5"; |
|
const char kStableSecretProperty[] = "persist.netd.stable_secret"; |
|
const char kStableSecretPath[] = "/proc/sys/net/ipv6/conf/wlan5/stable_secret"; |
|
const char kTestIPv6Address[] = "\x20\x01\x0d\xb8\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"; |
|
const char kTestIPv6AddressString[] = "2001:db8:506:708:90a:b0c:d0e:f10"; |
|
|
|
// getProperty() and setProperty() are forwarded to this mock |
|
class MockProperties { |
|
public: |
|
MOCK_CONST_METHOD2(get, std::string(const std::string& key, const std::string& dflt)); |
|
MOCK_CONST_METHOD2(set, Status(const std::string& key, const std::string& val)); |
|
}; |
|
|
|
} // namespace |
|
|
|
class StablePrivacyTest : public testing::Test { |
|
protected: |
|
void expectOpenFile(const std::string& path, const Fd fd, int err) { |
|
if (err == 0) { |
|
EXPECT_CALL(mSyscalls, open(path, _, _)).WillOnce(Return(ByMove(UniqueFd(fd)))); |
|
EXPECT_CALL(mSyscalls, close(fd)).WillOnce(Return(ok)); |
|
} else { |
|
EXPECT_CALL(mSyscalls, open(path, _, _)) |
|
.WillOnce(Return(ByMove(statusFromErrno(err, "open() failed")))); |
|
} |
|
} |
|
|
|
void expectReadFromDevRandom(const std::string& data) { |
|
expectOpenFile(kDevRandomPath, kDevRandomFd, 0); |
|
EXPECT_CALL(mSyscalls, read(kDevRandomFd, _)).WillOnce(Invoke([data](Fd, const Slice buf) { |
|
EXPECT_EQ(data.size(), buf.size()); |
|
return take(buf, copy(buf, makeSlice(data))); |
|
})); |
|
} |
|
|
|
void expectGetPropertyDefault(const std::string& key) { |
|
EXPECT_CALL(mProperties, get(key, _)) |
|
.WillOnce(Invoke([](const std::string&, const std::string& dflt) { return dflt; })); |
|
} |
|
|
|
void expectGetProperty(const std::string& key, const std::string& val) { |
|
EXPECT_CALL(mProperties, get(key, _)) |
|
.WillOnce(Invoke([val](const std::string&, const std::string&) { return val; })); |
|
} |
|
|
|
void expectSetProperty(const std::string& key, const std::string& val, Status status) { |
|
EXPECT_CALL(mProperties, set(key, val)).WillOnce(Return(status)); |
|
} |
|
|
|
void expectWriteToFile(const Fd fd, const std::string& val, int err) { |
|
EXPECT_CALL(mSyscalls, write(fd, _)) |
|
.WillOnce(Invoke([val, err](Fd, const Slice buf) -> StatusOr<size_t> { |
|
EXPECT_EQ(val, toString(buf)); |
|
if (err) { |
|
return statusFromErrno(err, "write() failed"); |
|
} |
|
return val.size(); |
|
})); |
|
} |
|
|
|
Status enableStablePrivacyAddresses(const std::string& iface) { |
|
return InterfaceController::enableStablePrivacyAddresses(iface, mGet, mSet); |
|
} |
|
|
|
StrictMock<ScopedMockSyscalls> mSyscalls; |
|
StrictMock<MockProperties> mProperties; |
|
|
|
const std::function<std::string(const std::string&, const std::string&)> mGet = |
|
[this](const std::string& key, const std::string& dflt) { |
|
return mProperties.get(key, dflt); |
|
}; |
|
const std::function<Status(const std::string&, const std::string&)> mSet = |
|
[this](const std::string& key, const std::string& val) { |
|
return mProperties.set(key, val); |
|
}; |
|
}; |
|
|
|
TEST_F(StablePrivacyTest, PropertyOpenEnoent) { |
|
expectOpenFile(kStableSecretPath, kStableSecretFd, ENOENT); |
|
EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface)); |
|
} |
|
|
|
TEST_F(StablePrivacyTest, PropertyOpenEaccess) { |
|
expectOpenFile(kStableSecretPath, kStableSecretFd, EACCES); |
|
EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface)); |
|
} |
|
|
|
TEST_F(StablePrivacyTest, FirstBootWriteOkSetPropertyOk) { |
|
expectOpenFile(kStableSecretPath, kStableSecretFd, 0); |
|
expectGetPropertyDefault(kStableSecretProperty); |
|
expectReadFromDevRandom(kTestIPv6Address); |
|
expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, 0); |
|
expectSetProperty(kStableSecretProperty, kTestIPv6AddressString, ok); |
|
EXPECT_EQ(ok, enableStablePrivacyAddresses(kTestIface)); |
|
} |
|
|
|
TEST_F(StablePrivacyTest, FirstBootWriteOkSetPropertyFail) { |
|
const auto kError = statusFromErrno(EINVAL, ""); |
|
expectOpenFile(kStableSecretPath, kStableSecretFd, 0); |
|
expectGetPropertyDefault(kStableSecretProperty); |
|
expectReadFromDevRandom(kTestIPv6Address); |
|
expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, 0); |
|
expectSetProperty(kStableSecretProperty, kTestIPv6AddressString, kError); |
|
EXPECT_EQ(kError, enableStablePrivacyAddresses(kTestIface)); |
|
} |
|
|
|
TEST_F(StablePrivacyTest, FirstBootWriteFail) { |
|
expectOpenFile(kStableSecretPath, kStableSecretFd, 0); |
|
expectGetPropertyDefault(kStableSecretProperty); |
|
expectReadFromDevRandom(kTestIPv6Address); |
|
expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, ENOSPC); |
|
EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface)); |
|
} |
|
|
|
TEST_F(StablePrivacyTest, ExistingPropertyWriteOk) { |
|
expectOpenFile(kStableSecretPath, kStableSecretFd, 0); |
|
expectGetProperty(kStableSecretProperty, kTestIPv6AddressString); |
|
expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, 0); |
|
EXPECT_EQ(ok, enableStablePrivacyAddresses(kTestIface)); |
|
} |
|
|
|
TEST_F(StablePrivacyTest, ExistingPropertyWriteFail) { |
|
expectOpenFile(kStableSecretPath, kStableSecretFd, 0); |
|
expectGetProperty(kStableSecretProperty, kTestIPv6AddressString); |
|
expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, EACCES); |
|
EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface)); |
|
} |
|
|
|
} // namespace net |
|
} // namespace android
|
|
|