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