• 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 <csignal>
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 <cstdio>
23 #include <unistd.h>
24 #include <dlfcn.h>
25 #include <sys/time.h>
26 #include <net/if.h>
27 #include <errno.h>
28 #include <fstream>
29 #include <thread>
30 #include "securec.h"
31 #include "dhcp_logger.h"
32 #include "dhcp_ipv6_client.h"
33 #include "dhcp_result.h"
34 #include "dhcp_thread.h"
35 #include "dhcp_function.h"
36 #include "dhcp_common_utils.h"
37 #ifndef OHOS_EUPDATER
38 #include "dhcp_system_timer.h"
39 #endif
40 
41 namespace OHOS {
42 namespace DHCP {
43 DEFINE_DHCPLOG_DHCP_LABEL("DhcpIpv6Client");
44 
45 const char *DEFAULUT_BAK_DNS = "240e:4c:4008::1";
46 const char *DEFAULT_ROUTE = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
47 const char *DEFAULT_IPV6_ANY_INIT_ADDR = "::";
48 const int IPV6_ADDR_ANY = 0x0000U;
49 const int IPV6_ADDR_UNICAST = 0x0001U;
50 const int IPV6_ADDR_MULTICAST = 0x0002U;
51 const int IPV6_ADDR_SCOPE_MASK = 0x00F0U;
52 const int IPV6_ADDR_LOOPBACK = 0x0010U;
53 const int IPV6_ADDR_LINKLOCAL = 0x0020U;
54 const int IPV6_ADDR_SITELOCAL = 0x0040U;
55 const int IPV6_ADDR_COMPATV4 = 0x0080U;
56 const int IPV6_ADDR_MAPPED = 0x1000U;
57 const unsigned int IPV6_ADDR_SCOPE_NODELOCAL = 0X01;
58 const unsigned int  IPV6_ADDR_SCOPE_LINKLOCAL = 0X02;
59 const unsigned int  IPV6_ADDR_SCOPE_SITELOCAL = 0X05;
60 const int  IPV6_ADDR_SCOPE_GLOBAL = 0X0E;
61 const int S6_ADDR_INDEX_ZERO = 0;
62 const int S6_ADDR_INDEX_FIRST = 1;
63 const int S6_ADDR_INDEX_SECOND = 2;
64 const int S6_ADDR_INDEX_THIRD = 3;
65 const int ADDRTYPE_FLAG_ZERO = 0x00000000;
66 const int ADDRTYPE_FLAG_ONE = 0x00000001;
67 const int ADDRTYPE_FLAG_LOWF = 0x0000ffff;
68 const int ADDRTYPE_FLAG_HIGHE = 0xE0000000;
69 const int ADDRTYPE_FLAG_HIGHFF = 0xFF000000;
70 const int ADDRTYPE_FLAG_HIGHFFC = 0xFFC00000;
71 const int ADDRTYPE_FLAG_HIGHFE8 = 0xFE800000;
72 const int ADDRTYPE_FLAG_HIGHFEC = 0xFEC00000;
73 const int ADDRTYPE_FLAG_HIGHFE = 0xFE000000;
74 const int ADDRTYPE_FLAG_HIGHFC = 0xFC000000;
75 const int MASK_FILTER = 0x7;
76 const int KERNEL_BUFF_SIZE = (8 * 1024);
77 const int ND_OPT_MIN_LEN = 3;
78 const int ROUTE_BUFF_SIZE = 1024;
79 const int POSITION_OFFSET_1 = 1;
80 const int POSITION_OFFSET_2 = 2;
81 const int POSITION_OFFSET_3 = 3;
82 const int POSITION_OFFSET_4 = 4;
83 const std::string IPV6_ACCEPT_RA_CONFIG_PATH = "/proc/sys/net/ipv6/conf/";
84 const std::string ACCEPT_RA = "accept_ra";
85 const std::string ACCEPT_OVERRULE_FORWORGING = "2";
86 
87 #define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
88 #define IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
89 #ifndef ND_OPT_RDNSS
90 #define ND_OPT_RDNSS 25
91 struct nd_opt_rdnss {
92     uint8_t nd_opt_rdnss_type;
93     uint8_t nd_opt_rdnss_len;
94     uint16_t nd_opt_rdnss_reserved;
95     uint32_t nd_opt_rdnss_lifetime;
96 } _packed;
97 #endif
98 
DhcpIpv6Client(std::string ifname)99 DhcpIpv6Client::DhcpIpv6Client(std::string ifname) : interfaceName(ifname)
100 {
101 #ifndef OHOS_ARCH_LITE
102     ipv6TimerId_ = 0;
103 #endif
104     ipv6Thread_ = std::make_unique<DhcpThread>("InnerIpv6Thread");
105     DHCP_LOGI("DhcpIpv6Client()");
106 }
107 
~DhcpIpv6Client()108 DhcpIpv6Client::~DhcpIpv6Client()
109 {
110     DHCP_LOGI("~DhcpIpv6Client()");
111     if (ipv6Thread_ != nullptr) {
112         ipv6Thread_.reset();
113     }
114 }
115 
IsRunning()116 bool DhcpIpv6Client::IsRunning()
117 {
118     DHCP_LOGI("IsRunning()");
119     return runFlag_.load();
120 }
SetCallback(std::function<void (const std::string ifname,DhcpIpv6Info & info)> callback)121 void DhcpIpv6Client::SetCallback(std::function<void(const std::string ifname, DhcpIpv6Info &info)> callback)
122 {
123     DHCP_LOGI("SetCallback()");
124     std::lock_guard<std::mutex> lock(ipv6CallbackMutex_);
125     onIpv6AddressChanged_ = callback;
126 }
127 
RunIpv6ThreadFunc()128 void DhcpIpv6Client::RunIpv6ThreadFunc()
129 {
130     DhcpIpv6Start();
131 }
132 
StartIpv6Thread(const std::string & ifname,bool isIpv6)133 int DhcpIpv6Client::StartIpv6Thread(const std::string &ifname, bool isIpv6)
134 {
135     DHCP_LOGI("StartIpv6Thread ifname:%{public}s bIpv6:%{public}d,runFlag:%{public}d", ifname.c_str(), isIpv6,
136         runFlag_.load());
137     if (!runFlag_.load()) {
138         runFlag_ = true;
139         interfaceName = ifname;
140         if (ipv6Thread_ == nullptr) {
141             ipv6Thread_ = std::make_unique<DhcpThread>("InnerIpv6Thread");
142         }
143 #ifndef OHOS_ARCH_LITE
144         StartIpv6Timer();
145 #endif
146         std::function<void()> func = [this]() { this->RunIpv6ThreadFunc(); };
147         int delayTime = 0;
148         bool result = ipv6Thread_->PostAsyncTask(func, delayTime);
149         if (!result) {
150             DHCP_LOGE("StartIpv6Thread PostAsyncTask failed!");
151         }
152         DHCP_LOGI("StartIpv6Thread RunIpv6ThreadFunc ok!");
153     } else {
154         DHCP_LOGI("StartIpv6Thread RunIpv6ThreadFunc!");
155     }
156     return 0;
157 }
158 
ipv6AddrScope2Type(unsigned int scope)159 unsigned int DhcpIpv6Client::ipv6AddrScope2Type(unsigned int scope)
160 {
161     switch (scope) {
162         case IPV6_ADDR_SCOPE_NODELOCAL:
163             return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
164                 IPV6_ADDR_LOOPBACK;
165             break;
166 
167         case IPV6_ADDR_SCOPE_LINKLOCAL:
168             return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
169                 IPV6_ADDR_LINKLOCAL;
170             break;
171 
172         case IPV6_ADDR_SCOPE_SITELOCAL:
173             return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
174                 IPV6_ADDR_SITELOCAL;
175             break;
176 
177         default:
178             break;
179     }
180 
181     return IPV6_ADDR_SCOPE_TYPE(scope);
182 }
183 
getAddrType(const struct in6_addr * addr)184 int DhcpIpv6Client::getAddrType(const struct in6_addr *addr)
185 {
186     if (!addr) {
187         DHCP_LOGE("getAddrType failed, data invalid.");
188         return IPV6_ADDR_LINKLOCAL;
189     }
190     unsigned int st = addr->s6_addr32[0];
191     if ((st & htonl(ADDRTYPE_FLAG_HIGHE)) != htonl(ADDRTYPE_FLAG_ZERO) &&
192         (st & htonl(ADDRTYPE_FLAG_HIGHE)) != htonl(ADDRTYPE_FLAG_HIGHE)) {
193         return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
194     }
195 
196     if ((st & htonl(ADDRTYPE_FLAG_HIGHFF)) == htonl(ADDRTYPE_FLAG_HIGHFF)) {
197         return (IPV6_ADDR_MULTICAST | ipv6AddrScope2Type(IPV6_ADDR_MC_SCOPE(addr)));
198     }
199 
200     if ((st & htonl(ADDRTYPE_FLAG_HIGHFFC)) == htonl(ADDRTYPE_FLAG_HIGHFE8)) {
201         return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
202             IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
203     }
204 
205     if ((st & htonl(ADDRTYPE_FLAG_HIGHFFC)) == htonl(ADDRTYPE_FLAG_HIGHFEC)) {
206         return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
207             IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));
208     }
209 
210     if ((st & htonl(ADDRTYPE_FLAG_HIGHFE)) == htonl(ADDRTYPE_FLAG_HIGHFC)) {
211         return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
212     }
213 
214     if ((addr->s6_addr32[S6_ADDR_INDEX_ZERO] | addr->s6_addr32[S6_ADDR_INDEX_FIRST]) == 0) {
215         if (addr->s6_addr32[S6_ADDR_INDEX_SECOND] == 0) {
216             if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == 0) {
217                 return IPV6_ADDR_ANY;
218             }
219             if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == htonl(ADDRTYPE_FLAG_ONE)) {
220                 return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
221                     IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
222             }
223             return (IPV6_ADDR_COMPATV4 | IPV6_ADDR_UNICAST |
224                 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
225         }
226         if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == htonl(ADDRTYPE_FLAG_LOWF)) {
227             return (IPV6_ADDR_MAPPED | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
228         }
229     }
230 
231     return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
232 }
233 
getAddrScope(const struct in6_addr * addr)234 int DhcpIpv6Client::getAddrScope(const struct in6_addr *addr)
235 {
236     if (!addr) {
237         DHCP_LOGE("getAddrType failed, data invalid.");
238         return IPV6_ADDR_LINKLOCAL;
239     }
240     return static_cast<unsigned int>(getAddrType(addr)) & IPV6_ADDR_SCOPE_MASK;
241 }
242 
GetIpv6Prefix(const char * ipv6Addr,char * ipv6PrefixBuf,uint8_t prefixLen)243 void DhcpIpv6Client::GetIpv6Prefix(const char* ipv6Addr, char* ipv6PrefixBuf, uint8_t prefixLen)
244 {
245     if (!ipv6Addr || !ipv6PrefixBuf) {
246         DHCP_LOGE("GetIpv6Prefix failed, input invalid.");
247         return;
248     }
249     if (prefixLen >= DHCP_INET6_ADDRSTRLEN) {
250         strlcpy(ipv6PrefixBuf, ipv6Addr, DHCP_INET6_ADDRSTRLEN);
251         return;
252     }
253 
254     struct in6_addr ipv6AddrBuf = IN6ADDR_ANY_INIT;
255     inet_pton(AF_INET6, ipv6Addr, &ipv6AddrBuf);
256 
257     char buf[INET6_ADDRSTRLEN] = {0};
258     if (inet_ntop(AF_INET6, &ipv6AddrBuf, buf, INET6_ADDRSTRLEN) == NULL) {
259         strlcpy(ipv6PrefixBuf, ipv6Addr, DHCP_INET6_ADDRSTRLEN);
260         return;
261     }
262 
263     struct in6_addr ipv6Prefix = IN6ADDR_ANY_INIT;
264     uint32_t byteIndex = prefixLen / CHAR_BIT;
265     if (memset_s(ipv6Prefix.s6_addr, sizeof(ipv6Prefix.s6_addr), 0, sizeof(ipv6Prefix.s6_addr)) != EOK ||
266         memcpy_s(ipv6Prefix.s6_addr, sizeof(ipv6Prefix.s6_addr), &ipv6AddrBuf, byteIndex) != EOK) {
267         return;
268     }
269     uint32_t bitOffset = prefixLen & MASK_FILTER;
270     if ((bitOffset != 0) && (byteIndex < INET_ADDRSTRLEN)) {
271         ipv6Prefix.s6_addr[byteIndex] = ipv6AddrBuf.s6_addr[byteIndex] & (0xff00 >> bitOffset);
272     }
273     inet_ntop(AF_INET6, &ipv6Prefix, ipv6PrefixBuf, INET6_ADDRSTRLEN);
274 }
275 
GetIpFromS6Address(void * addr,int family,char * buf,int buflen)276 int DhcpIpv6Client::GetIpFromS6Address(void* addr, int family, char* buf, int buflen)
277 {
278     if (!inet_ntop(family, (struct in6_addr*)addr, buf, buflen)) {
279         DHCP_LOGE("GetIpFromS6Address failed");
280         return -1;
281     }
282     return 0;
283 }
284 
onIpv6AddressAddEvent(void * data,int prefixLen,int ifaIndex)285 void DhcpIpv6Client::onIpv6AddressAddEvent(void* data, int prefixLen, int ifaIndex)
286 {
287     int currIndex = static_cast<int>(if_nametoindex(interfaceName.c_str()));
288     if (currIndex != ifaIndex) {
289         DHCP_LOGE("address ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
290         return;
291     }
292     if (!data) {
293         DHCP_LOGE("onIpv6AddressAddEvent failed, data invalid.");
294         return;
295     }
296     struct in6_addr *addr = (struct in6_addr*)data;
297     char addr_str[INET6_ADDRSTRLEN] = {0};
298     inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
299     int scope = getAddrScope(addr);
300     if (scope == 0) {
301         getIpv6RouteAddr();
302         if (memset_s(dhcpIpv6Info.ipv6SubnetAddr, DHCP_INET6_ADDRSTRLEN,
303             0, DHCP_INET6_ADDRSTRLEN) != EOK) {
304             DHCP_LOGE("onIpv6AddressAddEvent memset_s failed");
305             return;
306         }
307         dhcpIpv6Info.status |= 1;
308         GetIpv6Prefix(DEFAULT_ROUTE, dhcpIpv6Info.ipv6SubnetAddr, prefixLen);
309         DHCP_LOGD("onIpv6AddressAddEvent addr:%{private}s, subaddr:%{public}s, route:%{public}s, scope:%{public}d",
310             addr_str, dhcpIpv6Info.ipv6SubnetAddr, dhcpIpv6Info.routeAddr, scope);
311         AddIpv6Address(addr_str, INET6_ADDRSTRLEN);
312     } else if (scope == IPV6_ADDR_LINKLOCAL) {
313         if (memset_s(dhcpIpv6Info.linkIpv6Addr, DHCP_INET6_ADDRSTRLEN, 0, DHCP_INET6_ADDRSTRLEN) != EOK ||
314             memcpy_s(dhcpIpv6Info.linkIpv6Addr, INET6_ADDRSTRLEN, addr_str, INET6_ADDRSTRLEN) != EOK) {
315             DHCP_LOGE("onIpv6AddressAddEvent memset_s or memcpy_s failed");
316             return;
317         }
318         DHCP_LOGD("onIpv6AddressAddEvent addr:%{public}s, subaddr:%{public}s, route:%{public}s, scope:%{public}d",
319             addr_str, dhcpIpv6Info.ipv6SubnetAddr, dhcpIpv6Info.routeAddr, scope);
320         if (strlen(dhcpIpv6Info.linkIpv6Addr) != 0) {
321             PublishIpv6Result();
322         }
323     } else {
324         DHCP_LOGD("onIpv6AddressAddEvent other scope:%{public}d", scope);
325     }
326 }
327 
AddIpv6Address(char * ipv6addr,int len)328 void DhcpIpv6Client::AddIpv6Address(char *ipv6addr, int len)
329 {
330     if (!ipv6addr) {
331         DHCP_LOGE("AddIpv6Address ipv6addr is nullptr!");
332         return;
333     }
334     int first = ipv6addr[0]-'0';
335     if (first == NUMBER_TWO || first == NUMBER_THREE) { // begin '2' '3'
336         if (IsEui64ModeIpv6Address(ipv6addr, len)) {
337             DHCP_LOGI("AddIpv6Address add globalIpv6Addr, first=%{public}d", first);
338             if (memcpy_s(dhcpIpv6Info.globalIpv6Addr, len, ipv6addr, len) != EOK) {
339                 DHCP_LOGE("AddIpv6Address memcpy_s failed!");
340                 return;
341             }
342         }  else {
343             DHCP_LOGI("AddIpv6Address add randIpv6Addr, first=%{public}d", first);
344             if (memcpy_s(dhcpIpv6Info.randIpv6Addr, len, ipv6addr, len) != EOK) {
345                 DHCP_LOGE("onIpv6AddressAddEvent memcpy_s failed!");
346                 return;
347             }
348         }
349         if (strlen(dhcpIpv6Info.globalIpv6Addr) != 0 || strlen(dhcpIpv6Info.randIpv6Addr) != 0) {
350             PublishIpv6Result();
351         }
352     } else if (first == NUMBER_FIFTY_FOUR) {  // begin 'f'->54
353         if (IsEui64ModeIpv6Address(ipv6addr, len)) {
354             if (memcpy_s(dhcpIpv6Info.uniqueLocalAddr1, len, ipv6addr, len) != EOK) {
355                 DHCP_LOGE("AddIpv6Address memcpy_s failed!");
356                 return;
357             }
358             DHCP_LOGI("AddIpv6Address add uniqueLocalAddr1, first=%{public}d", first);
359         }  else {
360             if (memcpy_s(dhcpIpv6Info.uniqueLocalAddr2, len, ipv6addr, len) != EOK) {
361                 DHCP_LOGE("AddIpv6Address uniqueLocalAddr2 memcpy_s failed!");
362                 return;
363             }
364             DHCP_LOGI("AddIpv6Address add uniqueLocalAddr2, first=%{public}d", first);
365         }
366         if (strlen(dhcpIpv6Info.uniqueLocalAddr1) != 0 || strlen(dhcpIpv6Info.uniqueLocalAddr2) != 0) {
367             PublishIpv6Result();
368         }
369     } else {
370         DHCP_LOGI("AddIpv6Address other first=%{public}d", first);
371     }
372 }
373 
IsEui64ModeIpv6Address(char * ipv6addr,int len)374 bool DhcpIpv6Client::IsEui64ModeIpv6Address(char *ipv6addr, int len)
375 {
376     if (ipv6addr == nullptr) {
377         DHCP_LOGE("IsEui64ModeIpv6Address ipv6addr is nullptr!");
378         return false;
379     }
380     int ifaceIndex = 0;
381     unsigned char ifaceMac[MAC_ADDR_LEN];
382     if (GetLocalInterface(interfaceName.c_str(), &ifaceIndex, ifaceMac, NULL) != DHCP_OPT_SUCCESS) {
383         DHCP_LOGE("IsEui64ModeIpv6Address GetLocalInterface failed, ifaceName:%{public}s.", interfaceName.c_str());
384         return false;
385     }
386     char macAddr[MAC_ADDR_LEN * MAC_ADDR_CHAR_NUM];
387     if (memset_s(macAddr, sizeof(macAddr), 0, sizeof(macAddr)) != EOK) {
388         DHCP_LOGE("IsEui64ModeIpv6Address memset_s failed!");
389         return false;
390     }
391     MacChConToMacStr(ifaceMac, MAC_ADDR_LEN, macAddr, sizeof(macAddr));
392     std::string localMacString = macAddr;
393     std::string ipv6AddrString = ipv6addr;
394     size_t macPosition = localMacString.find_last_of(':');
395     size_t ipv6position = ipv6AddrString.find_last_of(':');
396     DHCP_LOGI("IsEui64ModeIpv6Address name:%{public}s index:%{public}d %{public}zu %{public}zu len:%{public}d",
397         interfaceName.c_str(), ifaceIndex, macPosition, ipv6position, len);
398     if ((macPosition != std::string::npos) && (ipv6position != std::string::npos)) {
399         if (macAddr[macPosition + POSITION_OFFSET_1] == ipv6addr[ipv6position + POSITION_OFFSET_3] &&
400             macAddr[macPosition + POSITION_OFFSET_2] == ipv6addr[ipv6position + POSITION_OFFSET_4] &&
401             macAddr[macPosition - POSITION_OFFSET_1] == ipv6addr[ipv6position + POSITION_OFFSET_2] &&
402             macAddr[macPosition - POSITION_OFFSET_2] == ipv6addr[ipv6position + POSITION_OFFSET_1]) {
403             DHCP_LOGI("IsEui64ModeIpv6Address is true!");
404             return true;
405         }
406     }
407     return false;
408 }
409 
onIpv6DnsAddEvent(void * data,int len,int ifaIndex)410 void DhcpIpv6Client::onIpv6DnsAddEvent(void* data, int len, int ifaIndex)
411 {
412     int currIndex = static_cast<int>(if_nametoindex(interfaceName.c_str()));
413     if (currIndex != ifaIndex) {
414         DHCP_LOGE("dnsevent ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
415         return;
416     }
417     dhcpIpv6Info.status |= (1 << 1);
418     if (!data) {
419         DHCP_LOGE("onIpv6DnsAddEvent failed, data invalid.");
420         return;
421     }
422     struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *)(data);
423     uint16_t optlen = opthdr->nd_opt_len;
424     if (optlen * CHAR_BIT > len) {
425         DHCP_LOGE("dns len invalid optlen:%{public}d > len:%{public}d", optlen, len);
426         return;
427     }
428     if (opthdr->nd_opt_type != ND_OPT_RDNSS) {
429         DHCP_LOGE("dns nd_opt_type invlid:%{public}d", opthdr->nd_opt_type);
430         return;
431     }
432     if ((optlen < ND_OPT_MIN_LEN) || !(optlen & 0x1)) {
433         DHCP_LOGE("dns optLen invlid:%{public}d", optlen);
434         return;
435     }
436     int numaddrs = (optlen - 1) / 2;
437     struct nd_opt_rdnss *rndsopt = (struct nd_opt_rdnss *)opthdr;
438     struct in6_addr *addrs = (struct in6_addr *)(rndsopt + 1);
439     if (numaddrs > 0) {
440         (void)memset_s(dhcpIpv6Info.dnsAddr, DHCP_INET6_ADDRSTRLEN, 0, DHCP_INET6_ADDRSTRLEN);
441         inet_ntop(AF_INET6, addrs, dhcpIpv6Info.dnsAddr, DHCP_INET6_ADDRSTRLEN);
442     }
443     for (int i = 0; i < numaddrs; i++) {
444         char dnsAddr[DHCP_INET6_ADDRSTRLEN] = {0};
445         inet_ntop(AF_INET6, addrs + i, dnsAddr, DHCP_INET6_ADDRSTRLEN);
446         auto iter = find(dhcpIpv6Info.vectorDnsAddr.begin(), dhcpIpv6Info.vectorDnsAddr.end(), dnsAddr);
447         if (iter == dhcpIpv6Info.vectorDnsAddr.end()) {
448             dhcpIpv6Info.vectorDnsAddr.push_back(dnsAddr);
449             DHCP_LOGI("onIpv6DnsAddEvent add dns:%{public}d", i);
450         }
451     }
452 }
453 
onIpv6RouteAddEvent(char * gateway,char * dst,int ifaIndex)454 void DhcpIpv6Client::onIpv6RouteAddEvent(char* gateway, char* dst, int ifaIndex)
455 {
456     int currIndex = static_cast<int>(if_nametoindex(interfaceName.c_str()));
457     if (currIndex != ifaIndex) {
458         DHCP_LOGE("route ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
459         return;
460     }
461     DHCP_LOGI("onIpv6RouteAddEvent gateway:%{private}s, dst:%{private}s, ifindex:%{public}d",
462         gateway, dst, ifaIndex);
463     if (!gateway || !dst) {
464         DHCP_LOGE("onIpv6RouteAddEvent input invalid.");
465         return;
466     }
467     if (strlen(dst) == 0 && strlen(gateway) != 0) {
468         (void)memset_s(dhcpIpv6Info.routeAddr, DHCP_INET6_ADDRSTRLEN,
469             0, DHCP_INET6_ADDRSTRLEN);
470         if (strncpy_s(dhcpIpv6Info.routeAddr, DHCP_INET6_ADDRSTRLEN, gateway, strlen(gateway)) != EOK) {
471             DHCP_LOGE("onIpv6RouteAddEvent strncpy_s gateway failed");
472             return;
473         }
474     }
475 }
476 
createKernelSocket(void)477 int32_t DhcpIpv6Client::createKernelSocket(void)
478 {
479     int32_t sz = KERNEL_BUFF_SIZE;
480     int32_t on = 1;
481     int32_t sockFd = socket(AF_NETLINK, SOCK_RAW, 0);
482     if (sockFd < 0) {
483         DHCP_LOGE("dhcp6 create socket failed.");
484         return -1;
485     }
486     if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
487         DHCP_LOGE("setsockopt socket SO_RCVBUFFORCE failed.");
488         close(sockFd);
489         return -1;
490     }
491     if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) {
492         DHCP_LOGE("setsockopt socket SO_RCVBUF failed.");
493         close(sockFd);
494         return -1;
495     }
496     if (setsockopt(sockFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
497         DHCP_LOGE("setsockopt socket SO_PASSCRED failed.");
498         close(sockFd);
499         return -1;
500     }
501     struct timeval timeout = {1, 0};
502     if (setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
503         DHCP_LOGE("setsockopt socket SO_RCVTIMEO failed.");
504     }
505     struct sockaddr saddr;
506     (void)memset_s(&saddr, sizeof(saddr), 0, sizeof(saddr));
507     setSocketFilter(&saddr);
508     if (bind(sockFd, &saddr, sizeof(saddr)) < 0) {
509         DHCP_LOGE("bind kernel socket failed.");
510         close(sockFd);
511         return -1;
512     }
513     return sockFd;
514 }
515 
Reset()516 void DhcpIpv6Client::Reset()
517 {
518     (void)memset_s(&dhcpIpv6Info, sizeof(dhcpIpv6Info), 0, sizeof(dhcpIpv6Info));
519 }
520 
getIpv6RouteAddr()521 void DhcpIpv6Client::getIpv6RouteAddr()
522 {
523     int len = ROUTE_BUFF_SIZE;
524     char buffer[ROUTE_BUFF_SIZE] = {0};
525     fillRouteData(buffer, len);
526     if (send(ipv6SocketFd, buffer, len, 0) < 0) {
527         DHCP_LOGE("getIpv6RouteAddr send route info failed.");
528     }
529     DHCP_LOGE("getIpv6RouteAddr send info ok");
530 }
531 
StartIpv6()532 int DhcpIpv6Client::StartIpv6()
533 {
534     DHCP_LOGI("StartIpv6 enter. %{public}s", interfaceName.c_str());
535     (void)memset_s(&dhcpIpv6Info, sizeof(dhcpIpv6Info), 0, sizeof(dhcpIpv6Info));
536     ipv6SocketFd = createKernelSocket();
537     if (ipv6SocketFd < 0) {
538         runFlag_ = false;
539         DHCP_LOGE("StartIpv6 ipv6SocketFd < 0 failed!");
540         return -1;
541     }
542     uint8_t *buff = (uint8_t*)malloc(KERNEL_BUFF_SIZE * sizeof(uint8_t));
543     if (buff == NULL) {
544         DHCP_LOGE("StartIpv6 ipv6 malloc buff failed.");
545         close(ipv6SocketFd);
546         runFlag_ = false;
547         return -1;
548     }
549     struct timeval timeout = {0};
550     fd_set rSet;
551     timeout.tv_sec = 0;
552     timeout.tv_usec = SELECT_TIMEOUT_US;
553     while (runFlag_.load()) {
554         (void)memset_s(buff, KERNEL_BUFF_SIZE * sizeof(uint8_t), 0, KERNEL_BUFF_SIZE * sizeof(uint8_t));
555         FD_ZERO(&rSet);
556         if (ipv6SocketFd < 0) {
557             DHCP_LOGE("error: ipv6SocketFd < 0");
558             break;
559         }
560         FD_SET(ipv6SocketFd, &rSet);
561         int iRet = select(ipv6SocketFd + 1, &rSet, NULL, NULL, &timeout);
562         if (iRet < 0) {
563             if ((iRet == -1) && (errno == EINTR)) {
564                 DHCP_LOGD("StartIpv6 select errno:%{public}d, a signal was caught!", errno);
565             } else {
566                 DHCP_LOGD("StartIpv6 failed, iRet:%{public}d error:%{public}d", iRet, errno);
567             }
568             continue;
569         }
570         if (!FD_ISSET(ipv6SocketFd, &rSet)) {
571             continue;
572         }
573         int32_t len = recv(ipv6SocketFd, buff, 8 *1024, 0);
574         if (len < 0) {
575             if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
576                 continue;
577             }
578             DHCP_LOGE("StartIpv6 recv kernel socket failed %{public}d.", errno);
579             break;
580         } else if (len == 0) {
581             continue;
582         }
583         handleKernelEvent(buff, len);
584     }
585     close(ipv6SocketFd);
586     ipv6SocketFd = 0;
587     free(buff);
588     buff = NULL;
589     DHCP_LOGI("DhcpIpv6Client thread exit.");
590     return 0;
591 }
592 
DhcpIpv6Start()593 void *DhcpIpv6Client::DhcpIpv6Start()
594 {
595     SetAcceptRa(ACCEPT_OVERRULE_FORWORGING);
596     int result = StartIpv6();
597     if (result < 0) {
598         DHCP_LOGE("dhcp6 run failed.");
599     }
600     return NULL;
601 }
602 
SetAcceptRa(const std::string & content)603 void DhcpIpv6Client::SetAcceptRa(const std::string &content)
604 {
605     std::string fileName = IPV6_ACCEPT_RA_CONFIG_PATH + interfaceName + '/' + ACCEPT_RA;
606     if (!IsValidPath(fileName)) {
607         DHCP_LOGE("invalid path:%{public}s", fileName.c_str());
608         return;
609     }
610     std::ofstream outf(fileName, std::ios::out);
611     if (!outf) {
612         DHCP_LOGE("SetAcceptRa, write content [%{public}s] to file [%{public}s] failed. error: %{public}d.",
613             content.c_str(), fileName.c_str(), errno);
614         return;
615     }
616     outf.write(content.c_str(), content.length());
617     outf.close();
618     DHCP_LOGI("SetAcceptRa, write content [%{public}s] to file [%{public}s] success.",
619         content.c_str(), fileName.c_str());
620 }
621 
PublishIpv6Result()622 void DhcpIpv6Client::PublishIpv6Result()
623 {
624     std::lock_guard<std::mutex> lock(ipv6CallbackMutex_);
625     if (onIpv6AddressChanged_ != nullptr) {
626         onIpv6AddressChanged_(interfaceName, dhcpIpv6Info);
627     }
628 }
629 
DhcpIPV6Stop(void)630 void DhcpIpv6Client::DhcpIPV6Stop(void)
631 {
632     DHCP_LOGI("DhcpIPV6Stop exit ipv6 thread, runFlag:%{public}d", runFlag_.load());
633     if (!runFlag_.load()) {
634         return;
635     }
636     runFlag_ = false;
637 #ifndef OHOS_ARCH_LITE
638     StopIpv6Timer();
639 #endif
640     std::lock_guard<std::mutex> lock(ipv6CallbackMutex_);
641     onIpv6AddressChanged_ = nullptr;
642 }
643 
644 #ifndef OHOS_ARCH_LITE
645 using TimeOutCallback = std::function<void()>;
Ipv6TimerCallback()646 void DhcpIpv6Client::Ipv6TimerCallback()
647 {
648     DHCP_LOGI("enter Ipv6TimerCallback, ipv6TimerId:%{public}" PRIu64, ipv6TimerId_);
649     StopIpv6Timer();
650     DhcpIpv6TimerCallbackEvent(interfaceName.c_str());
651 }
652 
StartIpv6Timer()653 void DhcpIpv6Client::StartIpv6Timer()
654 {
655     std::unique_lock<std::mutex> lock(ipv6TimerMutex);
656     DHCP_LOGI("StartIpv6Timer ipv6TimerId:%{public}" PRIu64, ipv6TimerId_);
657     if (ipv6TimerId_ != 0) {
658         DHCP_LOGE("StartIpv6Timer ipv6TimerId !=0 id:%{public}" PRIu64, ipv6TimerId_);
659         return;
660     }
661 
662 #ifndef OHOS_EUPDATER
663     std::shared_ptr<OHOS::DHCP::DhcpSysTimer> dhcpSysTimer =
664         std::make_shared<OHOS::DHCP::DhcpSysTimer>(false, 0, false, false);
665     if (dhcpSysTimer == nullptr) {
666         DHCP_LOGE("StartIpv6Timer dhcpSysTimer is nullptr");
667         return;
668     }
669 #endif
670 
671     std::function<void()> timeCallback = [this] { this->Ipv6TimerCallback(); };
672     if (timeCallback != nullptr) {
673 #ifndef OHOS_EUPDATER
674         dhcpSysTimer->SetCallbackInfo(timeCallback);
675         ipv6TimerId_ = MiscServices::TimeServiceClient::GetInstance()->CreateTimer(dhcpSysTimer);
676         int64_t currentTime = MiscServices::TimeServiceClient::GetInstance()->GetBootTimeMs();
677         MiscServices::TimeServiceClient::GetInstance()->StartTimer(ipv6TimerId_,
678             currentTime + DhcpTimer::DEFAULT_TIMEROUT);
679 #else
680         uint32_t tempTimerId = 0;
681         DhcpTimer::GetInstance()->Register(timeCallback, tempTimerId, DhcpTimer::DEFAULT_TIMEROUT);
682         ipv6TimerId_ = tempTimerId;
683 #endif
684         DHCP_LOGI("StartIpv6Timer success! ipv6TimerId:%{public}" PRIu64, ipv6TimerId_);
685     }
686 }
687 
StopIpv6Timer()688 void DhcpIpv6Client::StopIpv6Timer()
689 {
690     std::unique_lock<std::mutex> lock(ipv6TimerMutex);
691     DHCP_LOGI("StopIpv6Timer ipv6TimerId:%{public}" PRIu64, ipv6TimerId_);
692     if (ipv6TimerId_ == 0) {
693         DHCP_LOGE("StopIpv6Timer ipv6TimerId is 0");
694         return;
695     }
696 #ifndef OHOS_EUPDATER
697     MiscServices::TimeServiceClient::GetInstance()->StopTimer(ipv6TimerId_);
698     MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(ipv6TimerId_);
699 #else
700     DhcpTimer::GetInstance()->UnRegister(static_cast<uint32_t>(ipv6TimerId_));
701 #endif
702     ipv6TimerId_ = 0;
703     return;
704 }
705 #endif
706 }  // namespace DHCP
707 }  // namespace OHOS