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