1 /*
2 * Copyright (c) 2025 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 "net_trace_route_probe.h"
17 #include <cctype>
18 #include <dirent.h>
19 #include <cerrno>
20 #include <fcntl.h>
21 #include <fnmatch.h>
22 #include <grp.h>
23 #include <cinttypes>
24 #include <climits>
25 #include <cmath>
26 #include <paths.h>
27 #include <pwd.h>
28 #include <regex.h>
29 #include <sched.h>
30 #include <csetjmp>
31 #include <csignal>
32 #include <cstdarg>
33 #include <cstddef>
34 #include <cstdint>
35 #include <cstdio>
36 #include <cstdlib>
37 #include <cstring>
38 #include <strings.h>
39 #include <sys/mman.h>
40 #include <sys/resource.h>
41 #include <sys/stat.h>
42 #include <sys/statvfs.h>
43 #include <sys/time.h>
44 #include <sys/times.h>
45 #include <sys/utsname.h>
46 #include <sys/wait.h>
47 #include <termios.h>
48 #include <ctime>
49 #include <unistd.h>
50 #include <utime.h>
51
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #include <net/if.h>
55 #include <netinet/in.h>
56 #include <netinet/tcp.h>
57 #include <poll.h>
58 #include <sys/socket.h>
59 #include <sys/un.h>
60
61 #include <clocale>
62 #include <cwchar>
63 #include <cwctype>
64
65 #include <thread>
66
67 #include <sys/ioctl.h>
68
69 #include <ifaddrs.h>
70 #include <netinet/ip_icmp.h>
71 #include "ffrt.h"
72
73 #define TRACE_ROUTE_DATA_SIZE 1024
74 #define TIME_BASE_MS 1000
75 #define TIME_BASE_US 1000000
76 #define PING_NUM 5
77 #define PING_TIMEOUT_NUM 3
78
79 #define ICMP_ECHO_REQUEST 8
80 #define ICMPV6_ECHO_REQUEST 128
81
82 namespace OHOS {
83 namespace NetManagerStandard {
84
85 typedef struct IpInfo {
86 int ttl;
87 std::string ip;
88 int64_t delay[PING_NUM];
89 std::string rtt;
90 } IpInfo;
91
Now(void)92 static long long Now(void)
93 {
94 struct timespec ts;
95 clock_gettime(CLOCK_MONOTONIC, &ts);
96 return ts.tv_sec * TIME_BASE_MS + ts.tv_nsec / TIME_BASE_US;
97 }
98
TraceRouteCkSum(uint16_t * data,int len)99 unsigned short TraceRouteCkSum(uint16_t *data, int len)
100 {
101 uint32_t sum = 0;
102 uint16_t answer = 0;
103 uint8_t lenSize = 2;
104 uint8_t twoBytes = 16;
105
106 // 累加所有 16-bit 字
107 while (len > 1) {
108 sum += *data++;
109 len -= lenSize;
110 }
111
112 // 如果剩余 1 字节(奇数长度),补零并累加
113 if (len == 1) {
114 *reinterpret_cast<uint8_t *>(&answer) = *reinterpret_cast<uint8_t *>(data);
115 sum += answer;
116 }
117
118 // 回卷溢出位(carry-around)
119 sum = (sum >> twoBytes) + (sum & 0xFFFF);
120 sum += (sum >> twoBytes);
121
122 // 取反码
123 answer = ~sum;
124 return answer;
125 }
126
WaitResponse(int fd,int flag)127 static int WaitResponse(int fd, int flag)
128 {
129 struct pollfd pfd;
130 int32_t timeout = 1000;
131 pfd.fd = fd;
132 pfd.events = POLLIN;
133 if (poll(&pfd, 1, timeout) <= 0) {
134 return -1;
135 }
136 return 0;
137 }
138
ComputeRtt(struct IpInfo & ipinfo)139 void ComputeRtt(struct IpInfo &ipinfo)
140 {
141 // 初始化变量
142 int64_t maxValue = ipinfo.delay[0];
143 int64_t minValue = ipinfo.delay[0];
144 int64_t sum = 0;
145
146 // 遍历数组,计算最大值、最小值和总和
147 for (int i = 0; i < PING_NUM; ++i) {
148 if (ipinfo.delay[i] > maxValue) {
149 maxValue = ipinfo.delay[i];
150 }
151 if (ipinfo.delay[i] < minValue) {
152 minValue = ipinfo.delay[i];
153 }
154 sum += ipinfo.delay[i];
155 }
156
157 int64_t avg = sum / PING_NUM; // 计算平均值
158
159 // 计算标准差
160 int64_t varianceSum = 0;
161 for (int i = 0; i < PING_NUM; ++i) {
162 varianceSum += (ipinfo.delay[i] - avg) * (ipinfo.delay[i] - avg);
163 }
164 int64_t variance = varianceSum / PING_NUM;
165 int64_t standardDeviation = sqrt(variance);
166 ipinfo.rtt = std::to_string(maxValue) + ";" + std::to_string(minValue) + ";" + std::to_string(avg) +
167 ";" + std::to_string(standardDeviation) + " ";
168 }
169
GetIPAddress(struct addrinfo * ai)170 std::string GetIPAddress(struct addrinfo *ai)
171 {
172 std::string host;
173 if (ai->ai_family == AF_INET) {
174 auto addr = reinterpret_cast<sockaddr_in *>(ai->ai_addr);
175 char ip[INET_ADDRSTRLEN] = {0};
176 inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip));
177 host = ip;
178 } else if (ai->ai_family == AF_INET6) {
179 auto addr = reinterpret_cast<sockaddr_in6 *>(ai->ai_addr);
180 char ip[INET6_ADDRSTRLEN] = {0};
181 inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip));
182 host = ip;
183 }
184 return host;
185 }
186
TimeOutHandle(struct IpInfo & ipinfo,struct addrinfo * ai,int count)187 void TimeOutHandle(struct IpInfo &ipinfo, struct addrinfo *ai, int count)
188 {
189 if (ipinfo.ip == "") {
190 ipinfo.ip = "*.*.*.*";
191 for (int i = 0; i < PING_NUM; i++) {
192 ipinfo.delay[i] = TIME_BASE_MS;
193 }
194 return;
195 }
196 if (count >= PING_NUM) {
197 return;
198 }
199 ipinfo.delay[count] = TIME_BASE_MS;
200 }
201
ReSend(struct IpInfo & ipinfo,int i)202 void ReSend(struct IpInfo &ipinfo, int i)
203 {
204 struct addrinfo info = {0};
205 struct addrinfo *ai = nullptr;
206 int family = AF_UNSPEC;
207 info.ai_family = family;
208 const char *dest = ipinfo.ip.c_str();
209 if (getaddrinfo(dest, nullptr, &info, &ai) < 0) {
210 return;
211 }
212 if (ai == nullptr) {
213 return;
214 }
215 int sockfd = socket(ai->ai_family, SOCK_DGRAM, (ai->ai_family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
216 if (sockfd < 0) {
217 return;
218 }
219 unsigned char buffer[sizeof(struct icmphdr) + TRACE_ROUTE_DATA_SIZE] = {0}; /* icmp header and data */
220 struct icmphdr *ih = reinterpret_cast<struct icmphdr*>(buffer);
221 ih->type = (ai->ai_family == AF_INET) ? ICMP_ECHO_REQUEST : ICMPV6_ECHO_REQUEST;
222 ih->code = 0;
223 ih->un.echo.id = getpid();
224 ih->un.echo.sequence = ipinfo.ttl;
225 ih->checksum = 0;
226 ih->checksum = TraceRouteCkSum(reinterpret_cast<uint16_t *>(ih), sizeof(*ih));
227 long long timeSend = Now();
228 if (sendto(sockfd, buffer, sizeof(buffer), 0, ai->ai_addr, sizeof(*(ai->ai_addr))) < 0) {
229 close(sockfd);
230 return;
231 }
232 if (WaitResponse(sockfd, 0) < 0) {
233 TimeOutHandle(ipinfo, ai, i + 1); // 超时处理
234 close(sockfd);
235 return;
236 }
237 struct sockaddr_in srcAddr;
238 socklen_t addrLen = sizeof(srcAddr);
239 char recvBuffer[1024];
240 if (recvfrom(sockfd, recvBuffer, sizeof(recvBuffer), 0,
241 reinterpret_cast<struct sockaddr *>(&srcAddr), &addrLen) <= 0) {
242 close(sockfd);
243 return;
244 }
245 long long timeRecv = Now() - timeSend;
246 ipinfo.delay[i] = timeRecv; // 记录rtt
247 close(sockfd);
248 return;
249 }
250
Send(struct IpInfo & ipinfo)251 void Send(struct IpInfo &ipinfo)
252 {
253 std::vector<ffrt::task_handle> tasks(PING_NUM - 1); // 创建ffrt数组
254
255 // 循环创建ffrt
256 for (uint i = 0; i < PING_NUM - 1; ++i) {
257 auto task = ffrt::submit_h([ &, i ]() {
258 ReSend(ipinfo, i);
259 }, {}, {}, {ffrt::task_attr().name(("ReSend" + std::to_string(i)).c_str())});
260 tasks[i] = std::move(task);
261 }
262
263 // 等待所有ffrt完成
264 for (auto& task : tasks) {
265 ffrt::wait({task}); // 等待ffrt结束
266 }
267 ComputeRtt(ipinfo);
268 return;
269 }
270
CreateTasks(std::vector<struct IpInfo> & ipinfo)271 void CreateTasks(std::vector<struct IpInfo> &ipinfo)
272 {
273 std::vector<ffrt::task_handle> tasks(ipinfo.size()); // 创建ffrt数组
274 for (uint i = 0; i < ipinfo.size(); ++i) {
275 if (ipinfo[i].ip == "*.*.*.*") {
276 continue;
277 }
278 struct IpInfo &info = ipinfo[i];
279 auto task = ffrt::submit_h([ & ]() { Send(info); },
280 {}, {}, {ffrt::task_attr().name(("Send" + std::to_string(i)).c_str())});
281 tasks[i] = std::move(task);
282 }
283 for (auto& task : tasks) {
284 ffrt::wait({task}); // 等待ffrt结束
285 }
286 }
287
recv(struct IpInfo & info,std::vector<struct IpInfo> & ipinfo,int sockfd,long long timeSend,int family)288 void recv(struct IpInfo &info, std::vector<struct IpInfo> &ipinfo, int sockfd, long long timeSend, int family)
289 {
290 char recvBuffer[1024];
291 if (family == AF_INET) {
292 struct sockaddr_in srcAddr;
293 socklen_t addrLen = sizeof(srcAddr);
294 ssize_t received = recvfrom(sockfd, recvBuffer, sizeof(recvBuffer), 0,
295 reinterpret_cast<struct sockaddr*>(&srcAddr), &addrLen);
296 char srcIp[INET_ADDRSTRLEN];
297 inet_ntop(AF_INET, &(srcAddr.sin_addr), srcIp, INET_ADDRSTRLEN);
298 info.ip = std::string(srcIp); // 记录IP地址
299 } else if (family == AF_INET6) {
300 struct sockaddr_in6 srcAddr;
301 socklen_t addrLen = sizeof(srcAddr);
302 ssize_t received = recvfrom(sockfd, recvBuffer, sizeof(recvBuffer), 0,
303 reinterpret_cast<struct sockaddr*>(&srcAddr), &addrLen);
304 char srcIp[INET6_ADDRSTRLEN];
305 inet_ntop(AF_INET6, &(srcAddr.sin6_addr), srcIp, INET6_ADDRSTRLEN);
306 info.ip = std::string(srcIp); // 记录IPV6地址
307 }
308 long long timeRecv = Now() - timeSend;
309 info.delay[0] = timeRecv;
310 ipinfo.push_back(info); // 将info对象添加到vector中
311 }
312
doTraceRoute(struct addrinfo * ai,int32_t maxJumpNumber,int32_t packetsType,std::string & traceRouteInfo)313 static int doTraceRoute(struct addrinfo *ai, int32_t maxJumpNumber, int32_t packetsType, std::string &traceRouteInfo)
314 {
315 std::vector<struct IpInfo> ipinfo;
316 int sockfd = socket(ai->ai_family, SOCK_RAW, (ai->ai_family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
317 if (sockfd < 0) {
318 return 0;
319 }
320 int32_t count = 0;
321 for (int32_t ttl = 1; ttl <= maxJumpNumber; ttl++) {
322 struct IpInfo info; // 每次循环创建一个IpInfo对象
323 info.ttl = ttl;
324 unsigned char buffer[sizeof(struct icmphdr) + TRACE_ROUTE_DATA_SIZE] = {0}; /* icmp header and data */
325 struct icmphdr *ih = reinterpret_cast<struct icmphdr*>(buffer);
326 ih->type = (ai->ai_family == AF_INET) ? ICMP_ECHO_REQUEST : ICMPV6_ECHO_REQUEST;
327 ih->code = 0;
328 ih->un.echo.id = getpid();
329 ih->un.echo.sequence = ttl;
330 setsockopt(sockfd, (ai->ai_family == AF_INET) ? SOL_IP : SOL_IPV6,
331 (ai->ai_family == AF_INET) ? IP_TTL : IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
332 ih->checksum = 0;
333 ih->checksum = TraceRouteCkSum(reinterpret_cast<uint16_t*>(buffer), sizeof(buffer));
334 long long timeSend = Now();
335 ssize_t sent = sendto(sockfd, buffer, sizeof(buffer), 0,
336 ai->ai_addr, ai->ai_addrlen);
337 if (sent < 0) {
338 continue;
339 }
340 int rc = WaitResponse(sockfd, 0);
341 if (rc < 0) {
342 count++;
343 TimeOutHandle(info, ai, 0); // 超时处理
344 ComputeRtt(info);
345 ipinfo.push_back(info); // 将info对象添加到vector中
346 if (count >= PING_TIMEOUT_NUM) { // 3跳超时,直接break
347 break;
348 }
349 continue;
350 }
351 recv(info, ipinfo, sockfd, timeSend, ai->ai_family);
352 if (info.ip == GetIPAddress(ai)) {
353 break;
354 }
355 }
356 CreateTasks(ipinfo);
357 close(sockfd);
358 for (uint i = 0; i < ipinfo.size(); ++i) {
359 traceRouteInfo += std::to_string(ipinfo[i].ttl) + " " + ipinfo[i].ip + " " + ipinfo[i].rtt;
360 }
361 return 0;
362 }
363
QueryTraceRouteProbeResult(const std::string & destination,int32_t maxJumpNumber,int32_t packetsType,std::string & traceRouteInfo)364 int32_t QueryTraceRouteProbeResult(const std::string &destination, int32_t maxJumpNumber, int32_t packetsType,
365 std::string &traceRouteInfo)
366 {
367 struct addrinfo info = {0};
368 struct addrinfo *ai = nullptr;
369 int32_t family = AF_UNSPEC;
370
371 info.ai_family = family;
372 const char *dest = destination.c_str();
373 int32_t rc = getaddrinfo(dest, nullptr, &info, &ai);
374 if (rc < 0 || ai == nullptr) {
375 return 0;
376 }
377 rc = doTraceRoute(ai, maxJumpNumber, packetsType, traceRouteInfo);
378
379 if (ai != nullptr) {
380 freeaddrinfo(ai);
381 }
382 return rc;
383 }
384
385 }
386 }
387