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