1 /*
2  * Copyright (c) 2023-2024 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_rule_plugin.h"
17 
18 #include "edm_ipc_interface_code.h"
19 #include "edm_log.h"
20 #include "func_code_utils.h"
21 #include "netsys_controller.h"
22 #include "plugin_manager.h"
23 
24 namespace OHOS {
25 namespace EDM {
26 const bool REGISTER_RESULT = PluginManager::GetInstance()->AddPlugin(std::make_shared<IptablesRulePlugin>());
27 const std::string EDM_CHAIN_ALLOW_INPUT = "edm_allow_input";
28 const std::string EDM_CHAIN_ALLOW_OUTPUT = "edm_allow_output";
29 const std::string EDM_CHAIN_DENY_INPUT = "edm_deny_input";
30 const std::string EDM_CHAIN_DENY_OUTPUT = "edm_deny_output";
31 
32 bool IptablesRulePlugin::isChainInit_ = false;
33 
IptablesRulePlugin()34 IptablesRulePlugin::IptablesRulePlugin()
35 {
36     policyCode_ = EdmInterfaceCode::IPTABLES_RULE;
37     policyName_ = "iptables_rule";
38     permissionConfig_.permission = "ohos.permission.ENTERPRISE_MANAGE_NETWORK";
39     permissionConfig_.permissionType = IPlugin::PermissionType::SUPER_DEVICE_ADMIN;
40     permissionConfig_.apiType = IPlugin::ApiType::SYSTEM;
41     needSave_ = false;
42 }
43 
OnHandlePolicy(std::uint32_t funcCode,MessageParcel & data,MessageParcel & reply,HandlePolicyData & policyData,int32_t userId)44 ErrCode IptablesRulePlugin::OnHandlePolicy(std::uint32_t funcCode, MessageParcel &data, MessageParcel &reply,
45     HandlePolicyData &policyData, int32_t userId)
46 {
47     uint32_t typeCode = FUNC_TO_OPERATE(funcCode);
48     FuncOperateType type = FuncCodeUtils::ConvertOperateType(typeCode);
49     if (type == FuncOperateType::SET) {
50         return AddIptablesFilterRule(data);
51     } else if (type == FuncOperateType::REMOVE) {
52         return RemoveIptablesFilterRule(data);
53     } else {
54         return EdmReturnErrCode::SYSTEM_ABNORMALLY;
55     }
56 }
57 
OnGetPolicy(std::string & policyData,MessageParcel & data,MessageParcel & reply,int32_t userId)58 ErrCode IptablesRulePlugin::OnGetPolicy(std::string &policyData, MessageParcel &data, MessageParcel &reply,
59     int32_t userId)
60 {
61     std::string result;
62     std::string command("-t filter -n -v -L --line-number");
63     int32_t ret = NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(command, result);
64     EDMLOGI("IptablesRulePlugin::OnGetPolicy end retCode = %{public}d", ret);
65     if (ret == ERR_OK) {
66         reply.WriteInt32(ERR_OK);
67         reply.WriteString(result);
68         return ERR_OK;
69     }
70     reply.WriteInt32(EdmReturnErrCode::SYSTEM_ABNORMALLY);
71     return EdmReturnErrCode::SYSTEM_ABNORMALLY;
72 }
73 
AddIptablesFilterRule(MessageParcel & data)74 ErrCode IptablesRulePlugin::AddIptablesFilterRule(MessageParcel &data)
75 {
76     IPTABLES::AddFilter addFilter;
77     IPTABLES::IptablesUtils::ReadAddFilterConfig(addFilter, data);
78     std::string command;
79     if (!ConvertAddFilterToIptablesCommand(addFilter, command)) {
80         EDMLOGE("ConvertAddFilterToIptablesCommand failed");
81         return EdmReturnErrCode::PARAM_ERROR;
82     }
83     InitFirewallChain();
84     std::string result;
85     int32_t ret = NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(command, result);
86     EDMLOGI("AddIptablesFilterRule errcode = %{public}d, response = %{public}s", ret, result.c_str());
87     return ret;
88 }
89 
RemoveIptablesFilterRule(MessageParcel & data)90 ErrCode IptablesRulePlugin::RemoveIptablesFilterRule(MessageParcel &data)
91 {
92     IPTABLES::RemoveFilter removeFilter;
93     IPTABLES::IptablesUtils::ReadRemoveFilterConfig(removeFilter, data);
94     return ExecRemoveFilterIptablesCommand(removeFilter);
95 }
96 
InitFirewallChain()97 void IptablesRulePlugin::InitFirewallChain()
98 {
99     if (isChainInit_) {
100         EDMLOGD("no need init firewall chain");
101         return;
102     }
103     std::string allowInputChain = "-t filter -N " + EDM_CHAIN_ALLOW_INPUT;
104     std::string allowOutputChain = "-t filter -N " + EDM_CHAIN_ALLOW_OUTPUT;
105     std::string denyInputChain = "-t filter -N " + EDM_CHAIN_DENY_INPUT;
106     std::string denyOutputChain = "-t filter -N " + EDM_CHAIN_DENY_OUTPUT;
107 
108     std::string result;
109     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(allowInputChain, result);
110     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(allowOutputChain, result);
111     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(denyInputChain, result);
112     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(denyOutputChain, result);
113 
114     std::string refDenyOutputChain = "-t filter -I OUTPUT -j " + EDM_CHAIN_DENY_OUTPUT;
115     std::string refDenyInputChain = "-t filter -I INPUT -j " + EDM_CHAIN_DENY_INPUT;
116     std::string refAllowOutputChain = "-t filter -I OUTPUT -j " + EDM_CHAIN_ALLOW_OUTPUT;
117     std::string refAllowInputChain = "-t filter -I INPUT -j " + EDM_CHAIN_ALLOW_INPUT;
118     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(refDenyOutputChain, result);
119     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(refDenyInputChain, result);
120     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(refAllowOutputChain, result);
121     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(refAllowInputChain, result);
122     isChainInit_ = true;
123     EDMLOGD("InitFirewallChain success");
124 }
125 
ConvertAddFilterToIptablesCommand(const IPTABLES::AddFilter & addFilter,std::string & command)126 bool IptablesRulePlugin::ConvertAddFilterToIptablesCommand(const IPTABLES::AddFilter &addFilter, std::string &command)
127 {
128     command = "-t filter";
129     if (addFilter.method == IPTABLES::AddMethod::APPEND) {
130         command.append(" -A");
131     } else if (addFilter.method == IPTABLES::AddMethod::INSERT) {
132         command.append(" -I");
133     } else {
134         EDMLOGE("ConvertFirewallToIptablesCommand AddMethod must specify");
135         return false;
136     }
137     if (!ConvertChainCommand(addFilter.action, addFilter.direction, command)) {
138         EDMLOGE("ConvertFirewallToIptablesCommand action and direction must specify");
139         return false;
140     }
141     ConvertRuleNoCommand(addFilter.method, addFilter.ruleNo, command);
142     ConvertProtocolCommand(addFilter.protocol, command);
143     ConvertIpAddressCommand(addFilter.srcAddr, true, command);
144     ConvertIpAddressCommand(addFilter.destAddr, false, command);
145     ConvertPortCommand(addFilter.srcPort, true, command);
146     ConvertPortCommand(addFilter.destPort, false, command);
147     ConvertUidCommand(addFilter.uid, command);
148     return ConvertActionCommand(addFilter.action, command);
149 }
150 
ExecRemoveFilterIptablesCommand(const IPTABLES::RemoveFilter & removeFilter)151 ErrCode IptablesRulePlugin::ExecRemoveFilterIptablesCommand(const IPTABLES::RemoveFilter &removeFilter)
152 {
153     if (removeFilter.direction == IPTABLES::Direction::INVALID) {
154         return EdmReturnErrCode::PARAM_ERROR;
155     }
156     if (removeFilter.srcAddr.empty() && removeFilter.destAddr.empty() && removeFilter.srcPort.empty() &&
157         removeFilter.destPort.empty() && removeFilter.uid.empty() && removeFilter.action == IPTABLES::Action::INVALID &&
158         removeFilter.protocol == IPTABLES::Protocol::INVALID) {
159         return ExecRemoveFilterBySimpleCommand(removeFilter.direction);
160     }
161     return ExecRemoveFilterByDetailedCommand(removeFilter);
162 }
163 
ExecRemoveFilterBySimpleCommand(const IPTABLES::Direction & direction)164 ErrCode IptablesRulePlugin::ExecRemoveFilterBySimpleCommand(const IPTABLES::Direction &direction)
165 {
166     std::string commandAllow("-t filter -F");
167     std::string commandDeny("-t filter -F");
168     switch (direction) {
169         case IPTABLES::Direction::INPUT:
170             commandAllow.append(" " + EDM_CHAIN_ALLOW_INPUT);
171             commandDeny.append(" " + EDM_CHAIN_DENY_INPUT);
172             break;
173         case IPTABLES::Direction::OUTPUT:
174             commandAllow.append(" " + EDM_CHAIN_ALLOW_OUTPUT);
175             commandDeny.append(" " + EDM_CHAIN_DENY_OUTPUT);
176             break;
177         default:
178             return EdmReturnErrCode::PARAM_ERROR;
179     }
180     std::string result;
181     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(commandAllow, result);
182     NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(commandDeny, result);
183     return ERR_OK;
184 }
185 
ExecRemoveFilterByDetailedCommand(const IPTABLES::RemoveFilter & removeFilter)186 ErrCode IptablesRulePlugin::ExecRemoveFilterByDetailedCommand(const IPTABLES::RemoveFilter &removeFilter)
187 {
188     std::string command = "-t filter -D";
189     ConvertChainCommand(removeFilter.action, removeFilter.direction, command);
190     ConvertProtocolCommand(removeFilter.protocol, command);
191     ConvertIpAddressCommand(removeFilter.srcAddr, true, command);
192     ConvertIpAddressCommand(removeFilter.destAddr, false, command);
193     ConvertPortCommand(removeFilter.srcPort, true, command);
194     ConvertPortCommand(removeFilter.destPort, false, command);
195     ConvertUidCommand(removeFilter.uid, command);
196     ConvertActionCommand(removeFilter.action, command);
197     std::string result;
198     return NetManagerStandard::NetsysController::GetInstance().SetIptablesCommandForRes(command, result);
199 }
200 
ConvertChainCommand(const IPTABLES::Action & action,const IPTABLES::Direction & direction,std::string & command)201 bool IptablesRulePlugin::ConvertChainCommand(const IPTABLES::Action &action, const IPTABLES::Direction &direction,
202     std::string &command)
203 {
204     if (action == IPTABLES::Action::ALLOW && direction == IPTABLES::Direction::INPUT) {
205         command.append(" " + EDM_CHAIN_ALLOW_INPUT);
206     } else if (action == IPTABLES::Action::ALLOW && direction == IPTABLES::Direction::OUTPUT) {
207         command.append(" " + EDM_CHAIN_ALLOW_OUTPUT);
208     } else if (action == IPTABLES::Action::DENY && direction == IPTABLES::Direction::INPUT) {
209         command.append(" " + EDM_CHAIN_DENY_INPUT);
210     } else if (action == IPTABLES::Action::DENY && direction == IPTABLES::Direction::OUTPUT) {
211         command.append(" " + EDM_CHAIN_DENY_OUTPUT);
212     } else {
213         return false;
214     }
215     return true;
216 }
217 
ConvertProtocolCommand(const IPTABLES::Protocol & protocol,std::string & command)218 void IptablesRulePlugin::ConvertProtocolCommand(const IPTABLES::Protocol &protocol, std::string &command)
219 {
220     switch (protocol) {
221         case IPTABLES::Protocol::TCP:
222             command.append(" -p tcp");
223             break;
224         case IPTABLES::Protocol::UDP:
225             command.append(" -p udp");
226             break;
227         case IPTABLES::Protocol::ICMP:
228             command.append(" -p icmp");
229             break;
230         case IPTABLES::Protocol::ALL:
231             command.append(" -p all");
232             break;
233         default:
234             break;
235     }
236 }
237 
ConvertActionCommand(const IPTABLES::Action & action,std::string & command)238 bool IptablesRulePlugin::ConvertActionCommand(const IPTABLES::Action &action, std::string &command)
239 {
240     switch (action) {
241         case IPTABLES::Action::ALLOW:
242             command.append(" -j ACCEPT");
243             break;
244         case IPTABLES::Action::DENY:
245             command.append(" -j REJECT");
246             break;
247         default:
248             return false;
249     }
250     return true;
251 }
252 
ConvertIpAddressCommand(const std::string & ipAddress,const bool isSourceIp,std::string & command)253 void IptablesRulePlugin::ConvertIpAddressCommand(const std::string &ipAddress, const bool isSourceIp,
254     std::string &command)
255 {
256     if (ipAddress.empty()) {
257         return;
258     }
259     std::string splitStr = "-";
260     std::string::size_type idx = ipAddress.find(splitStr);
261     if (idx == std::string::npos) {
262         if (isSourceIp) {
263             command.append(" -s " + ipAddress);
264         } else {
265             command.append(" -d " + ipAddress);
266         }
267     } else {
268         if (isSourceIp) {
269             command.append(" -m iprange --src-range " + ipAddress);
270         } else {
271             command.append(" -m iprange --dst-range " + ipAddress);
272         }
273     }
274 }
275 
ConvertPortCommand(const std::string & port,const bool isSourcePort,std::string & command)276 void IptablesRulePlugin::ConvertPortCommand(const std::string &port, const bool isSourcePort, std::string &command)
277 {
278     if (port.empty()) {
279         return;
280     }
281     if (isSourcePort) {
282         command.append(" --sport " + port);
283     } else {
284         command.append(" --dport " + port);
285     }
286 }
287 
ConvertUidCommand(const std::string & uid,std::string & command)288 void IptablesRulePlugin::ConvertUidCommand(const std::string &uid, std::string &command)
289 {
290     if (uid.empty()) {
291         return;
292     }
293     command.append(" -m owner --uid-owner " + uid);
294 }
295 
ConvertRuleNoCommand(const IPTABLES::AddMethod & method,uint32_t ruleNo,std::string & command)296 void IptablesRulePlugin::ConvertRuleNoCommand(const IPTABLES::AddMethod &method, uint32_t ruleNo, std::string &command)
297 {
298     if (method == IPTABLES::AddMethod::INSERT && ruleNo != 0) {
299         command.append(" " + std::to_string(ruleNo));
300     }
301 }
302 } // namespace EDM
303 } // namespace OHOS
304