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