OSDN Git Service

Merge "Drop PROHIBIT_NON_VPN priority 11500 -> 12500" into nyc-dev
authorRobin Lee <rgl@google.com>
Tue, 17 May 2016 16:19:40 +0000 (16:19 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Tue, 17 May 2016 16:19:40 +0000 (16:19 +0000)
server/FirewallController.cpp
server/FirewallController.h
server/FirewallControllerTest.cpp
server/IptablesBaseTest.cpp
server/NetworkController.cpp
server/RouteController.cpp
tests/binder_test.cpp
tests/dns_responder.cpp
tests/netd_test.cpp

index 7bb883d..0a06b9d 100644 (file)
@@ -290,59 +290,44 @@ int FirewallController::detachChain(const char* childChain, const char* parentCh
 
 int FirewallController::createChain(const char* childChain,
         const char* parentChain, FirewallType type) {
-    // Order is important, otherwise later steps may fail.
     execIptablesSilently(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
-    execIptablesSilently(V4V6, "-t", TABLE, "-F", childChain, NULL);
-    execIptablesSilently(V4V6, "-t", TABLE, "-X", childChain, NULL);
-    int res = 0;
-    res |= execIptables(V4V6, "-t", TABLE, "-N", childChain, NULL);
+    std::vector<int32_t> uids;
+    return replaceUidChain(childChain, type == WHITELIST, uids);
+}
+
+std::string FirewallController::makeUidRules(IptablesTarget target, const char *name,
+        bool isWhitelist, const std::vector<int32_t>& uids) {
+    std::string commands;
+    StringAppendF(&commands, "*filter\n:%s -\n", name);
 
     // Allow TCP RSTs so we can cleanly close TCP connections of apps that no longer have network
     // access. Both incoming and outgoing RSTs are allowed.
-    res |= execIptables(V4V6, "-A", childChain, "-p", "tcp",
-            "--tcp-flags", "RST", "RST", "-j", "RETURN", NULL);
+    StringAppendF(&commands, "-A %s -p tcp --tcp-flags RST RST -j RETURN\n", name);
 
-    if (type == WHITELIST) {
+    if (isWhitelist) {
         // Allow ICMPv6 packets necessary to make IPv6 connectivity work. http://b/23158230 .
-        for (size_t i = 0; i < ARRAY_SIZE(ICMPV6_TYPES); i++) {
-            res |= execIptables(V6, "-A", childChain, "-p", "icmpv6", "--icmpv6-type",
-                    ICMPV6_TYPES[i], "-j", "RETURN", NULL);
+        if (target == V6) {
+            for (size_t i = 0; i < ARRAY_SIZE(ICMPV6_TYPES); i++) {
+                StringAppendF(&commands, "-A %s -p icmpv6 --icmpv6-type %s -j RETURN\n",
+                       name, ICMPV6_TYPES[i]);
+            }
         }
 
-        // create default white list for system uid range
-        char uidStr[16];
-        sprintf(uidStr, "0-%d", MAX_SYSTEM_UID);
-        res |= execIptables(V4V6, "-A", childChain, "-m", "owner", "--uid-owner",
-                uidStr, "-j", "RETURN", NULL);
-
-        // create default rule to drop all traffic
-        res |= execIptables(V4V6, "-A", childChain, "-j", "DROP", NULL);
-    }
-    return res;
-}
-
-std::string FirewallController::makeUidRules(
-        const char *name, bool isWhitelist, const std::vector<int32_t>& uids) {
-    const char *action = isWhitelist ? "RETURN" : "DROP";
-    const char *defaultAction = isWhitelist ? "DROP" : "RETURN";
-
-    std::string commands;
-
-    StringAppendF(&commands, "*filter\n:%s -\n", name);
-
-    if (isWhitelist) {
         // Always whitelist system UIDs.
         StringAppendF(&commands,
-                "-A %s -m owner --uid-owner %d-%d -j %s\n", name, 0, MAX_SYSTEM_UID, action);
+                "-A %s -m owner --uid-owner %d-%d -j RETURN\n", name, 0, MAX_SYSTEM_UID);
     }
 
+    // Whitelist or blacklist the specified UIDs.
+    const char *action = isWhitelist ? "RETURN" : "DROP";
     for (auto uid : uids) {
         StringAppendF(&commands, "-A %s -m owner --uid-owner %d -j %s\n", name, uid, action);
     }
 
-    // If it's a blacklist chain that blacklists nothing, then don't add a default action.
-    if (isWhitelist || uids.size() > 0) {
-        StringAppendF(&commands, "-A %s -j %s\n", name, defaultAction);
+    // If it's a whitelist chain, add a default DROP at the end. This is not necessary for a
+    // blacklist chain, because all user-defined chains implicitly RETURN at the end.
+    if (isWhitelist) {
+        StringAppendF(&commands, "-A %s -j DROP\n", name);
     }
 
     StringAppendF(&commands, "COMMIT\n\x04");  // EOT.
@@ -352,6 +337,7 @@ std::string FirewallController::makeUidRules(
 
 int FirewallController::replaceUidChain(
         const char *name, bool isWhitelist, const std::vector<int32_t>& uids) {
-   std::string commands = makeUidRules(name, isWhitelist, uids);
-   return execIptablesRestore(V4V6, commands.c_str());
+   std::string commands4 = makeUidRules(V4, name, isWhitelist, uids);
+   std::string commands6 = makeUidRules(V6, name, isWhitelist, uids);
+   return execIptablesRestore(V4, commands4.c_str()) | execIptablesRestore(V6, commands6.c_str());
 }
index 0854c20..d78b461 100644 (file)
@@ -83,7 +83,8 @@ public:
 
 protected:
     friend class FirewallControllerTest;
-    std::string makeUidRules(const char *name, bool isWhitelist, const std::vector<int32_t>& uids);
+    std::string makeUidRules(IptablesTarget target, const char *name, bool isWhitelist,
+                             const std::vector<int32_t>& uids);
     static int (*execIptables)(IptablesTarget target, ...);
     static int (*execIptablesSilently)(IptablesTarget target, ...);
     static int (*execIptablesRestore)(IptablesTarget target, const std::string& commands);
index b909833..c1226b2 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <gtest/gtest.h>
 
+#include <android-base/strings.h>
+
 #include "FirewallController.h"
 #include "IptablesBaseTest.h"
 
@@ -35,46 +37,73 @@ protected:
     }
     FirewallController mFw;
 
-    std::string makeUidRules(const char *a, bool b, const std::vector<int32_t>& c) {
-        return mFw.makeUidRules(a, b, c);
+    std::string makeUidRules(IptablesTarget a, const char* b, bool c,
+                             const std::vector<int32_t>& d) {
+        return mFw.makeUidRules(a, b, c, d);
     }
 
-    int createChain(const char* a, const char*b , FirewallType c) {
+    int createChain(const char* a, const char* b , FirewallType c) {
         return mFw.createChain(a, b, c);
     }
 };
 
 
 TEST_F(FirewallControllerTest, TestCreateWhitelistChain) {
-    ExpectedIptablesCommands expected = {
+    ExpectedIptablesCommands expectedCommands = {
         { V4V6, "-t filter -D INPUT -j fw_whitelist" },
-        { V4V6, "-t filter -F fw_whitelist" },
-        { V4V6, "-t filter -X fw_whitelist" },
-        { V4V6, "-t filter -N fw_whitelist" },
-        { V4V6, "-A fw_whitelist -p tcp --tcp-flags RST RST -j RETURN" },
-        { V6,   "-A fw_whitelist -p icmpv6 --icmpv6-type packet-too-big -j RETURN" },
-        { V6,   "-A fw_whitelist -p icmpv6 --icmpv6-type router-solicitation -j RETURN" },
-        { V6,   "-A fw_whitelist -p icmpv6 --icmpv6-type router-advertisement -j RETURN" },
-        { V6,   "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN" },
-        { V6,   "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN" },
-        { V6,   "-A fw_whitelist -p icmpv6 --icmpv6-type redirect -j RETURN" },
-        { V4V6, "-A fw_whitelist -m owner --uid-owner 0-9999 -j RETURN" },
-        { V4V6, "-A fw_whitelist -j DROP" },
     };
+
+    std::vector<std::string> expectedRestore4 = {
+        "*filter",
+        ":fw_whitelist -",
+        "-A fw_whitelist -p tcp --tcp-flags RST RST -j RETURN",
+        "-A fw_whitelist -m owner --uid-owner 0-9999 -j RETURN",
+        "-A fw_whitelist -j DROP",
+        "COMMIT\n\x04"
+    };
+    std::vector<std::string> expectedRestore6 = {
+        "*filter",
+        ":fw_whitelist -",
+        "-A fw_whitelist -p tcp --tcp-flags RST RST -j RETURN",
+        "-A fw_whitelist -p icmpv6 --icmpv6-type packet-too-big -j RETURN",
+        "-A fw_whitelist -p icmpv6 --icmpv6-type router-solicitation -j RETURN",
+        "-A fw_whitelist -p icmpv6 --icmpv6-type router-advertisement -j RETURN",
+        "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN",
+        "-A fw_whitelist -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN",
+        "-A fw_whitelist -p icmpv6 --icmpv6-type redirect -j RETURN",
+        "-A fw_whitelist -m owner --uid-owner 0-9999 -j RETURN",
+        "-A fw_whitelist -j DROP",
+        "COMMIT\n\x04"
+    };
+    std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
+        { V4, android::base::Join(expectedRestore4, '\n') },
+        { V6, android::base::Join(expectedRestore6, '\n') },
+    };
+
     createChain("fw_whitelist", "INPUT", WHITELIST);
-    expectIptablesCommands(expected);
+    expectIptablesCommands(expectedCommands);
+    expectIptablesRestoreCommands(expectedRestoreCommands);
 }
 
 TEST_F(FirewallControllerTest, TestCreateBlacklistChain) {
-    ExpectedIptablesCommands expected = {
+    ExpectedIptablesCommands expectedCommands = {
         { V4V6, "-t filter -D INPUT -j fw_blacklist" },
-        { V4V6, "-t filter -F fw_blacklist" },
-        { V4V6, "-t filter -X fw_blacklist" },
-        { V4V6, "-t filter -N fw_blacklist" },
-        { V4V6, "-A fw_blacklist -p tcp --tcp-flags RST RST -j RETURN" },
     };
+
+    std::vector<std::string> expectedRestore = {
+        "*filter",
+        ":fw_blacklist -",
+        "-A fw_blacklist -p tcp --tcp-flags RST RST -j RETURN",
+        "COMMIT\n\x04"
+    };
+    std::vector<std::pair<IptablesTarget, std::string>> expectedRestoreCommands = {
+        { V4, android::base::Join(expectedRestore, '\n') },
+        { V6, android::base::Join(expectedRestore, '\n') },
+    };
+
     createChain("fw_blacklist", "INPUT", BLACKLIST);
-    expectIptablesCommands(expected);
+    expectIptablesCommands(expectedCommands);
+    expectIptablesRestoreCommands(expectedRestoreCommands);
 }
 
 TEST_F(FirewallControllerTest, TestSetStandbyRule) {
@@ -109,6 +138,13 @@ TEST_F(FirewallControllerTest, TestReplaceWhitelistUidRule) {
     std::string expected =
             "*filter\n"
             ":FW_whitechain -\n"
+            "-A FW_whitechain -p tcp --tcp-flags RST RST -j RETURN\n"
+            "-A FW_whitechain -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
+            "-A FW_whitechain -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
+            "-A FW_whitechain -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
+            "-A FW_whitechain -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
+            "-A FW_whitechain -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
+            "-A FW_whitechain -p icmpv6 --icmpv6-type redirect -j RETURN\n"
             "-A FW_whitechain -m owner --uid-owner 0-9999 -j RETURN\n"
             "-A FW_whitechain -m owner --uid-owner 10023 -j RETURN\n"
             "-A FW_whitechain -m owner --uid-owner 10059 -j RETURN\n"
@@ -121,19 +157,19 @@ TEST_F(FirewallControllerTest, TestReplaceWhitelistUidRule) {
             "COMMIT\n\x04";
 
     std::vector<int32_t> uids = { 10023, 10059, 10124, 10111, 110122, 210153, 210024 };
-    EXPECT_EQ(expected, makeUidRules("FW_whitechain", true, uids));
+    EXPECT_EQ(expected, makeUidRules(V6, "FW_whitechain", true, uids));
 }
 
 TEST_F(FirewallControllerTest, TestReplaceBlacklistUidRule) {
     std::string expected =
             "*filter\n"
             ":FW_blackchain -\n"
+            "-A FW_blackchain -p tcp --tcp-flags RST RST -j RETURN\n"
             "-A FW_blackchain -m owner --uid-owner 10023 -j DROP\n"
             "-A FW_blackchain -m owner --uid-owner 10059 -j DROP\n"
             "-A FW_blackchain -m owner --uid-owner 10124 -j DROP\n"
-            "-A FW_blackchain -j RETURN\n"
             "COMMIT\n\x04";
 
     std::vector<int32_t> uids = { 10023, 10059, 10124 };
-    EXPECT_EQ(expected, makeUidRules("FW_blackchain", false, uids));
+    EXPECT_EQ(expected, makeUidRules(V4 ,"FW_blackchain", false, uids));
 }
index 5ce6667..1502c4b 100644 (file)
@@ -70,12 +70,20 @@ int IptablesBaseTest::fakeExecIptablesRestore(IptablesTarget target, const std::
 
 int IptablesBaseTest::expectIptablesCommand(IptablesTarget target, int pos,
                                             const std::string& cmd) {
+
+    if ((unsigned) pos >= sCmds.size()) {
+        ADD_FAILURE() << "Expected too many iptables commands, want command "
+               << pos + 1 << "/" << sCmds.size();
+        return -1;
+    }
+
     if (target == V4 || target == V4V6) {
         EXPECT_EQ("/system/bin/iptables -w " + cmd, sCmds[pos++]);
     }
     if (target == V6 || target == V4V6) {
         EXPECT_EQ("/system/bin/ip6tables -w " + cmd, sCmds[pos++]);
     }
+
     return target == V4V6 ? 2 : 1;
 }
 
@@ -92,7 +100,12 @@ void IptablesBaseTest::expectIptablesCommands(const ExpectedIptablesCommands& ex
     for (size_t i = 0; i < expectedCmds.size(); i ++) {
         auto target = expectedCmds[i].first;
         auto cmd = expectedCmds[i].second;
-        pos += expectIptablesCommand(target, pos, cmd);
+        int numConsumed = expectIptablesCommand(target, pos, cmd);
+        if (numConsumed < 0) {
+            // Read past the end of the array.
+            break;
+        }
+        pos += numConsumed;
     }
 
     EXPECT_EQ(pos, sCmds.size());
index 8b1f84e..3364577 100644 (file)
@@ -135,7 +135,8 @@ int NetworkController::DelegateImpl::modifyFallthrough(const std::string& physic
 }
 
 NetworkController::NetworkController() :
-        mDelegateImpl(new NetworkController::DelegateImpl(this)), mDefaultNetId(NETID_UNSET) {
+        mDelegateImpl(new NetworkController::DelegateImpl(this)), mDefaultNetId(NETID_UNSET),
+        mProtectableUsers({AID_VPN}) {
     mNetworks[LOCAL_NET_ID] = new LocalNetwork(LOCAL_NET_ID);
     mNetworks[DUMMY_NET_ID] = new DummyNetwork(DUMMY_NET_ID);
 }
index 4e43a47..fa39c89 100644 (file)
@@ -736,8 +736,8 @@ WARN_UNUSED_RESULT int addDirectlyConnectedRule() {
 // behaviour. We do flush the kernel-default rules at startup, but having an explicit unreachable
 // rule will hopefully make things even clearer.
 WARN_UNUSED_RESULT int addUnreachableRule() {
-    return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, RT_TABLE_UNSPEC, MARK_UNSET,
-                        MARK_UNSET);
+    return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, FR_ACT_UNREACHABLE, RT_TABLE_UNSPEC,
+                        MARK_UNSET, MARK_UNSET, IIF_NONE, OIF_NONE, INVALID_UID, INVALID_UID);
 }
 
 WARN_UNUSED_RESULT int modifyLocalNetwork(unsigned netId, const char* interface, bool add) {
index 6785c78..565db99 100644 (file)
@@ -140,15 +140,15 @@ TEST_F(BinderTest, TestFirewallReplaceUidChain) {
         mNetd->firewallReplaceUidChain(String16(chainName.c_str()), true, uids, &ret);
     }
     EXPECT_EQ(true, ret);
-    EXPECT_EQ((int) uids.size() + 4, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
-    EXPECT_EQ((int) uids.size() + 4, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
+    EXPECT_EQ((int) uids.size() + 5, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
+    EXPECT_EQ((int) uids.size() + 11, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
     {
         TimedOperation op("Clearing whitelist chain");
         mNetd->firewallReplaceUidChain(String16(chainName.c_str()), false, noUids, &ret);
     }
     EXPECT_EQ(true, ret);
-    EXPECT_EQ(2, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
-    EXPECT_EQ(2, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
+    EXPECT_EQ(3, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
+    EXPECT_EQ(3, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
 
     {
         TimedOperation op(StringPrintf("Programming %d-UID blacklist chain", kNumUids));
@@ -163,8 +163,8 @@ TEST_F(BinderTest, TestFirewallReplaceUidChain) {
         mNetd->firewallReplaceUidChain(String16(chainName.c_str()), false, noUids, &ret);
     }
     EXPECT_EQ(true, ret);
-    EXPECT_EQ(2, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
-    EXPECT_EQ(2, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
+    EXPECT_EQ(3, iptablesRuleLineLength(IPTABLES_PATH, chainName.c_str()));
+    EXPECT_EQ(3, iptablesRuleLineLength(IP6TABLES_PATH, chainName.c_str()));
 
     // Check that the call fails if iptables returns an error.
     std::string veryLongStringName = "netd_binder_test_UnacceptablyLongIptablesChainName";
index 4b77b62..6094ca1 100644 (file)
@@ -802,7 +802,7 @@ bool DNSResponder::addAnswerRecords(const DNSQuestion& question,
     record.name = question.qname;
     record.rtype = question.qtype;
     record.rclass = ns_class::ns_c_in;
-    record.ttl = 1;
+    record.ttl = 5;  // seconds
     if (question.qtype == ns_type::ns_t_a) {
         record.rdata.resize(4);
         if (inet_pton(AF_INET, it->second.c_str(), record.rdata.data()) != 1) {
index d2d1428..5093775 100644 (file)
@@ -763,3 +763,40 @@ TEST_F(ResolverTest, EmptySetup) {
     EXPECT_EQ(params[INetd::RESOLVER_PARAMS_MIN_SAMPLES], res_params.min_samples);
     EXPECT_EQ(params[INetd::RESOLVER_PARAMS_MAX_SAMPLES], res_params.max_samples);
 }
+
+TEST_F(ResolverTest, SearchPathChange) {
+    addrinfo* result = nullptr;
+
+    const char* listen_addr = "127.0.0.13";
+    const char* listen_srv = "53";
+    const char* host_name1 = "test13.domain1.org.";
+    const char* host_name2 = "test13.domain2.org.";
+    test::DNSResponder dns(listen_addr, listen_srv, 250,
+                           ns_rcode::ns_r_servfail, 1.0);
+    dns.addMapping(host_name1, ns_type::ns_t_aaaa, "2001:db8::13");
+    dns.addMapping(host_name2, ns_type::ns_t_aaaa, "2001:db8::1:13");
+    ASSERT_TRUE(dns.startServer());
+    std::vector<std::string> servers = { listen_addr };
+    std::vector<std::string> domains = { "domain1.org" };
+    ASSERT_TRUE(SetResolversForNetwork(domains, servers, mDefaultParams));
+
+    addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_INET6;
+    EXPECT_EQ(0, getaddrinfo("test13", nullptr, &hints, &result));
+    EXPECT_EQ(1U, dns.queries().size());
+    EXPECT_EQ(1U, GetNumQueries(dns, host_name1));
+    EXPECT_EQ("2001:db8::13", ToString(result));
+    if (result) freeaddrinfo(result);
+
+    // Test that changing the domain search path on its own works.
+    domains = { "domain2.org" };
+    ASSERT_TRUE(SetResolversForNetwork(domains, servers, mDefaultParams));
+    dns.clearQueries();
+
+    EXPECT_EQ(0, getaddrinfo("test13", nullptr, &hints, &result));
+    EXPECT_EQ(1U, dns.queries().size());
+    EXPECT_EQ(1U, GetNumQueries(dns, host_name2));
+    EXPECT_EQ("2001:db8::1:13", ToString(result));
+    if (result) freeaddrinfo(result);
+}