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.0ys/socket.h
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 #include <signal.h>
16 #include <pthread.h>
17 #include <ifaddrs.h>
18 #include <netdb.h>
19 #include <netinet/icmp6.h>
20 #include <arpa/inet.h>
21 #include <netinet/in.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <dlfcn.h>
25 #include <sys/time.h>
26 #include <net/if.h>
27 #include <errno.h>
28
29 #include "securec.h"
30 #include "wifi_logger.h"
31
32 #include "dhcp_ipv6_client.h"
33
34 namespace OHOS {
35 namespace Wifi {
36 DEFINE_WIFILOG_DHCP_LABEL("WifiDhcpIpv6Client");
37
38 const char *DEFAULUT_BAK_DNS = "240e:4c:4008::1";
39 const char *DEFAULT_ROUTE = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
40 const char *DEFAULT_IPV6_ANY_INIT_ADDR = "::";
41 const int IPV6_ADDR_ANY = 0x0000U;
42 const int IPV6_ADDR_UNICAST = 0x0001U;
43 const int IPV6_ADDR_MULTICAST = 0x0002U;
44 const int IPV6_ADDR_SCOPE_MASK = 0x00F0U;
45 const int IPV6_ADDR_LOOPBACK = 0x0010U;
46 const int IPV6_ADDR_LINKLOCAL = 0x0020U;
47 const int IPV6_ADDR_SITELOCAL = 0x0040U;
48 const int IPV6_ADDR_COMPATV4 = 0x0080U;
49 const int IPV6_ADDR_MAPPED = 0x1000U;
50 const unsigned int IPV6_ADDR_SCOPE_NODELOCAL = 0X01;
51 const unsigned int IPV6_ADDR_SCOPE_LINKLOCAL = 0X02;
52 const unsigned int IPV6_ADDR_SCOPE_SITELOCAL = 0X05;
53 const int IPV6_ADDR_SCOPE_GLOBAL = 0X0E;
54 const int S6_ADDR_INDEX_ZERO = 0;
55 const int S6_ADDR_INDEX_FIRST = 1;
56 const int S6_ADDR_INDEX_SECOND = 2;
57 const int S6_ADDR_INDEX_THIRD = 3;
58 const int ADDRTYPE_FLAG_ZERO = 0x00000000;
59 const int ADDRTYPE_FLAG_ONE = 0x00000001;
60 const int ADDRTYPE_FLAG_LOWF = 0x0000ffff;
61 const int ADDRTYPE_FLAG_HIGHE = 0xE0000000;
62 const int ADDRTYPE_FLAG_HIGHFF = 0xFF000000;
63 const int ADDRTYPE_FLAG_HIGHFFC = 0xFFC00000;
64 const int ADDRTYPE_FLAG_HIGHFE8 = 0xFE800000;
65 const int ADDRTYPE_FLAG_HIGHFEC = 0xFEC00000;
66 const int ADDRTYPE_FLAG_HIGHFE = 0xFE000000;
67 const int ADDRTYPE_FLAG_HIGHFC = 0xFC000000;
68 const int MASK_FILTER = 0x7;
69 const int KERNEL_BUFF_SIZE = (8 * 1024);
70 const int ND_OPT_MIN_LEN = 3;
71 const int ROUTE_BUFF_SIZE = 1024;
72
73 #define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
74 #define IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
75 #ifndef ND_OPT_RDNSS
76 #define ND_OPT_RDNSS 25
77 struct nd_opt_rdnss {
78 uint8_t nd_opt_rdnss_type;
79 uint8_t nd_opt_rdnss_len;
80 uint16_t nd_opt_rdnss_reserved;
81 uint32_t nd_opt_rdnss_lifetime;
82 } _packed;
83 #endif
84
ipv6AddrScope2Type(unsigned int scope)85 unsigned int DhcpIpv6Client::ipv6AddrScope2Type(unsigned int scope)
86 {
87 switch (scope) {
88 case IPV6_ADDR_SCOPE_NODELOCAL:
89 return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
90 IPV6_ADDR_LOOPBACK;
91 break;
92
93 case IPV6_ADDR_SCOPE_LINKLOCAL:
94 return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
95 IPV6_ADDR_LINKLOCAL;
96 break;
97
98 case IPV6_ADDR_SCOPE_SITELOCAL:
99 return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
100 IPV6_ADDR_SITELOCAL;
101 break;
102
103 default:
104 break;
105 }
106
107 return IPV6_ADDR_SCOPE_TYPE(scope);
108 }
109
getAddrType(const struct in6_addr * addr)110 int DhcpIpv6Client::getAddrType(const struct in6_addr *addr)
111 {
112 if (!addr) {
113 WIFI_LOGE("getAddrType failed, data invalid.");
114 return IPV6_ADDR_LINKLOCAL;
115 }
116 unsigned int st = addr->s6_addr32[0];
117 if ((st & htonl(ADDRTYPE_FLAG_HIGHE)) != htonl(ADDRTYPE_FLAG_ZERO) &&
118 (st & htonl(ADDRTYPE_FLAG_HIGHE)) != htonl(ADDRTYPE_FLAG_HIGHE)) {
119 return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
120 }
121
122 if ((st & htonl(ADDRTYPE_FLAG_HIGHFF)) == htonl(ADDRTYPE_FLAG_HIGHFF)) {
123 return (IPV6_ADDR_MULTICAST | ipv6AddrScope2Type(IPV6_ADDR_MC_SCOPE(addr)));
124 }
125
126 if ((st & htonl(ADDRTYPE_FLAG_HIGHFFC)) == htonl(ADDRTYPE_FLAG_HIGHFE8)) {
127 return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
128 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
129 }
130
131 if ((st & htonl(ADDRTYPE_FLAG_HIGHFFC)) == htonl(ADDRTYPE_FLAG_HIGHFEC)) {
132 return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
133 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));
134 }
135
136 if ((st & htonl(ADDRTYPE_FLAG_HIGHFE)) == htonl(ADDRTYPE_FLAG_HIGHFC)) {
137 return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
138 }
139
140 if ((addr->s6_addr32[S6_ADDR_INDEX_ZERO] | addr->s6_addr32[S6_ADDR_INDEX_FIRST]) == 0) {
141 if (addr->s6_addr32[S6_ADDR_INDEX_SECOND] == 0) {
142 if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == 0) {
143 return IPV6_ADDR_ANY;
144 }
145 if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == htonl(ADDRTYPE_FLAG_ONE)) {
146 return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
147 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
148 }
149 return (IPV6_ADDR_COMPATV4 | IPV6_ADDR_UNICAST |
150 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
151 }
152 if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == htonl(ADDRTYPE_FLAG_LOWF)) {
153 return (IPV6_ADDR_MAPPED | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
154 }
155 }
156
157 return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
158 }
159
getAddrScope(const struct in6_addr * addr)160 int DhcpIpv6Client::getAddrScope(const struct in6_addr *addr)
161 {
162 if (!addr) {
163 WIFI_LOGE("getAddrType failed, data invalid.");
164 return IPV6_ADDR_LINKLOCAL;
165 }
166 return getAddrType(addr) & IPV6_ADDR_SCOPE_MASK;
167 }
168
GetIpv6Prefix(const char * ipv6Addr,char * ipv6PrefixBuf,uint8_t prefixLen)169 void DhcpIpv6Client::GetIpv6Prefix(const char* ipv6Addr, char* ipv6PrefixBuf, uint8_t prefixLen)
170 {
171 if (!ipv6Addr || !ipv6PrefixBuf) {
172 WIFI_LOGE("GetIpv6Prefix failed, input invalid.");
173 return;
174 }
175 if (prefixLen >= DHCP_INET6_ADDRSTRLEN) {
176 strlcpy(ipv6PrefixBuf, ipv6Addr, DHCP_INET6_ADDRSTRLEN);
177 return;
178 }
179
180 struct in6_addr ipv6AddrBuf = IN6ADDR_ANY_INIT;
181 inet_pton(AF_INET6, ipv6Addr, &ipv6AddrBuf);
182
183 char buf[INET6_ADDRSTRLEN] = {0};
184 if (inet_ntop(AF_INET6, &ipv6AddrBuf, buf, INET6_ADDRSTRLEN) == NULL) {
185 strlcpy(ipv6PrefixBuf, ipv6Addr, DHCP_INET6_ADDRSTRLEN);
186 return;
187 }
188
189 struct in6_addr ipv6Prefix = IN6ADDR_ANY_INIT;
190 uint32_t byteIndex = prefixLen / CHAR_BIT;
191 if (memset_s(ipv6Prefix.s6_addr, sizeof(ipv6Prefix.s6_addr), 0, sizeof(ipv6Prefix.s6_addr)) != EOK ||
192 memcpy_s(ipv6Prefix.s6_addr, sizeof(ipv6Prefix.s6_addr), &ipv6AddrBuf, byteIndex) != EOK) {
193 return;
194 }
195 uint32_t bitOffset = prefixLen & MASK_FILTER;
196 if ((bitOffset != 0) && (byteIndex < INET_ADDRSTRLEN)) {
197 ipv6Prefix.s6_addr[byteIndex] = ipv6AddrBuf.s6_addr[byteIndex] & (0xff00 >> bitOffset);
198 }
199 inet_ntop(AF_INET6, &ipv6Prefix, ipv6PrefixBuf, INET6_ADDRSTRLEN);
200 }
201
GetIpFromS6Address(void * addr,int family,char * buf,int buflen)202 int DhcpIpv6Client::GetIpFromS6Address(void* addr, int family, char* buf, int buflen)
203 {
204 if (!inet_ntop(family, (struct in6_addr*)addr, buf, buflen)) {
205 WIFI_LOGE("GetIpFromS6Address failed");
206 return -1;
207 }
208 return 0;
209 }
210
onIpv6AddressAddEvent(void * data,int prefixLen,int ifaIndex)211 void DhcpIpv6Client::onIpv6AddressAddEvent(void* data, int prefixLen, int ifaIndex)
212 {
213 int currIndex = if_nametoindex(interfaceName.c_str());
214 if (currIndex != ifaIndex) {
215 WIFI_LOGE("address ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
216 return;
217 }
218 if (!data) {
219 WIFI_LOGE("onIpv6AddressAddEvent failed, data invalid.");
220 return;
221 }
222 struct in6_addr *addr = (struct in6_addr*)data;
223 char addr_str[INET6_ADDRSTRLEN] = {0};
224 inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
225 int scope = getAddrScope(addr);
226 if (scope == 0) {
227 getIpv6RouteAddr();
228 (void)memset_s(dhcpIpv6Info.globalIpv6Addr, DHCP_INET6_ADDRSTRLEN,
229 0, DHCP_INET6_ADDRSTRLEN);
230 (void)memset_s(dhcpIpv6Info.ipv6SubnetAddr, DHCP_INET6_ADDRSTRLEN,
231 0, DHCP_INET6_ADDRSTRLEN);
232 dhcpIpv6Info.status |= 1;
233 (void)memcpy_s(dhcpIpv6Info.globalIpv6Addr, INET6_ADDRSTRLEN, addr_str, INET6_ADDRSTRLEN);
234 GetIpv6Prefix(DEFAULT_ROUTE, dhcpIpv6Info.ipv6SubnetAddr, prefixLen);
235 onIpv6AddressChanged(interfaceName, dhcpIpv6Info);
236 } else if (scope == IPV6_ADDR_LINKLOCAL) {
237 (void)memset_s(dhcpIpv6Info.linkIpv6Addr, DHCP_INET6_ADDRSTRLEN,
238 0, DHCP_INET6_ADDRSTRLEN);
239 (void)memcpy_s(dhcpIpv6Info.linkIpv6Addr, INET6_ADDRSTRLEN, addr_str, INET6_ADDRSTRLEN);
240 onIpv6AddressChanged(interfaceName, dhcpIpv6Info);
241 }
242 WIFI_LOGI("onIpv6AddressAddEvent addr: %{private}s, max: %{private}s, route: %{private}s, scope: %{private}d",
243 addr_str, dhcpIpv6Info.ipv6SubnetAddr, dhcpIpv6Info.routeAddr, scope);
244 }
245
onIpv6DnsAddEvent(void * data,int len,int ifaIndex)246 void DhcpIpv6Client::onIpv6DnsAddEvent(void* data, int len, int ifaIndex)
247 {
248 int currIndex = if_nametoindex(interfaceName.c_str());
249 if (currIndex != ifaIndex) {
250 WIFI_LOGE("dnsevent ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
251 return;
252 }
253 dhcpIpv6Info.status |= (1 << 1);
254 (void)strncpy_s(dhcpIpv6Info.dnsAddr, DHCP_INET6_ADDRSTRLEN,
255 DEFAULUT_BAK_DNS, strlen(DEFAULUT_BAK_DNS));
256 do {
257 if (!data) {
258 WIFI_LOGE("onIpv6DnsAddEvent failed, data invalid.");
259 break;
260 }
261 struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *)(data);
262 uint16_t optlen = opthdr->nd_opt_len;
263 if (optlen * CHAR_BIT > len) {
264 WIFI_LOGE("dns len invalid optlen:%{public}d > len:%{public}d", optlen, len);
265 break;
266 }
267 if (opthdr->nd_opt_type != ND_OPT_RDNSS) {
268 WIFI_LOGE("dns nd_opt_type invlid:%{public}d", opthdr->nd_opt_type);
269 break;
270 }
271 if ((optlen < ND_OPT_MIN_LEN) || !(optlen & 0x1)) {
272 WIFI_LOGE("dns optLen invlid:%{public}d", optlen);
273 break;
274 }
275 (void)memset_s(dhcpIpv6Info.dnsAddr2, DHCP_INET6_ADDRSTRLEN,
276 0, DHCP_INET6_ADDRSTRLEN);
277 int numaddrs = (optlen - 1) / 2;
278 struct nd_opt_rdnss *rndsopt = (struct nd_opt_rdnss *)opthdr;
279 struct in6_addr *addrs = (struct in6_addr *)(rndsopt + 1);
280 for (int i = 0; i < numaddrs; i++) {
281 inet_ntop(AF_INET6, addrs + i, dhcpIpv6Info.dnsAddr2, DHCP_INET6_ADDRSTRLEN);
282 break;
283 }
284 onIpv6AddressChanged(interfaceName, dhcpIpv6Info);
285 WIFI_LOGI("onIpv6DnsAddEvent addr: %{private}s", dhcpIpv6Info.dnsAddr2);
286 } while (false);
287 }
288
onIpv6RouteAddEvent(char * gateway,char * dst,int ifaIndex)289 void DhcpIpv6Client::onIpv6RouteAddEvent(char* gateway, char* dst, int ifaIndex)
290 {
291 int currIndex = if_nametoindex(interfaceName.c_str());
292 if (currIndex != ifaIndex) {
293 WIFI_LOGE("route ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
294 return;
295 }
296 WIFI_LOGE("onIpv6RouteAddEvent gateway:%{public}s, dst:%{public}s, ifindex:%{public}d",
297 gateway, dst, ifaIndex);
298 if (!gateway || !dst) {
299 WIFI_LOGE("onIpv6RouteAddEvent input invalid.");
300 return;
301 }
302 if (strlen(dst) == 0 && strlen(gateway) != 0) {
303 (void)memset_s(dhcpIpv6Info.routeAddr, DHCP_INET6_ADDRSTRLEN,
304 0, DHCP_INET6_ADDRSTRLEN);
305 if (strncpy_s(dhcpIpv6Info.routeAddr, DHCP_INET6_ADDRSTRLEN, gateway, strlen(gateway)) != EOK) {
306 WIFI_LOGE("onIpv6RouteAddEvent strncpy_s gateway failed");
307 return;
308 }
309 onIpv6AddressChanged(interfaceName, dhcpIpv6Info);
310 }
311 }
312
createKernelSocket(void)313 int32_t DhcpIpv6Client::createKernelSocket(void)
314 {
315 int32_t sz = KERNEL_BUFF_SIZE;
316 int32_t on = 1;
317 int32_t sockFd = socket(AF_NETLINK, SOCK_RAW, 0);
318 if (sockFd < 0) {
319 WIFI_LOGE("dhcp6 create socket failed.");
320 return -1;
321 }
322 if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
323 WIFI_LOGE("setsockopt socket SO_RCVBUFFORCE failed.");
324 close(sockFd);
325 return -1;
326 }
327 if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) {
328 WIFI_LOGE("setsockopt socket SO_RCVBUF failed.");
329 close(sockFd);
330 return -1;
331 }
332 if (setsockopt(sockFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
333 WIFI_LOGE("setsockopt socket SO_PASSCRED failed.");
334 close(sockFd);
335 return -1;
336 }
337 struct timeval timeout = {1, 0};
338 if (setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
339 WIFI_LOGE("setsockopt socket SO_RCVTIMEO failed.");
340 }
341 struct sockaddr saddr;
342 (void)memset_s(&saddr, sizeof(saddr), 0, sizeof(saddr));
343 setSocketFilter(&saddr);
344 if (bind(sockFd, &saddr, sizeof(saddr)) < 0) {
345 WIFI_LOGE("bind kernel socket failed.");
346 close(sockFd);
347 return -1;
348 }
349 return sockFd;
350 }
351
Reset()352 void DhcpIpv6Client::Reset()
353 {
354 (void)memset_s(&dhcpIpv6Info, sizeof(dhcpIpv6Info), 0, sizeof(dhcpIpv6Info));
355 }
356
getIpv6RouteAddr()357 void DhcpIpv6Client::getIpv6RouteAddr()
358 {
359 int len = ROUTE_BUFF_SIZE;
360 char buffer[ROUTE_BUFF_SIZE] = {0};
361 fillRouteData(buffer, len);
362 if (send(ipv6SocketFd, buffer, len, 0) < 0) {
363 WIFI_LOGE("getIpv6RouteAddr send route info failed.");
364 }
365 }
366
StartIpv6(const char * ifname)367 int DhcpIpv6Client::StartIpv6(const char *ifname)
368 {
369 if (!ifname) {
370 WIFI_LOGE("StartIpv6 failed, ifname invalid.");
371 return -1;
372 }
373 WIFI_LOGI("StartIpv6 enter. %{public}s", ifname);
374 interfaceName = ifname;
375 (void)memset_s(&dhcpIpv6Info, sizeof(dhcpIpv6Info), 0, sizeof(dhcpIpv6Info));
376 runFlag = true;
377 ipv6SocketFd = createKernelSocket();
378 if (ipv6SocketFd < 0) {
379 WIFI_LOGE("StartIpv6 createKernelSocket failed.");
380 runFlag = false;
381 return -1;
382 }
383 uint8_t *buff = (uint8_t*)malloc(KERNEL_BUFF_SIZE * sizeof(uint8_t));
384 if (buff == NULL) {
385 WIFI_LOGE("ipv6 malloc buff failed.");
386 close(ipv6SocketFd);
387 runFlag = false;
388 return -1;
389 }
390 struct timeval timeout = {0};
391 fd_set rSet;
392 timeout.tv_sec = 1;
393 timeout.tv_usec = 0;
394 while (runFlag) {
395 (void)memset_s(buff, KERNEL_BUFF_SIZE * sizeof(uint8_t), 0,
396 KERNEL_BUFF_SIZE * sizeof(uint8_t));
397 FD_ZERO(&rSet);
398 FD_SET(ipv6SocketFd, &rSet);
399 int iRet = select(ipv6SocketFd + 1, &rSet, NULL, NULL, &timeout);
400 if (iRet < 0) {
401 WIFI_LOGE("StartIpv6 select failed.");
402 break;
403 } else if (iRet == 0) {
404 continue;
405 }
406 if (!FD_ISSET(ipv6SocketFd, &rSet)) {
407 continue;
408 }
409 int32_t len = recv(ipv6SocketFd, buff, 8 *1024, 0);
410 if (len < 0) {
411 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
412 continue;
413 }
414 WIFI_LOGE("recv kernel socket failed %{public}d.", errno);
415 break;
416 } else if (len == 0) {
417 continue;
418 }
419 handleKernelEvent(buff, len);
420 }
421 close(ipv6SocketFd);
422 ipv6SocketFd = 0;
423 runFlag = false;
424 free(buff);
425 buff = NULL;
426 WIFI_LOGI("DhcpIpv6Client thread exit.");
427 return 0;
428 }
429
DhcpIpv6Start(const char * param)430 void *DhcpIpv6Client::DhcpIpv6Start(const char* param)
431 {
432 if (runFlag) {
433 WIFI_LOGI("DhcpIpv6Client already started.");
434 return NULL;
435 }
436 if (!param) {
437 WIFI_LOGE("DhcpIpv6Start failed, param invalid.");
438 return NULL;
439 }
440 int result = StartIpv6((char*)param);
441 if (result < 0) {
442 WIFI_LOGE("dhcp6 run failed.");
443 }
444 return NULL;
445 }
446
DhcpIPV6Stop(void)447 void DhcpIpv6Client::DhcpIPV6Stop(void)
448 {
449 WIFI_LOGI("DhcpIPV6Stop enter.");
450 runFlag = false;
451 }
452 } // namespace Wifi
453 } // namespace OHOS