1 /*
2 * Copyright (C) 2019 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
17 #define LOG_TAG "resolv_callback_unit_test"
18
19 #include <sys/stat.h>
20
21 #include <android-base/file.h>
22 #include <android-base/properties.h>
23 #include <gtest/gtest.h>
24 #include <private/android_filesystem_config.h> // AID_DNS
25
26 #include "DnsResolver.h"
27 #include "getaddrinfo.h"
28 #include "resolv_cache.h"
29 #include "resolv_private.h"
30 #include "tests/resolv_test_utils.h"
31
32 namespace android::net {
33
34 using android::base::unique_fd;
35 using android::net::NetworkDnsEventReported;
36 using android::netdutils::ScopedAddrinfo;
37
38 // Use maximum reserved appId for applications to avoid conflict with existing uids.
39 const uid_t TEST_UID = 99999;
40 // Use testUid to make sure TagSocketCallback is called.
41 static uid_t testUid = 0;
42
43 // gApiLevel would be initialized in resolv_init().
44 #define SKIP_IF_APILEVEL_LESS_THAN(version) \
45 do { \
46 if (android::net::gApiLevel < (version)) { \
47 GTEST_LOG_(INFO) << "Skip. Required API version: " << (version) << "\n"; \
48 return; \
49 } \
50 } while (0)
51
getNetworkContextCallback(uint32_t,uint32_t,android_net_context *)52 void getNetworkContextCallback(uint32_t, uint32_t, android_net_context*) {
53 // No-op
54 }
55
checkCallingPermissionCallback(const char *)56 bool checkCallingPermissionCallback(const char*) {
57 // No-op
58 return true;
59 }
60
logCallback(const char *)61 void logCallback(const char*) {
62 // No-op
63 }
64
tagSocketCallback(int,uint32_t,uid_t uid,pid_t)65 int tagSocketCallback(int, uint32_t, uid_t uid, pid_t) {
66 testUid = uid;
67 return true;
68 }
69
evaluateDomainNameCallback(const android_net_context &,const char *)70 bool evaluateDomainNameCallback(const android_net_context&, const char*) {
71 // No-op
72 return true;
73 }
74
initDnsResolverCallbacks()75 void initDnsResolverCallbacks() {
76 ResolverNetdCallbacks callbacks = {
77 .check_calling_permission = &checkCallingPermissionCallback,
78 .get_network_context = &getNetworkContextCallback,
79 .log = &logCallback,
80 .tagSocket = &tagSocketCallback,
81 .evaluate_domain_name = &evaluateDomainNameCallback,
82 };
83 // It returns fail since socket 'dnsproxyd' has been occupied.
84 // But the callback funtions is configured successfully and can
85 // be tested when running unit test cases.
86 resolv_init(&callbacks);
87 }
88
resetDnsResolverCallbacks()89 void resetDnsResolverCallbacks() {
90 ResolverNetdCallbacks callbacks = {
91 .check_calling_permission = nullptr,
92 .get_network_context = nullptr,
93 .log = nullptr,
94 .tagSocket = nullptr,
95 .evaluate_domain_name = nullptr,
96 };
97 resolv_init(&callbacks);
98 }
99
resetCallbackParams()100 void resetCallbackParams() {
101 testUid = 0;
102 }
103
104 class CallbackTest : public ::testing::Test {
105 protected:
SetUp()106 void SetUp() override {
107 initDnsResolverCallbacks();
108 // Create cache for test
109 android::net::gDnsResolv->resolverCtrl.createNetworkCache(TEST_NETID);
110 }
111
TearDown()112 void TearDown() override {
113 // Reset related parameters and callback functions.
114 resetCallbackParams();
115 resetDnsResolverCallbacks();
116 // Delete cache for test
117 android::net::gDnsResolv->resolverCtrl.destroyNetworkCache(TEST_NETID);
118 }
119
SetResolvers()120 int SetResolvers() {
121 const std::vector<std::string> servers = {test::kDefaultListenAddr};
122 const std::vector<std::string> domains = {"example.com"};
123 const res_params params = {
124 .sample_validity = 300,
125 .success_threshold = 25,
126 .min_samples = 8,
127 .max_samples = 8,
128 .base_timeout_msec = 1000,
129 .retry_count = 2,
130 };
131 return resolv_set_nameservers(TEST_NETID, servers, domains, params, std::nullopt);
132 }
133
134 const android_net_context mNetcontext = {
135 .app_netid = TEST_NETID,
136 .app_mark = MARK_UNSET,
137 .dns_netid = TEST_NETID,
138 .dns_mark = MARK_UNSET,
139 .uid = TEST_UID,
140 };
141 };
142
TEST_F(CallbackTest,tagSocketCallback)143 TEST_F(CallbackTest, tagSocketCallback) {
144 // tagSocketCallback is used when supported sdk version >=30.
145 SKIP_IF_APILEVEL_LESS_THAN(30);
146
147 test::DNSResponder dns;
148 dns.addMapping(kHelloExampleCom, ns_type::ns_t_a, kHelloExampleComAddrV4);
149 ASSERT_TRUE(dns.startServer());
150 EXPECT_EQ(SetResolvers(), 0);
151
152 addrinfo* result = nullptr;
153 const addrinfo hints = {.ai_family = AF_INET};
154 NetworkDnsEventReported event;
155 // tagSocketCallback will be called.
156 const int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event);
157 ScopedAddrinfo result_cleanup(result);
158 EXPECT_EQ(testUid, TEST_UID);
159 EXPECT_EQ(rv, 0);
160 }
161
TEST_F(CallbackTest,tagSocketFchown)162 TEST_F(CallbackTest, tagSocketFchown) {
163 const uint64_t tmpApiLevel = gApiLevel;
164
165 // Expect the given socket will be fchown() with given uid.
166 gApiLevel = 30; // R
167 unique_fd sk(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
168 EXPECT_GE(sk, 3);
169 resolv_tag_socket(sk, TEST_UID, -1);
170 struct stat sb;
171 EXPECT_EQ(fstat(sk, &sb), 0);
172 EXPECT_EQ(sb.st_uid, TEST_UID);
173
174 // Expect the given socket will be fchown() with AID_DNS.
175 gApiLevel = 29; // Q
176 resolv_tag_socket(sk, TEST_UID, -1);
177 EXPECT_EQ(fstat(sk, &sb), 0);
178 EXPECT_EQ(sb.st_uid, static_cast<uid_t>(AID_DNS));
179
180 // restore API level.
181 gApiLevel = tmpApiLevel;
182 }
183
184 } // end of namespace android::net
185