1/* 2 * Copyright 2016 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 * binder_test.cpp - unit tests for netd binder RPCs. 17 */ 18 19#include <cerrno> 20#include <cinttypes> 21#include <cstdint> 22#include <cstdio> 23#include <cstdlib> 24#include <set> 25#include <vector> 26 27#include <fcntl.h> 28#include <ifaddrs.h> 29#include <netdb.h> 30#include <sys/socket.h> 31#include <sys/types.h> 32#include <netinet/in.h> 33#include <linux/if.h> 34#include <linux/if_tun.h> 35 36#include <android-base/macros.h> 37#include <android-base/stringprintf.h> 38#include <android-base/strings.h> 39#include <cutils/multiuser.h> 40#include <gtest/gtest.h> 41#include <logwrap/logwrap.h> 42#include <netutils/ifc.h> 43 44#include "NetdConstants.h" 45#include "Stopwatch.h" 46#include "tun_interface.h" 47#include "android/net/INetd.h" 48#include "android/net/UidRange.h" 49#include "binder/IServiceManager.h" 50 51#define TUN_DEV "/dev/tun" 52 53using namespace android; 54using namespace android::base; 55using namespace android::binder; 56using android::net::INetd; 57using android::net::TunInterface; 58using android::net::UidRange; 59 60static const char* IP_RULE_V4 = "-4"; 61static const char* IP_RULE_V6 = "-6"; 62 63class BinderTest : public ::testing::Test { 64 65public: 66 BinderTest() { 67 sp<IServiceManager> sm = defaultServiceManager(); 68 sp<IBinder> binder = sm->getService(String16("netd")); 69 if (binder != nullptr) { 70 mNetd = interface_cast<INetd>(binder); 71 } 72 } 73 74 void SetUp() override { 75 ASSERT_NE(nullptr, mNetd.get()); 76 } 77 78 // Static because setting up the tun interface takes about 40ms. 79 static void SetUpTestCase() { 80 ASSERT_EQ(0, sTun.init()); 81 ASSERT_LE(sTun.name().size(), static_cast<size_t>(IFNAMSIZ)); 82 } 83 84 static void TearDownTestCase() { 85 // Closing the socket removes the interface and IP addresses. 86 sTun.destroy(); 87 } 88 89 static void fakeRemoteSocketPair(int *clientSocket, int *serverSocket, int *acceptedSocket); 90 91protected: 92 sp<INetd> mNetd; 93 static TunInterface sTun; 94}; 95 96TunInterface BinderTest::sTun; 97 98class TimedOperation : public Stopwatch { 99public: 100 explicit TimedOperation(const std::string &name): mName(name) {} 101 virtual ~TimedOperation() { 102 fprintf(stderr, " %s: %6.1f ms\n", mName.c_str(), timeTaken()); 103 } 104 105private: 106 std::string mName; 107}; 108 109TEST_F(BinderTest, TestIsAlive) { 110 TimedOperation t("isAlive RPC"); 111 bool isAlive = false; 112 mNetd->isAlive(&isAlive); 113 ASSERT_TRUE(isAlive); 114} 115 116static int randomUid() { 117 return 100000 * arc4random_uniform(7) + 10000 + arc4random_uniform(5000); 118} 119 120static std::vector<std::string> runCommand(const std::string& command) { 121 std::vector<std::string> lines; 122 FILE *f; 123 124 if ((f = popen(command.c_str(), "r")) == nullptr) { 125 perror("popen"); 126 return lines; 127 } 128 129 char *line = nullptr; 130 size_t bufsize = 0; 131 ssize_t linelen = 0; 132 while ((linelen = getline(&line, &bufsize, f)) >= 0) { 133 lines.push_back(std::string(line, linelen)); 134 free(line); 135 line = nullptr; 136 } 137 138 pclose(f); 139 return lines; 140} 141 142static std::vector<std::string> listIpRules(const char *ipVersion) { 143 std::string command = StringPrintf("%s %s rule list", IP_PATH, ipVersion); 144 return runCommand(command); 145} 146 147static std::vector<std::string> listIptablesRule(const char *binary, const char *chainName) { 148 std::string command = StringPrintf("%s -w -n -L %s", binary, chainName); 149 return runCommand(command); 150} 151 152static int iptablesRuleLineLength(const char *binary, const char *chainName) { 153 return listIptablesRule(binary, chainName).size(); 154} 155 156TEST_F(BinderTest, TestFirewallReplaceUidChain) { 157 std::string chainName = StringPrintf("netd_binder_test_%u", arc4random_uniform(10000)); 158 const int kNumUids = 500; 159 std::vector<int32_t> noUids(0); 160 std::vector<int32_t> uids(kNumUids); 161 for (int i = 0; i < kNumUids; i++) { 162 uids[i] = randomUid(); 163 } 164 165 bool ret; 166 { 167 TimedOperation op(StringPrintf("Programming %d-UID whitelist chain", kNumUids)); 168 mNetd->firewallReplaceUidChain(String16(chainName.c_str()), true, uids, &ret); 169 } 170 EXPECT_EQ(true, ret); 171 EXPECT_EQ((int) uids.size() + 7, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str())); 172 EXPECT_EQ((int) uids.size() + 13, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str())); 173 { 174 TimedOperation op("Clearing whitelist chain"); 175 mNetd->firewallReplaceUidChain(String16(chainName.c_str()), false, noUids, &ret); 176 } 177 EXPECT_EQ(true, ret); 178 EXPECT_EQ(5, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str())); 179 EXPECT_EQ(5, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str())); 180 181 { 182 TimedOperation op(StringPrintf("Programming %d-UID blacklist chain", kNumUids)); 183 mNetd->firewallReplaceUidChain(String16(chainName.c_str()), false, uids, &ret); 184 } 185 EXPECT_EQ(true, ret); 186 EXPECT_EQ((int) uids.size() + 5, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str())); 187 EXPECT_EQ((int) uids.size() + 5, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str())); 188 189 { 190 TimedOperation op("Clearing blacklist chain"); 191 mNetd->firewallReplaceUidChain(String16(chainName.c_str()), false, noUids, &ret); 192 } 193 EXPECT_EQ(true, ret); 194 EXPECT_EQ(5, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str())); 195 EXPECT_EQ(5, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str())); 196 197 // Check that the call fails if iptables returns an error. 198 std::string veryLongStringName = "netd_binder_test_UnacceptablyLongIptablesChainName"; 199 mNetd->firewallReplaceUidChain(String16(veryLongStringName.c_str()), true, noUids, &ret); 200 EXPECT_EQ(false, ret); 201} 202 203static int bandwidthDataSaverEnabled(const char *binary) { 204 std::vector<std::string> lines = listIptablesRule(binary, "bw_data_saver"); 205 206 // Output looks like this: 207 // 208 // Chain bw_data_saver (1 references) 209 // target prot opt source destination 210 // RETURN all -- 0.0.0.0/0 0.0.0.0/0 211 EXPECT_EQ(3U, lines.size()); 212 if (lines.size() != 3) return -1; 213 214 EXPECT_TRUE(android::base::StartsWith(lines[2], "RETURN ") || 215 android::base::StartsWith(lines[2], "REJECT ")); 216 217 return android::base::StartsWith(lines[2], "REJECT"); 218} 219 220bool enableDataSaver(sp<INetd>& netd, bool enable) { 221 TimedOperation op(enable ? " Enabling data saver" : "Disabling data saver"); 222 bool ret; 223 netd->bandwidthEnableDataSaver(enable, &ret); 224 return ret; 225} 226 227int getDataSaverState() { 228 const int enabled4 = bandwidthDataSaverEnabled(IPTABLES_PATH); 229 const int enabled6 = bandwidthDataSaverEnabled(IP6TABLES_PATH); 230 EXPECT_EQ(enabled4, enabled6); 231 EXPECT_NE(-1, enabled4); 232 EXPECT_NE(-1, enabled6); 233 if (enabled4 != enabled6 || (enabled6 != 0 && enabled6 != 1)) { 234 return -1; 235 } 236 return enabled6; 237} 238 239TEST_F(BinderTest, TestBandwidthEnableDataSaver) { 240 const int wasEnabled = getDataSaverState(); 241 ASSERT_NE(-1, wasEnabled); 242 243 if (wasEnabled) { 244 ASSERT_TRUE(enableDataSaver(mNetd, false)); 245 EXPECT_EQ(0, getDataSaverState()); 246 } 247 248 ASSERT_TRUE(enableDataSaver(mNetd, false)); 249 EXPECT_EQ(0, getDataSaverState()); 250 251 ASSERT_TRUE(enableDataSaver(mNetd, true)); 252 EXPECT_EQ(1, getDataSaverState()); 253 254 ASSERT_TRUE(enableDataSaver(mNetd, true)); 255 EXPECT_EQ(1, getDataSaverState()); 256 257 if (!wasEnabled) { 258 ASSERT_TRUE(enableDataSaver(mNetd, false)); 259 EXPECT_EQ(0, getDataSaverState()); 260 } 261} 262 263static bool ipRuleExistsForRange(const uint32_t priority, const UidRange& range, 264 const std::string& action, const char* ipVersion) { 265 // Output looks like this: 266 // "12500:\tfrom all fwmark 0x0/0x20000 iif lo uidrange 1000-2000 prohibit" 267 std::vector<std::string> rules = listIpRules(ipVersion); 268 269 std::string prefix = StringPrintf("%" PRIu32 ":", priority); 270 std::string suffix = StringPrintf(" iif lo uidrange %d-%d %s\n", 271 range.getStart(), range.getStop(), action.c_str()); 272 for (std::string line : rules) { 273 if (android::base::StartsWith(line, prefix.c_str()) 274 && android::base::EndsWith(line, suffix.c_str())) { 275 return true; 276 } 277 } 278 return false; 279} 280 281static bool ipRuleExistsForRange(const uint32_t priority, const UidRange& range, 282 const std::string& action) { 283 bool existsIp4 = ipRuleExistsForRange(priority, range, action, IP_RULE_V4); 284 bool existsIp6 = ipRuleExistsForRange(priority, range, action, IP_RULE_V6); 285 EXPECT_EQ(existsIp4, existsIp6); 286 return existsIp4; 287} 288 289TEST_F(BinderTest, TestNetworkRejectNonSecureVpn) { 290 constexpr uint32_t RULE_PRIORITY = 12500; 291 292 constexpr int baseUid = AID_USER_OFFSET * 5; 293 std::vector<UidRange> uidRanges = { 294 {baseUid + 150, baseUid + 224}, 295 {baseUid + 226, baseUid + 300} 296 }; 297 298 const std::vector<std::string> initialRulesV4 = listIpRules(IP_RULE_V4); 299 const std::vector<std::string> initialRulesV6 = listIpRules(IP_RULE_V6); 300 301 // Create two valid rules. 302 ASSERT_TRUE(mNetd->networkRejectNonSecureVpn(true, uidRanges).isOk()); 303 EXPECT_EQ(initialRulesV4.size() + 2, listIpRules(IP_RULE_V4).size()); 304 EXPECT_EQ(initialRulesV6.size() + 2, listIpRules(IP_RULE_V6).size()); 305 for (auto const& range : uidRanges) { 306 EXPECT_TRUE(ipRuleExistsForRange(RULE_PRIORITY, range, "prohibit")); 307 } 308 309 // Remove the rules. 310 ASSERT_TRUE(mNetd->networkRejectNonSecureVpn(false, uidRanges).isOk()); 311 EXPECT_EQ(initialRulesV4.size(), listIpRules(IP_RULE_V4).size()); 312 EXPECT_EQ(initialRulesV6.size(), listIpRules(IP_RULE_V6).size()); 313 for (auto const& range : uidRanges) { 314 EXPECT_FALSE(ipRuleExistsForRange(RULE_PRIORITY, range, "prohibit")); 315 } 316 317 // Fail to remove the rules a second time after they are already deleted. 318 binder::Status status = mNetd->networkRejectNonSecureVpn(false, uidRanges); 319 ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode()); 320 EXPECT_EQ(ENOENT, status.serviceSpecificErrorCode()); 321 322 // All rules should be the same as before. 323 EXPECT_EQ(initialRulesV4, listIpRules(IP_RULE_V4)); 324 EXPECT_EQ(initialRulesV6, listIpRules(IP_RULE_V6)); 325} 326 327// Create a socket pair that isLoopbackSocket won't think is local. 328void BinderTest::fakeRemoteSocketPair(int *clientSocket, int *serverSocket, int *acceptedSocket) { 329 *serverSocket = socket(AF_INET6, SOCK_STREAM, 0); 330 struct sockaddr_in6 server6 = { .sin6_family = AF_INET6, .sin6_addr = sTun.dstAddr() }; 331 ASSERT_EQ(0, bind(*serverSocket, (struct sockaddr *) &server6, sizeof(server6))); 332 333 socklen_t addrlen = sizeof(server6); 334 ASSERT_EQ(0, getsockname(*serverSocket, (struct sockaddr *) &server6, &addrlen)); 335 ASSERT_EQ(0, listen(*serverSocket, 10)); 336 337 *clientSocket = socket(AF_INET6, SOCK_STREAM, 0); 338 struct sockaddr_in6 client6 = { .sin6_family = AF_INET6, .sin6_addr = sTun.srcAddr() }; 339 ASSERT_EQ(0, bind(*clientSocket, (struct sockaddr *) &client6, sizeof(client6))); 340 ASSERT_EQ(0, connect(*clientSocket, (struct sockaddr *) &server6, sizeof(server6))); 341 ASSERT_EQ(0, getsockname(*clientSocket, (struct sockaddr *) &client6, &addrlen)); 342 343 *acceptedSocket = accept(*serverSocket, (struct sockaddr *) &server6, &addrlen); 344 ASSERT_NE(-1, *acceptedSocket); 345 346 ASSERT_EQ(0, memcmp(&client6, &server6, sizeof(client6))); 347} 348 349void checkSocketpairOpen(int clientSocket, int acceptedSocket) { 350 char buf[4096]; 351 EXPECT_EQ(4, write(clientSocket, "foo", sizeof("foo"))); 352 EXPECT_EQ(4, read(acceptedSocket, buf, sizeof(buf))); 353 EXPECT_EQ(0, memcmp(buf, "foo", sizeof("foo"))); 354} 355 356void checkSocketpairClosed(int clientSocket, int acceptedSocket) { 357 // Check that the client socket was closed with ECONNABORTED. 358 int ret = write(clientSocket, "foo", sizeof("foo")); 359 int err = errno; 360 EXPECT_EQ(-1, ret); 361 EXPECT_EQ(ECONNABORTED, err); 362 363 // Check that it sent a RST to the server. 364 ret = write(acceptedSocket, "foo", sizeof("foo")); 365 err = errno; 366 EXPECT_EQ(-1, ret); 367 EXPECT_EQ(ECONNRESET, err); 368} 369 370TEST_F(BinderTest, TestSocketDestroy) { 371 int clientSocket, serverSocket, acceptedSocket; 372 ASSERT_NO_FATAL_FAILURE(fakeRemoteSocketPair(&clientSocket, &serverSocket, &acceptedSocket)); 373 374 // Pick a random UID in the system UID range. 375 constexpr int baseUid = AID_APP - 2000; 376 static_assert(baseUid > 0, "Not enough UIDs? Please fix this test."); 377 int uid = baseUid + 500 + arc4random_uniform(1000); 378 EXPECT_EQ(0, fchown(clientSocket, uid, -1)); 379 380 // UID ranges that don't contain uid. 381 std::vector<UidRange> uidRanges = { 382 {baseUid + 42, baseUid + 449}, 383 {baseUid + 1536, AID_APP - 4}, 384 {baseUid + 498, uid - 1}, 385 {uid + 1, baseUid + 1520}, 386 }; 387 // A skip list that doesn't contain UID. 388 std::vector<int32_t> skipUids { baseUid + 123, baseUid + 1600 }; 389 390 // Close sockets. Our test socket should be intact. 391 EXPECT_TRUE(mNetd->socketDestroy(uidRanges, skipUids).isOk()); 392 checkSocketpairOpen(clientSocket, acceptedSocket); 393 394 // UID ranges that do contain uid. 395 uidRanges = { 396 {baseUid + 42, baseUid + 449}, 397 {baseUid + 1536, AID_APP - 4}, 398 {baseUid + 498, baseUid + 1520}, 399 }; 400 // Add uid to the skip list. 401 skipUids.push_back(uid); 402 403 // Close sockets. Our test socket should still be intact because it's in the skip list. 404 EXPECT_TRUE(mNetd->socketDestroy(uidRanges, skipUids).isOk()); 405 checkSocketpairOpen(clientSocket, acceptedSocket); 406 407 // Now remove uid from skipUids, and close sockets. Our test socket should have been closed. 408 skipUids.resize(skipUids.size() - 1); 409 EXPECT_TRUE(mNetd->socketDestroy(uidRanges, skipUids).isOk()); 410 checkSocketpairClosed(clientSocket, acceptedSocket); 411 412 close(clientSocket); 413 close(serverSocket); 414 close(acceptedSocket); 415} 416 417namespace { 418 419int netmaskToPrefixLength(const uint8_t *buf, size_t buflen) { 420 if (buf == nullptr) return -1; 421 422 int prefixLength = 0; 423 bool endOfContiguousBits = false; 424 for (unsigned int i = 0; i < buflen; i++) { 425 const uint8_t value = buf[i]; 426 427 // Bad bit sequence: check for a contiguous set of bits from the high 428 // end by verifying that the inverted value + 1 is a power of 2 429 // (power of 2 iff. (v & (v - 1)) == 0). 430 const uint8_t inverse = ~value + 1; 431 if ((inverse & (inverse - 1)) != 0) return -1; 432 433 prefixLength += (value == 0) ? 0 : CHAR_BIT - ffs(value) + 1; 434 435 // Bogus netmask. 436 if (endOfContiguousBits && value != 0) return -1; 437 438 if (value != 0xff) endOfContiguousBits = true; 439 } 440 441 return prefixLength; 442} 443 444template<typename T> 445int netmaskToPrefixLength(const T *p) { 446 return netmaskToPrefixLength(reinterpret_cast<const uint8_t*>(p), sizeof(T)); 447} 448 449 450static bool interfaceHasAddress( 451 const std::string &ifname, const char *addrString, int prefixLength) { 452 struct addrinfo *addrinfoList = nullptr; 453 ScopedAddrinfo addrinfoCleanup(addrinfoList); 454 455 const struct addrinfo hints = { 456 .ai_flags = AI_NUMERICHOST, 457 .ai_family = AF_UNSPEC, 458 .ai_socktype = SOCK_DGRAM, 459 }; 460 if (getaddrinfo(addrString, nullptr, &hints, &addrinfoList) != 0 || 461 addrinfoList == nullptr || addrinfoList->ai_addr == nullptr) { 462 return false; 463 } 464 465 struct ifaddrs *ifaddrsList = nullptr; 466 ScopedIfaddrs ifaddrsCleanup(ifaddrsList); 467 468 if (getifaddrs(&ifaddrsList) != 0) { 469 return false; 470 } 471 472 for (struct ifaddrs *addr = ifaddrsList; addr != nullptr; addr = addr->ifa_next) { 473 if (std::string(addr->ifa_name) != ifname || 474 addr->ifa_addr == nullptr || 475 addr->ifa_addr->sa_family != addrinfoList->ai_addr->sa_family) { 476 continue; 477 } 478 479 switch (addr->ifa_addr->sa_family) { 480 case AF_INET: { 481 auto *addr4 = reinterpret_cast<const struct sockaddr_in*>(addr->ifa_addr); 482 auto *want = reinterpret_cast<const struct sockaddr_in*>(addrinfoList->ai_addr); 483 if (memcmp(&addr4->sin_addr, &want->sin_addr, sizeof(want->sin_addr)) != 0) { 484 continue; 485 } 486 487 if (prefixLength < 0) return true; // not checking prefix lengths 488 489 if (addr->ifa_netmask == nullptr) return false; 490 auto *nm = reinterpret_cast<const struct sockaddr_in*>(addr->ifa_netmask); 491 EXPECT_EQ(prefixLength, netmaskToPrefixLength(&nm->sin_addr)); 492 return (prefixLength == netmaskToPrefixLength(&nm->sin_addr)); 493 } 494 case AF_INET6: { 495 auto *addr6 = reinterpret_cast<const struct sockaddr_in6*>(addr->ifa_addr); 496 auto *want = reinterpret_cast<const struct sockaddr_in6*>(addrinfoList->ai_addr); 497 if (memcmp(&addr6->sin6_addr, &want->sin6_addr, sizeof(want->sin6_addr)) != 0) { 498 continue; 499 } 500 501 if (prefixLength < 0) return true; // not checking prefix lengths 502 503 if (addr->ifa_netmask == nullptr) return false; 504 auto *nm = reinterpret_cast<const struct sockaddr_in6*>(addr->ifa_netmask); 505 EXPECT_EQ(prefixLength, netmaskToPrefixLength(&nm->sin6_addr)); 506 return (prefixLength == netmaskToPrefixLength(&nm->sin6_addr)); 507 } 508 default: 509 // Cannot happen because we have already screened for matching 510 // address families at the top of each iteration. 511 continue; 512 } 513 } 514 515 return false; 516} 517 518} // namespace 519 520TEST_F(BinderTest, TestInterfaceAddRemoveAddress) { 521 static const struct TestData { 522 const char *addrString; 523 const int prefixLength; 524 const bool expectSuccess; 525 } kTestData[] = { 526 { "192.0.2.1", 24, true }, 527 { "192.0.2.2", 25, true }, 528 { "192.0.2.3", 32, true }, 529 { "192.0.2.4", 33, false }, 530 { "192.not.an.ip", 24, false }, 531 { "2001:db8::1", 64, true }, 532 { "2001:db8::2", 65, true }, 533 { "2001:db8::3", 128, true }, 534 { "2001:db8::4", 129, false }, 535 { "foo:bar::bad", 64, false }, 536 }; 537 538 for (unsigned int i = 0; i < arraysize(kTestData); i++) { 539 const auto &td = kTestData[i]; 540 541 // [1.a] Add the address. 542 binder::Status status = mNetd->interfaceAddAddress( 543 sTun.name(), td.addrString, td.prefixLength); 544 if (td.expectSuccess) { 545 EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); 546 } else { 547 ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode()); 548 ASSERT_NE(0, status.serviceSpecificErrorCode()); 549 } 550 551 // [1.b] Verify the addition meets the expectation. 552 if (td.expectSuccess) { 553 EXPECT_TRUE(interfaceHasAddress(sTun.name(), td.addrString, td.prefixLength)); 554 } else { 555 EXPECT_FALSE(interfaceHasAddress(sTun.name(), td.addrString, -1)); 556 } 557 558 // [2.a] Try to remove the address. If it was not previously added, removing it fails. 559 status = mNetd->interfaceDelAddress(sTun.name(), td.addrString, td.prefixLength); 560 if (td.expectSuccess) { 561 EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); 562 } else { 563 ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode()); 564 ASSERT_NE(0, status.serviceSpecificErrorCode()); 565 } 566 567 // [2.b] No matter what, the address should not be present. 568 EXPECT_FALSE(interfaceHasAddress(sTun.name(), td.addrString, -1)); 569 } 570} 571 572TEST_F(BinderTest, TestSetProcSysNet) { 573 static const struct TestData { 574 const int family; 575 const int which; 576 const char *ifname; 577 const char *parameter; 578 const char *value; 579 const int expectedReturnCode; 580 } kTestData[] = { 581 { INetd::IPV4, INetd::CONF, sTun.name().c_str(), "arp_ignore", "1", 0 }, 582 { -1, INetd::CONF, sTun.name().c_str(), "arp_ignore", "1", EAFNOSUPPORT }, 583 { INetd::IPV4, -1, sTun.name().c_str(), "arp_ignore", "1", EINVAL }, 584 { INetd::IPV4, INetd::CONF, "..", "conf/lo/arp_ignore", "1", EINVAL }, 585 { INetd::IPV4, INetd::CONF, ".", "lo/arp_ignore", "1", EINVAL }, 586 { INetd::IPV4, INetd::CONF, sTun.name().c_str(), "../all/arp_ignore", "1", EINVAL }, 587 { INetd::IPV6, INetd::NEIGH, sTun.name().c_str(), "ucast_solicit", "7", 0 }, 588 }; 589 590 for (unsigned int i = 0; i < arraysize(kTestData); i++) { 591 const auto &td = kTestData[i]; 592 593 const binder::Status status = mNetd->setProcSysNet( 594 td.family, td.which, td.ifname, td.parameter, 595 td.value); 596 597 if (td.expectedReturnCode == 0) { 598 SCOPED_TRACE(String8::format("test case %d should have passed", i)); 599 EXPECT_EQ(0, status.exceptionCode()); 600 EXPECT_EQ(0, status.serviceSpecificErrorCode()); 601 } else { 602 SCOPED_TRACE(String8::format("test case %d should have failed", i)); 603 EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode()); 604 EXPECT_EQ(td.expectedReturnCode, status.serviceSpecificErrorCode()); 605 } 606 } 607} 608