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