1 /*
2 * Copyright (c) 2022-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_wrapper.h"
17
18 #include <unistd.h>
19 #include <sys/syscall.h>
20 #include <sys/resource.h>
21
22 #include "datetime_ex.h"
23 #include "net_manager_constants.h"
24 #include "netmanager_base_common_utils.h"
25 #include "netnative_log_wrapper.h"
26
27 #ifdef UNITTEST_WAIT_FFRT
28 #undef UNITTEST_WAIT_FFRT
29 #endif
30 #define UNITTEST_WAIT_FFRT 1
31
32 namespace OHOS {
33 namespace nmd {
34 using namespace NetManagerStandard;
35 namespace {
36 constexpr const char *IPATBLES_CMD_PATH = "/system/bin/iptables";
37 constexpr const char *IP6TABLES_CMD_PATH = "/system/bin/ip6tables";
38 constexpr const int32_t MAX_IPTABLES_FFRT_TASK_NUM = 200;
39 constexpr const int32_t IPTABLES_PROCESS_PRIORITY = -20;
40 constexpr const int32_t DEFAULT_PROCESS_PRIORITY = 0;
41 } // namespace
42
IptablesWrapper()43 IptablesWrapper::IptablesWrapper()
44 {
45 isRunningFlag_ = true;
46 isIptablesSystemAccess_ = access(IPATBLES_CMD_PATH, F_OK) == 0;
47 isIp6tablesSystemAccess_ = access(IP6TABLES_CMD_PATH, F_OK) == 0;
48
49 iptablesWrapperFfrtQueue_ = std::make_shared<ffrt::queue>("IptablesWrapper");
50 }
51
~IptablesWrapper()52 IptablesWrapper::~IptablesWrapper()
53 {
54 isRunningFlag_ = false;
55 iptablesWrapperFfrtQueue_.reset();
56 }
57
ExecuteCommand(const std::string & command)58 void IptablesWrapper::ExecuteCommand(const std::string &command)
59 {
60 std::string cmdWithWait = command + " -w 5 ";
61 NETNATIVE_LOGI("ExecuteCommand %{public}s", CommonUtils::AnonymousIpInStr(cmdWithWait).c_str());
62 setpriority(PRIO_PROCESS, syscall(SYS_gettid), IPTABLES_PROCESS_PRIORITY);
63 if (CommonUtils::ForkExec(cmdWithWait) == NETMANAGER_ERROR) {
64 NETNATIVE_LOGE("run exec faild");
65 }
66 setpriority(PRIO_PROCESS, syscall(SYS_gettid), DEFAULT_PROCESS_PRIORITY);
67 }
68
ExecuteCommandForRes(const std::string & command)69 void IptablesWrapper::ExecuteCommandForRes(const std::string &command)
70 {
71 std::string cmdWithWait = command + " -w 5 ";
72 NETNATIVE_LOGI("ExecuteCommandForRes %{public}s", CommonUtils::AnonymousIpInStr(cmdWithWait).c_str());
73 setpriority(PRIO_PROCESS, syscall(SYS_gettid), IPTABLES_PROCESS_PRIORITY);
74 if (CommonUtils::ForkExec(cmdWithWait, &result_) == NETMANAGER_ERROR) {
75 NETNATIVE_LOGE("run exec faild");
76 }
77 setpriority(PRIO_PROCESS, syscall(SYS_gettid), DEFAULT_PROCESS_PRIORITY);
78 }
79
RunCommand(const IpType & ipType,const std::string & command)80 int32_t IptablesWrapper::RunCommand(const IpType &ipType, const std::string &command)
81 {
82 NETNATIVE_LOG_D("IptablesWrapper::RunCommand, ipType:%{public}d", ipType);
83 if (!iptablesWrapperFfrtQueue_) {
84 NETNATIVE_LOGE("FFRT Init Fail");
85 return NETMANAGER_ERROR;
86 }
87
88 if (isIptablesSystemAccess_ && (ipType == IPTYPE_IPV4 || ipType == IPTYPE_IPV4V6)) {
89 std::string cmd = std::string(IPATBLES_CMD_PATH) + " " + command;
90 std::function<void()> executeCommand = std::bind(&IptablesWrapper::ExecuteCommand, shared_from_this(), cmd);
91 #if UNITTEST_FORBID_FFRT // Forbid FFRT for unittest, which will cause crash in destructor process
92 ExecuteCommand(cmd);
93 #elif UNITTEST_WAIT_FFRT
94 // if too much task in queue, wait until task finish
95 if (iptablesWrapperFfrtQueue_->get_task_cnt() >= MAX_IPTABLES_FFRT_TASK_NUM) {
96 NETNATIVE_LOGE("iptables queue task count overmax, wait");
97 ffrt::task_handle handle = iptablesWrapperFfrtQueue_->submit_h(executeCommand);
98 iptablesWrapperFfrtQueue_->wait(handle);
99 } else {
100 iptablesWrapperFfrtQueue_->submit(executeCommand);
101 }
102 #else
103 iptablesWrapperFfrtQueue_->submit(executeCommand);
104 #endif // UNITTEST_FORBID_FFRT
105 }
106
107 if (isIp6tablesSystemAccess_ && (ipType == IPTYPE_IPV6 || ipType == IPTYPE_IPV4V6)) {
108 std::string cmd = std::string(IP6TABLES_CMD_PATH) + " " + command;
109 std::function<void()> executeCommand = std::bind(&IptablesWrapper::ExecuteCommand, shared_from_this(), cmd);
110 #if UNITTEST_FORBID_FFRT // Forbid FFRT for unittest, which will cause crash in destructor process
111 ExecuteCommand(cmd);
112 #elif UNITTEST_WAIT_FFRT
113 // if too much task in queue, wait until task finish
114 if (iptablesWrapperFfrtQueue_->get_task_cnt() >= MAX_IPTABLES_FFRT_TASK_NUM) {
115 NETNATIVE_LOGE("iptables queue task count overmax, wait");
116 ffrt::task_handle handle = iptablesWrapperFfrtQueue_->submit_h(executeCommand);
117 iptablesWrapperFfrtQueue_->wait(handle);
118 } else {
119 iptablesWrapperFfrtQueue_->submit(executeCommand);
120 }
121 #else
122 iptablesWrapperFfrtQueue_->submit(executeCommand);
123 #endif // UNITTEST_FORBID_FFRT
124 }
125
126 return NetManagerStandard::NETMANAGER_SUCCESS;
127 }
128
RunCommandForRes(const IpType & ipType,const std::string & command)129 std::string IptablesWrapper::RunCommandForRes(const IpType &ipType, const std::string &command)
130 {
131 NETNATIVE_LOGI("IptablesWrapper::RunCommandForRes, ipType:%{public}d", ipType);
132 if (!iptablesWrapperFfrtQueue_) {
133 NETNATIVE_LOGE("FFRT Init Fail");
134 return result_;
135 }
136
137 if (ipType == IPTYPE_IPV4 || ipType == IPTYPE_IPV4V6) {
138 std::string cmd = std::string(IPATBLES_CMD_PATH) + " " + command;
139 std::function<void()> executeCommandForRes =
140 std::bind(&IptablesWrapper::ExecuteCommandForRes, shared_from_this(), cmd);
141
142 int64_t start = GetTickCount();
143 ffrt::task_handle RunCommandForResTaskIpv4 = iptablesWrapperFfrtQueue_->submit_h(executeCommandForRes);
144 iptablesWrapperFfrtQueue_->wait(RunCommandForResTaskIpv4);
145 NETNATIVE_LOGI("FFRT cost:%{public}lld ms", static_cast<long long>(GetTickCount() - start));
146 }
147
148 if (ipType == IPTYPE_IPV6 || ipType == IPTYPE_IPV4V6) {
149 std::string cmd = std::string(IP6TABLES_CMD_PATH) + " " + command;
150 std::function<void()> executeCommandForRes =
151 std::bind(&IptablesWrapper::ExecuteCommandForRes, shared_from_this(), cmd);
152
153 int64_t start = GetTickCount();
154 ffrt::task_handle RunCommandForResTaskIpv6 = iptablesWrapperFfrtQueue_->submit_h(executeCommandForRes);
155 iptablesWrapperFfrtQueue_->wait(RunCommandForResTaskIpv6);
156 NETNATIVE_LOGI("FFRT cost:%{public}lld ms", static_cast<long long>(GetTickCount() - start));
157 }
158
159 return result_;
160 }
161
RunMutipleCommands(const IpType & ipType,const std::vector<std::string> & commands)162 int32_t IptablesWrapper::RunMutipleCommands(const IpType &ipType, const std::vector<std::string> &commands)
163 {
164 NETNATIVE_LOG_D("IptablesWrapper::RunMutipleCommands, ipType:%{public}d", ipType);
165 if (!iptablesWrapperFfrtQueue_) {
166 NETNATIVE_LOGE("FFRT Init Fail");
167 return NETMANAGER_ERROR;
168 }
169
170 for (const std::string& command : commands) {
171 if (isIptablesSystemAccess_ && (ipType == IPTYPE_IPV4 || ipType == IPTYPE_IPV4V6)) {
172 std::string cmd = std::string(IPATBLES_CMD_PATH) + " " + command;
173 std::function<void()> executeCommand = std::bind(&IptablesWrapper::ExecuteCommand, shared_from_this(), cmd);
174 #if UNITTEST_FORBID_FFRT // Forbid FFRT for unittest, which will cause crash in destructor process
175 executeCommand();
176 #elif UNITTEST_WAIT_FFRT
177 // if too much task in queue, wait until task finish
178 if (iptablesWrapperFfrtQueue_->get_task_cnt() >= MAX_IPTABLES_FFRT_TASK_NUM) {
179 NETNATIVE_LOGE("iptables queue task count overmax, wait");
180 ffrt::task_handle handle = iptablesWrapperFfrtQueue_->submit_h(executeCommand);
181 iptablesWrapperFfrtQueue_->wait(handle);
182 } else {
183 iptablesWrapperFfrtQueue_->submit(executeCommand);
184 }
185 #else
186 iptablesWrapperFfrtQueue_->submit(executeCommand);
187 #endif
188 }
189
190 if (isIp6tablesSystemAccess_ && (ipType == IPTYPE_IPV6 || ipType == IPTYPE_IPV4V6)) {
191 std::string cmd = std::string(IP6TABLES_CMD_PATH) + " " + command;
192 std::function<void()> executeCommand = std::bind(&IptablesWrapper::ExecuteCommand, shared_from_this(), cmd);
193 #if UNITTEST_FORBID_FFRT // Forbid FFRT for unittest, which will cause crash in destructor process
194 executeCommand();
195 #elif UNITTEST_WAIT_FFRT
196 // if too much task in queue, wait until task finish
197 if (iptablesWrapperFfrtQueue_->get_task_cnt() >= MAX_IPTABLES_FFRT_TASK_NUM) {
198 NETNATIVE_LOGE("iptables queue task count overmax, wait");
199 ffrt::task_handle handle = iptablesWrapperFfrtQueue_->submit_h(executeCommand);
200 iptablesWrapperFfrtQueue_->wait(handle);
201 } else {
202 iptablesWrapperFfrtQueue_->submit(executeCommand);
203 }
204 #else
205 iptablesWrapperFfrtQueue_->submit(executeCommand);
206 #endif
207 }
208 }
209
210 return NetManagerStandard::NETMANAGER_SUCCESS;
211 }
212
213 } // namespace nmd
214 } // namespace OHOS
215