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