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