• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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