• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "DnsBpfHelper"
18 
19 #include "DnsBpfHelper.h"
20 
21 #include <android-base/logging.h>
22 #include <android-modules-utils/sdk_level.h>
23 
24 namespace android {
25 namespace net {
26 
27 #define RETURN_IF_RESULT_NOT_OK(result)                                                            \
28   do {                                                                                             \
29     if (!result.ok()) {                                                                            \
30       LOG(ERROR) << "L" << __LINE__ << " " << __func__ << ": " << strerror(result.error().code()); \
31       return result.error();                                                                       \
32     }                                                                                              \
33   } while (0)
34 
35 // copied from BpfHandler.cpp
mainlineNetBpfLoadDone()36 static bool mainlineNetBpfLoadDone() {
37   return !access("/sys/fs/bpf/netd_shared/mainline_done", F_OK);
38 }
39 
40 // copied from BpfHandler.cpp
waitForNetProgsLoaded()41 static inline void waitForNetProgsLoaded() {
42   // infinite loop until success with 5/10/20/40/60/60/60... delay
43   for (int delay = 5;; delay *= 2) {
44     if (delay > 60) delay = 60;
45     if (base::WaitForProperty("init.svc.mdnsd_netbpfload", "stopped", std::chrono::seconds(delay))
46       && mainlineNetBpfLoadDone()) return;
47     LOG(WARNING) << "Waited " << delay << "s for init.svc.mdnsd_netbpfload=stopped, still waiting.";
48   }
49 }
50 
init()51 base::Result<void> DnsBpfHelper::init() {
52   if (!android::modules::sdklevel::IsAtLeastS()) {
53     LOG(ERROR) << __func__ << ": Unsupported before Android S.";
54     return base::Error(EOPNOTSUPP);
55   }
56 
57   if (!android::modules::sdklevel::IsAtLeastT()) {
58     LOG(INFO) << "performing Android S mainline NetBpfload magic!";
59     if (!mainlineNetBpfLoadDone()) {
60       // We're on S/Sv2 & it's the first time netd is starting up (unless crashlooping)
61       if (!base::SetProperty("ctl.start", "mdnsd_netbpfload")) {
62         LOG(ERROR) << "Failed to set property ctl.start=mdnsd_netbpfload, see dmesg for reason.";
63         return base::Error(ENOEXEC);
64       }
65 
66       LOG(INFO) << "Waiting for Networking BPF programs";
67       waitForNetProgsLoaded();
68       LOG(INFO) << "Networking BPF programs are loaded";
69     }
70     return {};
71   }
72 
73   RETURN_IF_RESULT_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
74   RETURN_IF_RESULT_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH));
75   RETURN_IF_RESULT_NOT_OK(mDataSaverEnabledMap.init(DATA_SAVER_ENABLED_MAP_PATH));
76   return {};
77 }
78 
isUidNetworkingBlocked(uid_t uid,bool metered)79 base::Result<bool> DnsBpfHelper::isUidNetworkingBlocked(uid_t uid, bool metered) {
80   if (is_system_uid(uid)) return false;
81   if (!mConfigurationMap.isValid() || !mUidOwnerMap.isValid()) {
82     LOG(ERROR) << __func__
83                << ": BPF maps are not ready. Forgot to call ADnsHelper_init?";
84     return base::Error(EUNATCH);
85   }
86 
87   auto enabledRules = mConfigurationMap.readValue(UID_RULES_CONFIGURATION_KEY);
88   RETURN_IF_RESULT_NOT_OK(enabledRules);
89 
90   auto value = mUidOwnerMap.readValue(uid);
91   uint32_t uidRules = value.ok() ? value.value().rule : 0;
92 
93   // For doze mode, battery saver, low power standby.
94   if (isBlockedByUidRules(enabledRules.value(), uidRules)) return true;
95 
96   // For data saver.
97   // DataSaverEnabled map on V+ platforms is the only reliable source of information about the
98   // current data saver status. While ConnectivityService offers two ways to update this map for U
99   // and V+, the U- platform implementation can have delays, potentially leading to inaccurate
100   // results. Conversely, the V+ platform implementation is synchronized with the actual data saver
101   // state, making it a trustworthy source. Since this library primarily serves DNS resolvers,
102   // relying solely on V+ data prevents erroneous blocking of DNS queries.
103   if (android::modules::sdklevel::IsAtLeastV() && metered) {
104     // The background data setting (PENALTY_BOX_USER_MATCH, PENALTY_BOX_ADMIN_MATCH) and
105     // unrestricted data usage setting (HAPPY_BOX_MATCH) for individual apps override the system
106     // wide Data Saver setting.
107     if (uidRules & (PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH)) return true;
108     if (uidRules & HAPPY_BOX_MATCH) return false;
109 
110     auto dataSaverSetting = mDataSaverEnabledMap.readValue(DATA_SAVER_ENABLED_KEY);
111     RETURN_IF_RESULT_NOT_OK(dataSaverSetting);
112     return dataSaverSetting.value();
113   }
114 
115   return false;
116 }
117 
118 }  // namespace net
119 }  // namespace android
120