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