• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "netstack_common_utils.h"
17 
18 #ifdef WINDOWS_PLATFORM
19 #include <winsock2.h>
20 #include <ws2tcpip.h>
21 #pragma comment(lib, "ws2_32.lib")
22 #else
23 #include <arpa/inet.h>
24 #endif
25 
26 #include <algorithm>
27 #include <cctype>
28 #include <cerrno>
29 #include <regex>
30 #include <string>
31 #include <unistd.h>
32 #include <vector>
33 
34 #include "curl/curl.h"
35 #include "netstack_log.h"
36 
37 constexpr int32_t INET_OPTION_SUC = 1;
38 constexpr size_t MAX_DISPLAY_NUM = 2;
39 
40 namespace OHOS::NetStack::CommonUtils {
41 const std::regex IP_PATTERN{
42     "((2([0-4]\\d|5[0-5])|1\\d\\d|[1-9]\\d|\\d)\\.){3}(2([0-4]\\d|5[0-5])|1\\d\\d|[1-9]\\d|\\d)"};
43 const std::regex IP_MASK_PATTERN{
44     "((2([0-4]\\d|5[0-5])|1\\d\\d|[1-9]\\d|\\d)\\.){3}(2([0-4]\\d|5[0-5])|1\\d\\d|[1-9]\\d|\\d)/"
45     "(3[0-2]|[1-2]\\d|\\d)"};
46 const std::regex IPV6_PATTERN{"([\\da-fA-F]{0,4}:){2,7}([\\da-fA-F]{0,4})"};
47 const std::regex IPV6_MASK_PATTERN{"([\\da-fA-F]{0,4}:){2,7}([\\da-fA-F]{0,4})/(1[0-2][0-8]|[1-9]\\d|[1-9])"};
48 std::mutex g_commonUtilsMutex;
49 
Split(const std::string & str,const std::string & sep)50 std::vector<std::string> Split(const std::string &str, const std::string &sep)
51 {
52     std::string s = str;
53     std::vector<std::string> res;
54     while (!s.empty()) {
55         auto pos = s.find(sep);
56         if (pos == std::string::npos) {
57             res.emplace_back(s);
58             break;
59         }
60         res.emplace_back(s.substr(0, pos));
61         s = s.substr(pos + sep.size());
62     }
63     return res;
64 }
65 
Split(const std::string & str,const std::string & sep,size_t size)66 std::vector<std::string> Split(const std::string &str, const std::string &sep, size_t size)
67 {
68     std::string s = str;
69     std::vector<std::string> res;
70     while (!s.empty()) {
71         if (res.size() + 1 == size) {
72             res.emplace_back(s);
73             break;
74         }
75 
76         auto pos = s.find(sep);
77         if (pos == std::string::npos) {
78             res.emplace_back(s);
79             break;
80         }
81         res.emplace_back(s.substr(0, pos));
82         s = s.substr(pos + sep.size());
83     }
84     return res;
85 }
86 
Strip(const std::string & str,char ch)87 std::string Strip(const std::string &str, char ch)
88 {
89     int64_t i = 0;
90     while (static_cast<size_t>(i) < str.size() && str[i] == ch) {
91         ++i;
92     }
93     int64_t j = static_cast<int64_t>(str.size()) - 1;
94     while (j > 0 && str[j] == ch) {
95         --j;
96     }
97     if (i >= 0 && static_cast<size_t>(i) < str.size() && j >= 0 && static_cast<size_t>(j) < str.size() &&
98         j - i + 1 > 0) {
99         return str.substr(i, j - i + 1);
100     }
101     return "";
102 }
103 
ToLower(const std::string & s)104 std::string ToLower(const std::string &s)
105 {
106     std::string res = s;
107     std::transform(res.begin(), res.end(), res.begin(), tolower);
108     return res;
109 }
110 
ToString(const std::list<std::string> & lists,char tab)111 std::string ToString(const std::list<std::string> &lists, char tab)
112 {
113     std::string str;
114     for (auto it = lists.begin(); it != lists.end(); ++it) {
115         if (it != lists.begin()) {
116             str.append(1, tab);
117         }
118         str.append(*it);
119     }
120     return str;
121 }
122 
HasInternetPermission()123 bool HasInternetPermission()
124 {
125 #ifndef OH_CORE_NETSTACK_PERMISSION_CHECK
126 #ifdef FUZZ_TEST
127     return true;
128 #endif
129     int testSock = socket(AF_INET, SOCK_STREAM, 0);
130     if (testSock < 0 && errno == EPERM) {
131         NETSTACK_LOGE("make tcp testSock failed errno is %{public}d %{public}s", errno, strerror(errno));
132         return false;
133     }
134     if (testSock > 0) {
135         close(testSock);
136     }
137     return true;
138 #else
139     constexpr int inetGroup = 40002003; // 3003 in gateway shell.
140     int groupNum = getgroups(0, nullptr);
141     if (groupNum <= 0) {
142         NETSTACK_LOGE("no group of INTERNET permission");
143         return false;
144     }
145     auto groups = (gid_t *)malloc(groupNum * sizeof(gid_t));
146     groupNum = getgroups(groupNum, groups);
147     for (int i = 0; i < groupNum; i++) {
148         if (groups[i] == inetGroup) {
149             free(groups);
150             return true;
151         }
152     }
153     free(groups);
154     NETSTACK_LOGE("INTERNET permission denied by group");
155     return false;
156 #endif
157 }
158 
EndsWith(const std::string & str,const std::string & suffix)159 bool EndsWith(const std::string &str, const std::string &suffix)
160 {
161     if (str.length() < suffix.length()) {
162         return false;
163     }
164     return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
165 }
166 
Trim(std::string str)167 std::string Trim(std::string str)
168 {
169     size_t start = str.find_first_not_of(" \t\n\r");
170     size_t end = str.find_last_not_of(" \t\n\r");
171     if (start == std::string::npos || end == std::string::npos) {
172         return "";
173     } else {
174         return str.substr(start, end - start + 1);
175     }
176 }
177 
IsMatch(const std::string & str,const std::string & patternStr)178 bool IsMatch(const std::string &str, const std::string &patternStr)
179 {
180     if (patternStr.empty()) {
181         return false;
182     }
183     if (patternStr == "*") {
184         return true;
185     }
186     if (!IsRegexValid(patternStr)) {
187         NETSTACK_LOGD("Invalid pattern string: %{public}s", patternStr.c_str());
188         return patternStr == str;
189     }
190     std::regex pattern(ReplaceCharacters(patternStr));
191     bool isMacth = patternStr != "" && std::regex_match(str, pattern);
192     if (isMacth) {
193         NETSTACK_LOGD("Match patternStr: %{public}s", patternStr.c_str());
194     }
195     return isMacth;
196 }
197 
InsertCharBefore(const std::string & input,const char from,const char preChar,const char nextChar)198 std::string InsertCharBefore(const std::string &input, const char from, const char preChar, const char nextChar)
199 {
200     std::string output = input;
201     char arr[] = {preChar, from};
202     unsigned long strSize = sizeof(arr) / sizeof(arr[0]);
203     std::string str(arr, strSize);
204     std::size_t pos = output.find(from);
205     std::size_t length = output.length();
206     while (pos <= length - 1 && pos != std::string::npos) {
207         char nextCharTemp = pos == length - 1 ? '\0' : output[pos + 1];
208         if (nextChar == '\0' || nextCharTemp == '\0' || nextCharTemp != nextChar) {
209             output.replace(pos, 1, str);
210             length += (strSize - 1);
211         }
212         pos = output.find(from, pos + strSize);
213     }
214     return output;
215 }
216 
ReplaceCharacters(const std::string & input)217 std::string ReplaceCharacters(const std::string &input)
218 {
219     std::string output = InsertCharBefore(input, '*', '.', '\0');
220     output = InsertCharBefore(output, '.', '\\', '*');
221     return output;
222 }
223 
IsRegexValid(const std::string & regex)224 bool IsRegexValid(const std::string &regex)
225 {
226     if (Trim(regex).empty()) {
227         return false;
228     }
229     return regex_match(regex, std::regex("^[a-zA-Z0-9\\-_\\.*]+$"));
230 }
231 
GetHostnameFromURL(const std::string & url)232 std::string GetHostnameFromURL(const std::string &url)
233 {
234     if (url.empty()) {
235         return "";
236     }
237     std::string delimiter = "://";
238     std::string tempUrl = url;
239     std::replace(tempUrl.begin(), tempUrl.end(), '\\', '/');
240     size_t posStart = tempUrl.find(delimiter);
241     if (posStart != std::string::npos) {
242         posStart += delimiter.length();
243     } else {
244         posStart = 0;
245     }
246     size_t notSlash = tempUrl.find_first_not_of('/', posStart);
247     if (notSlash != std::string::npos) {
248         posStart = notSlash;
249     }
250     size_t posEnd = std::min({ tempUrl.find(':', posStart),
251                               tempUrl.find('/', posStart), tempUrl.find('?', posStart) });
252     if (posEnd != std::string::npos) {
253         return tempUrl.substr(posStart, posEnd - posStart);
254     }
255     return tempUrl.substr(posStart);
256 }
257 
IsExcluded(const std::string & str,const std::string & exclusions,const std::string & split)258 bool IsExcluded(const std::string &str, const std::string &exclusions, const std::string &split)
259 {
260     if (Trim(exclusions).empty()) {
261         return false;
262     }
263     std::size_t start = 0;
264     std::size_t end = exclusions.find(split);
265     while (end != std::string::npos) {
266         if (end - start > 0 && IsMatch(str, Trim(exclusions.substr(start, end - start)))) {
267             return true;
268         }
269         start = end + 1;
270         end = exclusions.find(split, start);
271     }
272     return IsMatch(str, Trim(exclusions.substr(start)));
273 }
274 
IsHostNameExcluded(const std::string & url,const std::string & exclusions,const std::string & split)275 bool IsHostNameExcluded(const std::string &url, const std::string &exclusions, const std::string &split)
276 {
277     std::string hostName = GetHostnameFromURL(url);
278     NETSTACK_LOGD("hostName is: %{public}s", hostName.c_str());
279     return IsExcluded(hostName, exclusions, split);
280 }
281 
IsValidIPV4(const std::string & ip)282 bool IsValidIPV4(const std::string &ip)
283 {
284     return IsValidIP(ip, AF_INET);
285 }
286 
IsValidIPV6(const std::string & ip)287 bool IsValidIPV6(const std::string &ip)
288 {
289     return IsValidIP(ip, AF_INET6);
290 }
291 
IsValidIP(const std::string & ip,int af)292 bool IsValidIP(const std::string& ip, int af)
293 {
294     if (ip.empty()) {
295         return false;
296     }
297 #ifdef WINDOWS_PLATFORM
298     if (af == AF_INET6) {
299         struct sockaddr_in6 sa;
300         return inet_pton(af, ip.c_str(), &(sa.sin6_addr)) == INET_OPTION_SUC;
301     } else {
302         struct sockaddr_in sa;
303         return inet_pton(af, ip.c_str(), &(sa.sin_addr)) == INET_OPTION_SUC;
304     }
305 #else
306     if (af == AF_INET6) {
307         struct in6_addr addr;
308         return inet_pton(af, ip.c_str(), reinterpret_cast<void *>(&addr)) == INET_OPTION_SUC;
309     } else {
310         struct in_addr addr;
311         return inet_pton(af, ip.c_str(), reinterpret_cast<void *>(&addr)) == INET_OPTION_SUC;
312     }
313 #endif
314 }
315 
MaskIpv4(std::string & maskedResult)316 std::string MaskIpv4(std::string &maskedResult)
317 {
318     int maxDisplayNum = MAX_DISPLAY_NUM;
319     for (char &i : maskedResult) {
320         if (i == '/') {
321             break;
322         }
323         if (maxDisplayNum > 0) {
324             if (i == '.') {
325                 maxDisplayNum--;
326             }
327         } else {
328             if (i != '.') {
329                 i = '*';
330             }
331         }
332     }
333     return maskedResult;
334 }
335 
MaskIpv6(std::string & maskedResult)336 std::string MaskIpv6(std::string &maskedResult)
337 {
338     size_t colonCount = 0;
339     for (char &i : maskedResult) {
340         if (i == '/') {
341             break;
342         }
343         if (i == ':') {
344             colonCount++;
345         }
346 
347         if (colonCount >= MAX_DISPLAY_NUM) {
348             if (i != ':') {
349                 i = '*';
350             }
351         }
352     }
353     return maskedResult;
354 }
355 
AnonymizeIp(std::string & input)356 std::string AnonymizeIp(std::string &input)
357 {
358     if (input.empty()) {
359         return input;
360     }
361     std::lock_guard<std::mutex> lock(g_commonUtilsMutex);
362     std::string maskedResult{input};
363     if (std::regex_match(maskedResult, IP_PATTERN) || std::regex_match(maskedResult, IP_MASK_PATTERN)) {
364         return MaskIpv4(maskedResult);
365     }
366     if (std::regex_match(maskedResult, IPV6_PATTERN) || std::regex_match(maskedResult, IPV6_MASK_PATTERN)) {
367         return MaskIpv6(maskedResult);
368     }
369     return input;
370 }
371 } // namespace OHOS::NetStack::CommonUtils