1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "iptables_manager.h"
17
18 #include <iostream>
19 #include <unordered_map>
20
21 #include "domain_chain_rule.h"
22 #include "edm_log.h"
23 #include "executer_factory.h"
24 #include "firewall_chain_rule.h"
25 #include "iexecuter.h"
26 #include "rule_utils.h"
27
28 namespace OHOS {
29 namespace EDM {
30 namespace IPTABLES {
31
32 const int32_t MAX_DOMAIN_LENGTH = 255;
33
34 bool IptablesManager::g_chainInit = false;
35 bool IptablesManager::g_defaultFirewallChainInit = false;
36 bool IptablesManager::g_defaultDomainChainInit = false;
37 std::shared_ptr<IptablesManager> IptablesManager::instance_ = nullptr;
38 std::mutex IptablesManager::mutexLock_;
39
GetInstance()40 std::shared_ptr<IptablesManager> IptablesManager::GetInstance()
41 {
42 if (instance_ == nullptr) {
43 std::lock_guard<std::mutex> lock(mutexLock_);
44 if (instance_ == nullptr) {
45 std::shared_ptr<IptablesManager> temp = std::make_shared<IptablesManager>();
46 instance_ = temp;
47 }
48 }
49 return instance_;
50 }
51
AddFirewallRule(const FirewallRuleParcel & firewall)52 ErrCode IptablesManager::AddFirewallRule(const FirewallRuleParcel& firewall)
53 {
54 auto rule = firewall.GetRule();
55 std::string chainName;
56 Direction direction = std::get<FIREWALL_DICECTION_IND>(rule);
57 if (direction == Direction::INPUT && !std::get<FIREWALL_APPUID_IND>(rule).empty()) {
58 EDMLOGE("AddFirewallRule: illegal parameter: appUid");
59 return EdmReturnErrCode::PARAM_ERROR;
60 }
61 if (std::get<FIREWALL_PROT_IND>(rule) == Protocol::ALL &&
62 !std::get<FIREWALL_SRCPORT_IND>(rule).empty() && !std::get<FIREWALL_DESTPORT_IND>(rule).empty()) {
63 EDMLOGE("AddFirewallRule: illegal parameter: protocol");
64 return EdmReturnErrCode::PARAM_ERROR;
65 }
66
67 Action action = std::get<FIREWALL_ACTION_IND>(rule);
68 if (action == Action::ALLOW && direction == Direction::INPUT) {
69 chainName = EDM_ALLOW_INPUT_CHAIN_NAME;
70 } else if (action == Action::ALLOW && direction == Direction::OUTPUT) {
71 chainName = EDM_ALLOW_OUTPUT_CHAIN_NAME;
72 } else if (action == Action::DENY && direction == Direction::INPUT) {
73 chainName = EDM_DENY_INPUT_CHAIN_NAME;
74 } else if (action == Action::DENY && direction == Direction::OUTPUT) {
75 chainName = EDM_DENY_OUTPUT_CHAIN_NAME;
76 } else {
77 EDMLOGE("AddFirewallRule: illegal parameter: action, direction");
78 return EdmReturnErrCode::PARAM_ERROR;
79 }
80
81 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
82 if (executer == nullptr) {
83 EDMLOGE("AddFirewallRule:GetExecuter fail, this should not happen.");
84 return EdmReturnErrCode::SYSTEM_ABNORMALLY;
85 }
86 if (action == Action::ALLOW) {
87 SetDefaultFirewallDenyChain();
88 }
89 auto chainRule = std::make_shared<FirewallChainRule>(rule);
90 return executer->Add(chainRule);
91 }
92
RemoveFirewallRule(const FirewallRuleParcel & firewall)93 ErrCode IptablesManager::RemoveFirewallRule(const FirewallRuleParcel& firewall)
94 {
95 auto rule = firewall.GetRule();
96 Direction direction = std::get<FIREWALL_DICECTION_IND>(rule);
97 Action action = std::get<FIREWALL_ACTION_IND>(rule);
98 if (direction == Direction::INPUT && !std::get<FIREWALL_APPUID_IND>(rule).empty()) {
99 EDMLOGE("RemoveFirewallRule: illegal parameter: appUid");
100 return EdmReturnErrCode::PARAM_ERROR;
101 }
102 if (std::get<FIREWALL_PROT_IND>(rule) == Protocol::ALL &&
103 (!std::get<FIREWALL_SRCPORT_IND>(rule).empty() || !std::get<FIREWALL_DESTPORT_IND>(rule).empty())) {
104 EDMLOGE("RemoveFirewallRule: illegal parameter: protocol");
105 return EdmReturnErrCode::PARAM_ERROR;
106 }
107
108 std::vector<std::string> chainNameList;
109 ErrCode ret = GetRemoveChainName(direction, action, chainNameList);
110 if (ret != ERR_OK) {
111 EDMLOGE("RemoveFirewallRule: illegal parameter: action, direction");
112 return ret;
113 }
114
115 if (chainNameList.size() > 1) {
116 if (std::get<FIREWALL_PROT_IND>(rule) != IPTABLES::Protocol::INVALID ||
117 !std::get<FIREWALL_SRCADDR_IND>(rule).empty() || !std::get<FIREWALL_DESTADDR_IND>(rule).empty() ||
118 !std::get<FIREWALL_SRCPORT_IND>(rule).empty() || !std::get<FIREWALL_DESTPORT_IND>(rule).empty() ||
119 !std::get<FIREWALL_APPUID_IND>(rule).empty()) {
120 EDMLOGE("RemoveFirewallRule: illegal parameter: Too many parameters set");
121 return EdmReturnErrCode::PARAM_ERROR;
122 }
123 // flash chain
124 for (const auto& chainName : chainNameList) {
125 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
126 if (executer == nullptr) {
127 EDMLOGE("RemoveFirewallRule:GetExecuter fail, this should not happen.");
128 continue;
129 }
130 executer->Remove(nullptr);
131 }
132 } else if (chainNameList.size() == 1) {
133 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainNameList[0]);
134 if (executer == nullptr) {
135 EDMLOGE("RemoveFirewallRule:GetExecuter fail, this should not happen.");
136 } else {
137 auto chainRule = std::make_shared<FirewallChainRule>(rule);
138 executer->Remove(chainRule);
139 }
140 }
141 if (!ExistAllowFirewallRule()) {
142 ClearDefaultFirewallDenyChain();
143 }
144 return ERR_OK;
145 }
146
GetFirewallRules(std::vector<FirewallRuleParcel> & list)147 ErrCode IptablesManager::GetFirewallRules(std::vector<FirewallRuleParcel>& list)
148 {
149 std::vector<std::string> inputRuleList;
150 std::vector<std::string> inputChainVector{EDM_ALLOW_INPUT_CHAIN_NAME, EDM_DENY_INPUT_CHAIN_NAME};
151 for (const auto& chainName : inputChainVector) {
152 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
153 if (executer == nullptr) {
154 EDMLOGE("GetFirewallRules:GetExecuter fail, this should not happen.");
155 continue;
156 }
157 executer->GetAll(inputRuleList);
158 }
159
160 for (const auto& rule : inputRuleList) {
161 FirewallChainRule firewallRule{rule};
162 FirewallRuleParcel firewall{firewallRule.ToFilterRule(Direction::INPUT)};
163 list.emplace_back(firewall);
164 }
165
166 std::vector<std::string> outputRuleList;
167 std::vector<std::string> outputChainVector{EDM_ALLOW_OUTPUT_CHAIN_NAME, EDM_DENY_OUTPUT_CHAIN_NAME};
168 for (const auto& chainName : outputChainVector) {
169 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
170 if (executer == nullptr) {
171 EDMLOGE("GetFirewallRules:GetExecuter fail, this should not happen.");
172 continue;
173 }
174 executer->GetAll(outputRuleList);
175 }
176 for (const auto& rule : outputRuleList) {
177 FirewallChainRule firewallRule{rule};
178 FirewallRuleParcel firewall{firewallRule.ToFilterRule(Direction::OUTPUT)};
179 list.emplace_back(firewall);
180 }
181 return ERR_OK;
182 }
183
AddDomainFilterRule(const DomainFilterRuleParcel & DomainFilter)184 ErrCode IptablesManager::AddDomainFilterRule(const DomainFilterRuleParcel& DomainFilter)
185 {
186 auto rule = DomainFilter.GetRule();
187 Action action = std::get<DOMAIN_ACTION_IND>(rule);
188 std::string domainName = std::get<DOMAIN_DOMAINNAME_IND>(rule);
189 std::string chainName;
190 if (action == Action::ALLOW) {
191 chainName = EDM_DNS_ALLOW_OUTPUT_CHAIN_NAME;
192 } else if (action == Action::DENY) {
193 chainName = EDM_DNS_DENY_OUTPUT_CHAIN_NAME;
194 } else {
195 EDMLOGE("AddDomainFilterRule: illegal parameter: action");
196 return EdmReturnErrCode::PARAM_ERROR;
197 }
198 if (domainName.empty() || domainName.length() > MAX_DOMAIN_LENGTH) {
199 EDMLOGE("AddDomainFilterRule: illegal parameter: domainName");
200 return EdmReturnErrCode::PARAM_ERROR;
201 }
202 auto index = domainName.find_first_of("|/");
203 if (index != std::string ::npos) {
204 EDMLOGE("AddDomainFilterRule: illegal parameter: domainName");
205 return EdmReturnErrCode::PARAM_ERROR;
206 }
207
208 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
209 if (executer == nullptr) {
210 EDMLOGE("AddDomainFilterRule:GetExecuter fail, this should not happen.");
211 return EdmReturnErrCode::SYSTEM_ABNORMALLY;
212 }
213 if (action == Action::ALLOW) {
214 EDMLOGD("AddDomainFilterRule:GetExecuter before SetDefaultDomainDenyChain.");
215 SetDefaultDomainDenyChain();
216 }
217 auto chainRule = std::make_shared<DomainChainRule>(rule);
218 return executer->Add(chainRule);
219 }
220
RemoveDomainFilterRules(const DomainFilterRuleParcel & DomainFilter)221 ErrCode IptablesManager::RemoveDomainFilterRules(const DomainFilterRuleParcel& DomainFilter)
222 {
223 auto rule = DomainFilter.GetRule();
224 Action action = std::get<DOMAIN_ACTION_IND>(rule);
225 std::string appUid = std::get<DOMAIN_APPUID_IND>(rule);
226 std::string domainName = std::get<DOMAIN_DOMAINNAME_IND>(rule);
227 if (domainName.empty() && !appUid.empty()) {
228 EDMLOGE("RemoveDomainFilterRules: illegal parameter: appUid");
229 return EdmReturnErrCode::PARAM_ERROR;
230 }
231 if (!domainName.empty() && domainName.length() > MAX_DOMAIN_LENGTH) {
232 EDMLOGE("RemoveDomainFilterRules: illegal parameter: domainName");
233 return EdmReturnErrCode::PARAM_ERROR;
234 }
235 auto index = domainName.find_first_of("|/");
236 if (index != std::string ::npos) {
237 EDMLOGE("RemoveDomainFilterRules: illegal parameter: domainName");
238 return EdmReturnErrCode::PARAM_ERROR;
239 }
240
241 if (action == Action::INVALID && (!appUid.empty() || !domainName.empty())) {
242 EDMLOGE("RemoveDomainFilterRules: illegal parameter: Too many parameters set");
243 return EdmReturnErrCode::PARAM_ERROR;
244 }
245
246 std::vector<std::string> chainNameList;
247 if (action == Action::ALLOW) {
248 chainNameList.emplace_back(EDM_DNS_ALLOW_OUTPUT_CHAIN_NAME);
249 } else if (action == Action::DENY) {
250 chainNameList.emplace_back(EDM_DNS_DENY_OUTPUT_CHAIN_NAME);
251 } else {
252 chainNameList.emplace_back(EDM_DNS_ALLOW_OUTPUT_CHAIN_NAME);
253 chainNameList.emplace_back(EDM_DNS_DENY_OUTPUT_CHAIN_NAME);
254 for (const auto& chainName : chainNameList) {
255 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
256 // flush chain
257 executer->Remove(nullptr);
258 }
259 ClearDefaultDomainDenyChain();
260 return ERR_OK;
261 }
262
263 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainNameList[0]);
264 if (executer == nullptr) {
265 EDMLOGE("RemoveDomainFilterRules:GetExecuter fail, this should not happen.");
266 return EdmReturnErrCode::SYSTEM_ABNORMALLY;
267 }
268 auto chainRule = std::make_shared<DomainChainRule>(rule);
269 auto ret = executer->Remove(chainRule);
270 if (ret == ERR_OK && !ExistAllowDomainRule()) {
271 ClearDefaultDomainDenyChain();
272 }
273 return ret;
274 }
275
GetDomainFilterRules(std::vector<DomainFilterRuleParcel> & list)276 ErrCode IptablesManager::GetDomainFilterRules(std::vector<DomainFilterRuleParcel>& list)
277 {
278 std::vector<std::string> ruleList;
279 std::vector<std::string> chainNameVector{EDM_DNS_ALLOW_OUTPUT_CHAIN_NAME, EDM_DNS_DENY_OUTPUT_CHAIN_NAME};
280 for (const auto& chainName : chainNameVector) {
281 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
282 executer->GetAll(ruleList);
283 }
284 for (const auto& rule : ruleList) {
285 DomainChainRule chainRule{rule};
286 list.emplace_back(chainRule.ToFilterRule());
287 }
288 return ERR_OK;
289 }
290
GetRemoveChainName(Direction direction,Action action,std::vector<std::string> & chainNameList)291 ErrCode IptablesManager::GetRemoveChainName(Direction direction, Action action, std::vector<std::string>& chainNameList)
292 {
293 if (direction == Direction::INPUT) {
294 if (action == Action::ALLOW) {
295 chainNameList.emplace_back(EDM_ALLOW_INPUT_CHAIN_NAME);
296 } else if (action == Action::DENY) {
297 chainNameList.emplace_back(EDM_DENY_INPUT_CHAIN_NAME);
298 } else {
299 chainNameList.emplace_back(EDM_ALLOW_INPUT_CHAIN_NAME);
300 chainNameList.emplace_back(EDM_DENY_INPUT_CHAIN_NAME);
301 }
302 } else if (direction == Direction::OUTPUT) {
303 if (action == Action::ALLOW) {
304 chainNameList.emplace_back(EDM_ALLOW_OUTPUT_CHAIN_NAME);
305 } else if (action == Action::DENY) {
306 chainNameList.emplace_back(EDM_DENY_OUTPUT_CHAIN_NAME);
307 } else {
308 chainNameList.emplace_back(EDM_ALLOW_OUTPUT_CHAIN_NAME);
309 chainNameList.emplace_back(EDM_DENY_OUTPUT_CHAIN_NAME);
310 }
311 } else {
312 if (action == Action::INVALID) {
313 chainNameList.emplace_back(EDM_ALLOW_INPUT_CHAIN_NAME);
314 chainNameList.emplace_back(EDM_ALLOW_OUTPUT_CHAIN_NAME);
315 chainNameList.emplace_back(EDM_DENY_INPUT_CHAIN_NAME);
316 chainNameList.emplace_back(EDM_DENY_OUTPUT_CHAIN_NAME);
317 } else {
318 EDMLOGE("GetRemoveChainName: illegal parameter: direction, action");
319 return EdmReturnErrCode::PARAM_ERROR;
320 }
321 }
322 return ERR_OK;
323 }
324
HasInit()325 bool IptablesManager::HasInit()
326 {
327 return g_chainInit;
328 }
329
Init()330 void IptablesManager::Init()
331 {
332 if (!g_chainInit) {
333 EDMLOGD("IptablesManager:start init.");
334 std::vector<std::shared_ptr<IExecuter>> allExecuter = ExecuterFactory::GetInstance()->GetAllExecuter();
335 for (const auto &executer : allExecuter) {
336 ErrCode ret = executer->CreateChain();
337 if (ret != ERR_OK) {
338 EDMLOGE("Init CreateChain fail, this should not happen.");
339 return;
340 }
341 }
342 for (const auto &executer : allExecuter) {
343 ErrCode ret = executer->Init();
344 if (ret != ERR_OK) {
345 EDMLOGE("Init fail, this should not happen.");
346 return;
347 }
348 }
349 g_chainInit = true;
350 }
351 }
352
SetDefaultFirewallDenyChain()353 void IptablesManager::SetDefaultFirewallDenyChain()
354 {
355 if (!g_defaultFirewallChainInit) {
356 FirewallRule firewallRule1{Direction::OUTPUT, Action::DENY, Protocol::UDP, "", "", "", "", ""};
357 FirewallRule firewallRule2{Direction::OUTPUT, Action::DENY, Protocol::TCP, "", "", "", "", ""};
358
359 std::vector<std::shared_ptr<ChainRule>> chainRuleVector{std::make_shared<FirewallChainRule>(),
360 std::make_shared<FirewallChainRule>(firewallRule1), std::make_shared<FirewallChainRule>(firewallRule2)};
361
362 auto executer = ExecuterFactory::GetInstance()->GetExecuter(EDM_DEFAULT_DENY_OUTPUT_CHAIN_NAME);
363 for (const auto& chainRule : chainRuleVector) {
364 if (executer == nullptr) {
365 EDMLOGE("SetDefaultFirewallDenyChain:GetExecuter fail, this should not happen.");
366 } else {
367 executer->Add(chainRule);
368 g_defaultFirewallChainInit = true;
369 }
370 }
371 }
372 }
373
ClearDefaultFirewallDenyChain()374 void IptablesManager::ClearDefaultFirewallDenyChain()
375 {
376 if (g_defaultFirewallChainInit) {
377 auto executer = ExecuterFactory::GetInstance()->GetExecuter(EDM_DEFAULT_DENY_OUTPUT_CHAIN_NAME);
378 if (executer == nullptr) {
379 EDMLOGE("ClearDefaultFirewallDenyChain:GetExecuter fail, this should not happen.");
380 } else {
381 executer->Remove(nullptr);
382 g_defaultFirewallChainInit = false;
383 }
384 }
385 }
386
SetDefaultDomainDenyChain()387 void IptablesManager::SetDefaultDomainDenyChain()
388 {
389 if (!g_defaultDomainChainInit) {
390 DomainFilterRule domainFilterRule{Action::DENY, "", ""};
391 std::shared_ptr<ChainRule> chainRule = std::make_shared<DomainChainRule>(domainFilterRule);
392 auto executer = ExecuterFactory::GetInstance()->GetExecuter(EDM_DEFAULT_DNS_DENY_OUTPUT_CHAIN_NAME);
393 if (executer == nullptr) {
394 EDMLOGE("SetDefaultDomainDenyChain:GetExecuter fail, this should not happen.");
395 } else {
396 executer->Add(chainRule);
397 g_defaultDomainChainInit = true;
398 }
399 }
400 }
401
ClearDefaultDomainDenyChain()402 void IptablesManager::ClearDefaultDomainDenyChain()
403 {
404 if (g_defaultDomainChainInit) {
405 auto executer = ExecuterFactory::GetInstance()->GetExecuter(EDM_DEFAULT_DNS_DENY_OUTPUT_CHAIN_NAME);
406 if (executer == nullptr) {
407 EDMLOGE("ClearDefaultDomainDenyChain:GetExecuter fail, this should not happen.");
408 } else {
409 executer->Remove(nullptr);
410 g_defaultDomainChainInit = false;
411 }
412 }
413 }
414
ExistAllowFirewallRule()415 bool IptablesManager::ExistAllowFirewallRule()
416 {
417 std::vector<std::string> chainNameVector{EDM_ALLOW_INPUT_CHAIN_NAME, EDM_ALLOW_OUTPUT_CHAIN_NAME};
418 return ChainExistRule(chainNameVector);
419 }
420
ExistAllowDomainRule()421 bool IptablesManager::ExistAllowDomainRule()
422 {
423 std::vector<std::string> chainNameVector{EDM_DNS_ALLOW_OUTPUT_CHAIN_NAME};
424 return ChainExistRule(chainNameVector);
425 }
426
ChainExistRule(const std::vector<std::string> & chainNames)427 bool IptablesManager::ChainExistRule(const std::vector<std::string>& chainNames)
428 {
429 std::vector<std::string> ruleList;
430 for (const auto& chainName : chainNames) {
431 auto executer = ExecuterFactory::GetInstance()->GetExecuter(chainName);
432 executer->GetAll(ruleList);
433 if (!ruleList.empty()) {
434 return true;
435 }
436 }
437 return false;
438 }
439
440 } // namespace IPTABLES
441 } // namespace EDM
442 } // namespace OHOS