blob: e4669cbb918a369447ccb5d792d053bbb025e392 [file] [log] [blame]
Ken Chenc52cbe02022-07-29 03:30:25 +08001/*
2 * Copyright (C) 2022 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
18#include "firewall.h"
19
20#include <android-base/result.h>
21#include <gtest/gtest.h>
22
23Firewall::Firewall() {
24 std::lock_guard guard(mMutex);
25 auto result = mConfigurationMap.init(CONFIGURATION_MAP_PATH);
26 EXPECT_RESULT_OK(result) << "init mConfigurationMap failed";
27
28 result = mUidOwnerMap.init(UID_OWNER_MAP_PATH);
29 EXPECT_RESULT_OK(result) << "init mUidOwnerMap failed";
30}
31
32Firewall* Firewall::getInstance() {
33 static Firewall instance;
34 return &instance;
35}
36
37Result<void> Firewall::toggleStandbyMatch(bool enable) {
38 std::lock_guard guard(mMutex);
39 uint32_t key = UID_RULES_CONFIGURATION_KEY;
40 auto oldConfiguration = mConfigurationMap.readValue(key);
41 if (!oldConfiguration.ok()) {
42 return Errorf("Cannot read the old configuration: {}", oldConfiguration.error().message());
43 }
44
45 BpfConfig newConfiguration = enable ? (oldConfiguration.value() | STANDBY_MATCH)
46 : (oldConfiguration.value() & (~STANDBY_MATCH));
47 auto res = mConfigurationMap.writeValue(key, newConfiguration, BPF_EXIST);
48 if (!res.ok()) return Errorf("Failed to toggle STANDBY_MATCH: {}", res.error().message());
49
50 return {};
51}
52
53Result<void> Firewall::addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif) {
54 // iif should be non-zero if and only if match == MATCH_IIF
55 if (match == IIF_MATCH && iif == 0) {
56 return Errorf("Interface match {} must have nonzero interface index", match);
57 } else if (match != IIF_MATCH && iif != 0) {
58 return Errorf("Non-interface match {} must have zero interface index", match);
59 }
60
61 std::lock_guard guard(mMutex);
62 auto oldMatch = mUidOwnerMap.readValue(uid);
63 if (oldMatch.ok()) {
64 UidOwnerValue newMatch = {
65 .iif = iif ? iif : oldMatch.value().iif,
66 .rule = static_cast<uint8_t>(oldMatch.value().rule | match),
67 };
68 auto res = mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY);
69 if (!res.ok()) return Errorf("Failed to update rule: {}", res.error().message());
70 } else {
71 UidOwnerValue newMatch = {
72 .iif = iif,
73 .rule = static_cast<uint8_t>(match),
74 };
75 auto res = mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY);
76 if (!res.ok()) return Errorf("Failed to add rule: {}", res.error().message());
77 }
78 return {};
79}
80
81Result<void> Firewall::removeRule(uint32_t uid, UidOwnerMatchType match) {
82 std::lock_guard guard(mMutex);
83 auto oldMatch = mUidOwnerMap.readValue(uid);
84 if (!oldMatch.ok()) return Errorf("uid: %u does not exist in map", uid);
85
86 UidOwnerValue newMatch = {
87 .iif = (match == IIF_MATCH) ? 0 : oldMatch.value().iif,
88 .rule = static_cast<uint8_t>(oldMatch.value().rule & ~match),
89 };
90 if (newMatch.rule == 0) {
91 auto res = mUidOwnerMap.deleteValue(uid);
92 if (!res.ok()) return Errorf("Failed to remove rule: {}", res.error().message());
93 } else {
94 auto res = mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY);
95 if (!res.ok()) return Errorf("Failed to update rule: {}", res.error().message());
96 }
97 return {};
98}
99
100Result<void> Firewall::addUidInterfaceRules(const std::string& ifName,
101 const std::vector<int32_t>& uids) {
102 unsigned int iif = if_nametoindex(ifName.c_str());
103 if (!iif) return Errorf("Failed to get interface index: {}", ifName);
104
105 for (auto uid : uids) {
106 auto res = addRule(uid, IIF_MATCH, iif);
107 if (!res.ok()) return res;
108 }
109 return {};
110}
111
112Result<void> Firewall::removeUidInterfaceRules(const std::vector<int32_t>& uids) {
113 for (auto uid : uids) {
114 auto res = removeRule(uid, IIF_MATCH);
115 if (!res.ok()) return res;
116 }
117 return {};
118}