blob: 006018d765b43a6ad7181edee4bee7e9613705a8 [file] [log] [blame]
Joel Scherpelzde937962017-06-01 13:20:21 +09001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Chenbo Feng7e974052018-02-28 22:57:21 -080017#include <ifaddrs.h>
18#include <net/if.h>
19#include <sys/types.h>
20
Joel Scherpelzde937962017-06-01 13:20:21 +090021#include <gmock/gmock.h>
22#include <gtest/gtest.h>
23
24#include <netdutils/MockSyscalls.h>
waynema5851b032021-11-24 17:08:25 +080025#include <netdutils/Utils.h>
Joel Scherpelzde937962017-06-01 13:20:21 +090026
27#include "InterfaceController.h"
28
29using testing::ByMove;
30using testing::Invoke;
31using testing::Return;
32using testing::StrictMock;
33using testing::_;
34
35namespace android {
36namespace net {
37namespace {
38
39using netdutils::Fd;
waynema5851b032021-11-24 17:08:25 +080040using netdutils::getIfaceList;
41using netdutils::getIfaceNames;
42using netdutils::makeSlice;
Joel Scherpelzde937962017-06-01 13:20:21 +090043using netdutils::ScopedMockSyscalls;
44using netdutils::Slice;
45using netdutils::Status;
waynema5851b032021-11-24 17:08:25 +080046using netdutils::statusFromErrno;
Joel Scherpelzde937962017-06-01 13:20:21 +090047using netdutils::StatusOr;
48using netdutils::UniqueFd;
Joel Scherpelzde937962017-06-01 13:20:21 +090049using netdutils::status::ok;
Joel Scherpelzde937962017-06-01 13:20:21 +090050
51constexpr Fd kDevRandomFd(777);
52constexpr Fd kStableSecretFd(9999);
53const char kDevRandomPath[] = "/dev/random";
54const char kTestIface[] = "wlan5";
55const char kStableSecretProperty[] = "persist.netd.stable_secret";
56const char kStableSecretPath[] = "/proc/sys/net/ipv6/conf/wlan5/stable_secret";
57const char kTestIPv6Address[] = "\x20\x01\x0d\xb8\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10";
58const char kTestIPv6AddressString[] = "2001:db8:506:708:90a:b0c:d0e:f10";
59
60// getProperty() and setProperty() are forwarded to this mock
61class MockProperties {
62 public:
63 MOCK_CONST_METHOD2(get, std::string(const std::string& key, const std::string& dflt));
64 MOCK_CONST_METHOD2(set, Status(const std::string& key, const std::string& val));
65};
66
67} // namespace
68
69class StablePrivacyTest : public testing::Test {
70 protected:
71 void expectOpenFile(const std::string& path, const Fd fd, int err) {
72 if (err == 0) {
73 EXPECT_CALL(mSyscalls, open(path, _, _)).WillOnce(Return(ByMove(UniqueFd(fd))));
74 EXPECT_CALL(mSyscalls, close(fd)).WillOnce(Return(ok));
75 } else {
76 EXPECT_CALL(mSyscalls, open(path, _, _))
77 .WillOnce(Return(ByMove(statusFromErrno(err, "open() failed"))));
78 }
79 }
80
81 void expectReadFromDevRandom(const std::string& data) {
82 expectOpenFile(kDevRandomPath, kDevRandomFd, 0);
83 EXPECT_CALL(mSyscalls, read(kDevRandomFd, _)).WillOnce(Invoke([data](Fd, const Slice buf) {
84 EXPECT_EQ(data.size(), buf.size());
85 return take(buf, copy(buf, makeSlice(data)));
86 }));
87 }
88
89 void expectGetPropertyDefault(const std::string& key) {
90 EXPECT_CALL(mProperties, get(key, _))
91 .WillOnce(Invoke([](const std::string&, const std::string& dflt) { return dflt; }));
92 }
93
94 void expectGetProperty(const std::string& key, const std::string& val) {
95 EXPECT_CALL(mProperties, get(key, _))
96 .WillOnce(Invoke([val](const std::string&, const std::string&) { return val; }));
97 }
98
99 void expectSetProperty(const std::string& key, const std::string& val, Status status) {
Bernie Innocenti7e25ec02018-07-02 19:32:17 +0900100 EXPECT_CALL(mProperties, set(key, val)).WillOnce(Return(std::move(status)));
Joel Scherpelzde937962017-06-01 13:20:21 +0900101 }
102
103 void expectWriteToFile(const Fd fd, const std::string& val, int err) {
104 EXPECT_CALL(mSyscalls, write(fd, _))
105 .WillOnce(Invoke([val, err](Fd, const Slice buf) -> StatusOr<size_t> {
106 EXPECT_EQ(val, toString(buf));
107 if (err) {
108 return statusFromErrno(err, "write() failed");
109 }
110 return val.size();
111 }));
112 }
113
114 Status enableStablePrivacyAddresses(const std::string& iface) {
115 return InterfaceController::enableStablePrivacyAddresses(iface, mGet, mSet);
116 }
117
118 StrictMock<ScopedMockSyscalls> mSyscalls;
119 StrictMock<MockProperties> mProperties;
120
121 const std::function<std::string(const std::string&, const std::string&)> mGet =
122 [this](const std::string& key, const std::string& dflt) {
123 return mProperties.get(key, dflt);
124 };
125 const std::function<Status(const std::string&, const std::string&)> mSet =
126 [this](const std::string& key, const std::string& val) {
127 return mProperties.set(key, val);
128 };
129};
130
131TEST_F(StablePrivacyTest, PropertyOpenEnoent) {
132 expectOpenFile(kStableSecretPath, kStableSecretFd, ENOENT);
133 EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface));
134}
135
136TEST_F(StablePrivacyTest, PropertyOpenEaccess) {
137 expectOpenFile(kStableSecretPath, kStableSecretFd, EACCES);
138 EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface));
139}
140
141TEST_F(StablePrivacyTest, FirstBootWriteOkSetPropertyOk) {
142 expectOpenFile(kStableSecretPath, kStableSecretFd, 0);
143 expectGetPropertyDefault(kStableSecretProperty);
144 expectReadFromDevRandom(kTestIPv6Address);
145 expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, 0);
146 expectSetProperty(kStableSecretProperty, kTestIPv6AddressString, ok);
147 EXPECT_EQ(ok, enableStablePrivacyAddresses(kTestIface));
148}
149
150TEST_F(StablePrivacyTest, FirstBootWriteOkSetPropertyFail) {
151 const auto kError = statusFromErrno(EINVAL, "");
152 expectOpenFile(kStableSecretPath, kStableSecretFd, 0);
153 expectGetPropertyDefault(kStableSecretProperty);
154 expectReadFromDevRandom(kTestIPv6Address);
155 expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, 0);
156 expectSetProperty(kStableSecretProperty, kTestIPv6AddressString, kError);
157 EXPECT_EQ(kError, enableStablePrivacyAddresses(kTestIface));
158}
159
160TEST_F(StablePrivacyTest, FirstBootWriteFail) {
161 expectOpenFile(kStableSecretPath, kStableSecretFd, 0);
162 expectGetPropertyDefault(kStableSecretProperty);
163 expectReadFromDevRandom(kTestIPv6Address);
164 expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, ENOSPC);
165 EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface));
166}
167
168TEST_F(StablePrivacyTest, ExistingPropertyWriteOk) {
169 expectOpenFile(kStableSecretPath, kStableSecretFd, 0);
170 expectGetProperty(kStableSecretProperty, kTestIPv6AddressString);
171 expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, 0);
172 EXPECT_EQ(ok, enableStablePrivacyAddresses(kTestIface));
173}
174
175TEST_F(StablePrivacyTest, ExistingPropertyWriteFail) {
176 expectOpenFile(kStableSecretPath, kStableSecretFd, 0);
177 expectGetProperty(kStableSecretProperty, kTestIPv6AddressString);
178 expectWriteToFile(kStableSecretFd, kTestIPv6AddressString, EACCES);
179 EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface));
180}
181
Chenbo Feng7e974052018-02-28 22:57:21 -0800182class GetIfaceListTest : public testing::Test {};
183
Nathan Harold172f8e42018-04-19 13:10:19 -0700184TEST_F(GetIfaceListTest, IfaceNames) {
waynema5851b032021-11-24 17:08:25 +0800185 StatusOr<std::vector<std::string>> ifaceNames = getIfaceNames();
Nathan Harold172f8e42018-04-19 13:10:19 -0700186 EXPECT_EQ(ok, ifaceNames.status());
187 struct ifaddrs *ifaddr, *ifa;
188 EXPECT_EQ(0, getifaddrs(&ifaddr));
Yi Kongbdfd57e2018-07-25 13:26:10 -0700189 for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
Nathan Harold172f8e42018-04-19 13:10:19 -0700190 const auto val = std::find(
191 ifaceNames.value().begin(), ifaceNames.value().end(), ifa->ifa_name);
192 EXPECT_NE(ifaceNames.value().end(), val);
193 }
194 freeifaddrs(ifaddr);
195}
196
Chenbo Feng7e974052018-02-28 22:57:21 -0800197TEST_F(GetIfaceListTest, IfaceExist) {
waynema5851b032021-11-24 17:08:25 +0800198 StatusOr<std::map<std::string, uint32_t>> ifaceMap = getIfaceList();
Chenbo Feng7e974052018-02-28 22:57:21 -0800199 EXPECT_EQ(ok, ifaceMap.status());
200 struct ifaddrs *ifaddr, *ifa;
201 EXPECT_EQ(0, getifaddrs(&ifaddr));
Yi Kongbdfd57e2018-07-25 13:26:10 -0700202 for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
Chenbo Feng7e974052018-02-28 22:57:21 -0800203 uint32_t ifaceIndex = if_nametoindex(ifa->ifa_name);
204 const auto ifacePair = ifaceMap.value().find(ifa->ifa_name);
205 EXPECT_NE(ifaceMap.value().end(), ifacePair);
206 EXPECT_EQ(ifaceIndex, ifacePair->second);
207 }
208 freeifaddrs(ifaddr);
209}
210
Joel Scherpelzde937962017-06-01 13:20:21 +0900211} // namespace net
212} // namespace android