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 
init()35 base::Result<void> DnsBpfHelper::init() {
36   if (!android::modules::sdklevel::IsAtLeastT()) {
37     LOG(ERROR) << __func__ << ": Unsupported before Android T.";
38     return base::Error(EOPNOTSUPP);
39   }
40 
41   RETURN_IF_RESULT_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
42   RETURN_IF_RESULT_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH));
43   RETURN_IF_RESULT_NOT_OK(mDataSaverEnabledMap.init(DATA_SAVER_ENABLED_MAP_PATH));
44   return {};
45 }
46 
isUidNetworkingBlocked(uid_t uid,bool metered)47 base::Result<bool> DnsBpfHelper::isUidNetworkingBlocked(uid_t uid, bool metered) {
48   if (is_system_uid(uid)) return false;
49   if (!mConfigurationMap.isValid() || !mUidOwnerMap.isValid()) {
50     LOG(ERROR) << __func__
51                << ": BPF maps are not ready. Forgot to call ADnsHelper_init?";
52     return base::Error(EUNATCH);
53   }
54 
55   auto enabledRules = mConfigurationMap.readValue(UID_RULES_CONFIGURATION_KEY);
56   RETURN_IF_RESULT_NOT_OK(enabledRules);
57 
58   auto value = mUidOwnerMap.readValue(uid);
59   uint32_t uidRules = value.ok() ? value.value().rule : 0;
60 
61   // For doze mode, battery saver, low power standby.
62   if (isBlockedByUidRules(enabledRules.value(), uidRules)) return true;
63 
64   // For data saver.
65   // DataSaverEnabled map on V+ platforms is the only reliable source of information about the
66   // current data saver status. While ConnectivityService offers two ways to update this map for U
67   // and V+, the U- platform implementation can have delays, potentially leading to inaccurate
68   // results. Conversely, the V+ platform implementation is synchronized with the actual data saver
69   // state, making it a trustworthy source. Since this library primarily serves DNS resolvers,
70   // relying solely on V+ data prevents erroneous blocking of DNS queries.
71   if (android::modules::sdklevel::IsAtLeastV() && metered) {
72     // The background data setting (PENALTY_BOX_USER_MATCH, PENALTY_BOX_ADMIN_MATCH) and
73     // unrestricted data usage setting (HAPPY_BOX_MATCH) for individual apps override the system
74     // wide Data Saver setting.
75     if (uidRules & (PENALTY_BOX_USER_MATCH | PENALTY_BOX_ADMIN_MATCH)) return true;
76     if (uidRules & HAPPY_BOX_MATCH) return false;
77 
78     auto dataSaverSetting = mDataSaverEnabledMap.readValue(DATA_SAVER_ENABLED_KEY);
79     RETURN_IF_RESULT_NOT_OK(dataSaverSetting);
80     return dataSaverSetting.value();
81   }
82 
83   return false;
84 }
85 
86 }  // namespace net
87 }  // namespace android
88