• 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 
38 namespace OHOS {
39 namespace DHCP {
40 const char *DEFAULT_ROUTE = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
41 const std::string IPV6_ACCEPT_RA_CONFIG_PATH = "/proc/sys/net/ipv6/conf/";
42 const std::string ACCEPT_RA = "accept_ra";
43 const std::string ACCEPT_OVERRULE_FORWORGING = "2";
44 const int INDEX0 = 0;
45 const int INDEX1 = 1;
46 const int INDEX2 = 2;
47 const int INDEX3 = 3;
48 const int INDEX4 = 4;
49 const int INDEX5 = 5;
50 const int INDEX6 = 6;
51 const int INDEX7 = 7;
52 #ifndef ND_OPT_RDNSS
53 #define ND_OPT_RDNSS 25
54 struct nd_opt_rdnss {
55     uint8_t nd_opt_rdnss_type;
56     uint8_t nd_opt_rdnss_len;
57     uint16_t nd_opt_rdnss_reserved;
58     uint32_t nd_opt_rdnss_lifetime;
59 } _packed;
60 #endif
61 DEFINE_DHCPLOG_DHCP_LABEL("DhcpIpv6Client");
62 
IPV6_ADDR_MC_SCOPE(const struct in6_addr * a)63 inline int IPV6_ADDR_MC_SCOPE(const struct in6_addr* a)
64 {
65     return (a)->s6_addr[1] & 0x0f;
66 }
67 
DhcpIpv6Client(std::string ifname)68 DhcpIpv6Client::DhcpIpv6Client(std::string ifname) : interfaceName(ifname)
69 {
70     dhcpIpv6DnsRepository_ = std::make_unique<DnsServerRepository>();
71     DHCP_LOGI("DhcpIpv6Client()");
72 }
73 
~DhcpIpv6Client()74 DhcpIpv6Client::~DhcpIpv6Client()
75 {
76     DHCP_LOGI("~DhcpIpv6Client()");
77     if (dhcpIpv6DnsRepository_ != nullptr) {
78         dhcpIpv6DnsRepository_.reset();
79     }
80 }
81 
IsRunning()82 bool DhcpIpv6Client::IsRunning()
83 {
84     DHCP_LOGI("IsRunning()");
85     return runFlag_.load();
86 }
SetCallback(std::function<void (const std::string ifname,DhcpIpv6Info & info)> callback)87 void DhcpIpv6Client::SetCallback(std::function<void(const std::string ifname, DhcpIpv6Info &info)> callback)
88 {
89     DHCP_LOGI("SetCallback()");
90     std::lock_guard<std::mutex> lock(ipv6CallbackMutex_);
91     onIpv6AddressChanged_ = callback;
92 }
93 
RunIpv6ThreadFunc()94 void DhcpIpv6Client::RunIpv6ThreadFunc()
95 {
96     pthread_setname_np(pthread_self(), "ipv6NetlinkThread");
97     DhcpIpv6Start();
98 }
99 
StartIpv6Thread(const std::string & ifname,bool isIpv6)100 int DhcpIpv6Client::StartIpv6Thread(const std::string &ifname, bool isIpv6)
101 {
102     DHCP_LOGI("StartIpv6Thread ifname:%{public}s bIpv6:%{public}d,runFlag:%{public}d", ifname.c_str(), isIpv6,
103         runFlag_.load());
104 
105     if (!runFlag_.load()) {
106         runFlag_ = true;
107         interfaceName = ifname;
108         if (ipv6Thread_ == nullptr) {
109             ipv6Thread_ = std::make_unique<std::thread>(&DhcpIpv6Client::RunIpv6ThreadFunc, this);
110         }
111     } else {
112         DHCP_LOGI("StartIpv6Thread RunIpv6ThreadFunc!");
113     }
114     return 0;
115 }
116 
ipv6AddrScope2Type(unsigned int scope)117 unsigned int DhcpIpv6Client::ipv6AddrScope2Type(unsigned int scope)
118 {
119     switch (scope) {
120         case IPV6_ADDR_SCOPE_NODELOCAL:
121             return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
122                 IPV6_ADDR_LOOPBACK;
123             break;
124 
125         case IPV6_ADDR_SCOPE_LINKLOCAL:
126             return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
127                 IPV6_ADDR_LINKLOCAL;
128             break;
129 
130         case IPV6_ADDR_SCOPE_SITELOCAL:
131             return IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
132                 IPV6_ADDR_SITELOCAL;
133             break;
134 
135         default:
136             break;
137     }
138 
139     return IPV6_ADDR_SCOPE_TYPE(scope);
140 }
141 
GetAddrType(const struct in6_addr * addr)142 int DhcpIpv6Client::GetAddrType(const struct in6_addr *addr)
143 {
144     if (!addr) {
145         DHCP_LOGE("GetAddrType failed, data invalid.");
146         return IPV6_ADDR_LINKLOCAL;
147     }
148     unsigned int st = addr->s6_addr32[0];
149     if ((st & htonl(ADDRTYPE_FLAG_HIGHE)) != htonl(ADDRTYPE_FLAG_ZERO) &&
150         (st & htonl(ADDRTYPE_FLAG_HIGHE)) != htonl(ADDRTYPE_FLAG_HIGHE)) {
151         return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
152     }
153 
154     if ((st & htonl(ADDRTYPE_FLAG_HIGHFF)) == htonl(ADDRTYPE_FLAG_HIGHFF)) {
155         return (IPV6_ADDR_MULTICAST | ipv6AddrScope2Type(IPV6_ADDR_MC_SCOPE(addr)));
156     }
157 
158     if ((st & htonl(ADDRTYPE_FLAG_HIGHFFC)) == htonl(ADDRTYPE_FLAG_HIGHFE8)) {
159         return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
160             IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
161     }
162 
163     if ((st & htonl(ADDRTYPE_FLAG_HIGHFFC)) == htonl(ADDRTYPE_FLAG_HIGHFEC)) {
164         return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
165             IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));
166     }
167 
168     if ((st & htonl(ADDRTYPE_FLAG_HIGHFE)) == htonl(ADDRTYPE_FLAG_HIGHFC)) {
169         return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
170     }
171 
172     if ((addr->s6_addr32[S6_ADDR_INDEX_ZERO] | addr->s6_addr32[S6_ADDR_INDEX_FIRST]) == 0) {
173         if (addr->s6_addr32[S6_ADDR_INDEX_SECOND] == 0) {
174             if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == 0) {
175                 return IPV6_ADDR_ANY;
176             }
177             if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == htonl(ADDRTYPE_FLAG_ONE)) {
178                 return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
179                     IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));
180             }
181             return (IPV6_ADDR_COMPATV4 | IPV6_ADDR_UNICAST |
182                 IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
183         }
184         if (addr->s6_addr32[S6_ADDR_INDEX_THIRD] == htonl(ADDRTYPE_FLAG_LOWF)) {
185             return (IPV6_ADDR_MAPPED | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
186         }
187     }
188 
189     return (IPV6_ADDR_UNICAST | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
190 }
191 
GetAddrScope(void * addr)192 int DhcpIpv6Client::GetAddrScope(void *addr)
193 {
194     if (!addr) {
195         DHCP_LOGE("GetAddrType failed, data invalid.");
196         return IPV6_ADDR_LINKLOCAL;
197     }
198     in6_addr *ipv6Addr = reinterpret_cast<in6_addr *>(addr);
199     return static_cast<unsigned int>(GetAddrType(ipv6Addr)) & IPV6_ADDR_SCOPE_MASK;
200 }
201 
GetIpv6Prefix(const char * ipv6Addr,char * ipv6PrefixBuf,uint8_t prefixLen)202 void DhcpIpv6Client::GetIpv6Prefix(const char* ipv6Addr, char* ipv6PrefixBuf, uint8_t prefixLen)
203 {
204     if (!ipv6Addr || !ipv6PrefixBuf) {
205         DHCP_LOGE("GetIpv6Prefix failed, input invalid.");
206         return;
207     }
208     if (prefixLen >= DHCP_INET6_ADDRSTRLEN) {
209         strlcpy(ipv6PrefixBuf, ipv6Addr, DHCP_INET6_ADDRSTRLEN);
210         return;
211     }
212 
213     struct in6_addr ipv6AddrBuf = IN6ADDR_ANY_INIT;
214     inet_pton(AF_INET6, ipv6Addr, &ipv6AddrBuf);
215 
216     char buf[INET6_ADDRSTRLEN] = {0};
217     if (inet_ntop(AF_INET6, &ipv6AddrBuf, buf, INET6_ADDRSTRLEN) == NULL) {
218         strlcpy(ipv6PrefixBuf, ipv6Addr, DHCP_INET6_ADDRSTRLEN);
219         return;
220     }
221 
222     struct in6_addr ipv6Prefix = IN6ADDR_ANY_INIT;
223     uint32_t byteIndex = prefixLen / CHAR_BIT;
224     if (memset_s(ipv6Prefix.s6_addr, sizeof(ipv6Prefix.s6_addr), 0, sizeof(ipv6Prefix.s6_addr)) != EOK ||
225         memcpy_s(ipv6Prefix.s6_addr, sizeof(ipv6Prefix.s6_addr), &ipv6AddrBuf, byteIndex) != EOK) {
226         return;
227     }
228     uint32_t bitOffset = prefixLen & MASK_FILTER;
229     if ((bitOffset != 0) && (byteIndex < INET_ADDRSTRLEN)) {
230         ipv6Prefix.s6_addr[byteIndex] = ipv6AddrBuf.s6_addr[byteIndex] & (0xff00 >> bitOffset);
231     }
232     inet_ntop(AF_INET6, &ipv6Prefix, ipv6PrefixBuf, INET6_ADDRSTRLEN);
233 }
234 
GetIpFromS6Address(void * addr,int family,char * buf,int buflen)235 int DhcpIpv6Client::GetIpFromS6Address(void* addr, int family, char* buf, int buflen)
236 {
237     if (family != AF_INET6) {
238         DHCP_LOGE("GetIpFromS6Address family failed");
239         return -1;
240     }
241     if (!inet_ntop(family, (struct in6_addr*)addr, buf, buflen)) {
242         DHCP_LOGE("GetIpFromS6Address failed");
243         return -1;
244     }
245     return 0;
246 }
247 
OnIpv6AddressUpdateEvent(char * addr,int addrlen,int prefixLen,int ifaIndex,int scope,bool isUpdate)248 void DhcpIpv6Client::OnIpv6AddressUpdateEvent(char *addr, int addrlen, int prefixLen,
249                                               int ifaIndex, int scope, bool isUpdate)
250 {
251     int currIndex = static_cast<int>(if_nametoindex(interfaceName.c_str()));
252     if (currIndex != ifaIndex) {
253         DHCP_LOGE("address ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
254         return;
255     }
256     if (!addr) {
257         DHCP_LOGE("OnIpv6AddressUpdateEvent failed, data invalid.");
258         return;
259     }
260     AddrType type = AddrType::UNKNOW;
261     if (scope == 0) {
262         getIpv6RouteAddr();
263         if (memset_s(dhcpIpv6Info.ipv6SubnetAddr, DHCP_INET6_ADDRSTRLEN,
264             0, DHCP_INET6_ADDRSTRLEN) != EOK) {
265             DHCP_LOGE("OnIpv6AddressUpdateEvent memset_s failed");
266             return;
267         }
268         dhcpIpv6Info.status |= 1;
269         GetIpv6Prefix(DEFAULT_ROUTE, dhcpIpv6Info.ipv6SubnetAddr, prefixLen);
270         DHCP_LOGD("OnIpv6AddressUpdateEvent addr:%{private}s, subaddr:%{public}s, route:%{public}s, scope:%{public}d",
271             addr, dhcpIpv6Info.ipv6SubnetAddr, dhcpIpv6Info.routeAddr, scope);
272         type = AddIpv6Address(addr, INET6_ADDRSTRLEN);
273     } else if (scope == IPV6_ADDR_LINKLOCAL) {
274         type = AddrType::DEFAULT;
275     } else {
276         DHCP_LOGD("OnIpv6AddressUpdateEvent other scope:%{public}d", scope);
277     }
278     if (type == AddrType::UNKNOW) {
279         return;
280     }
281 
282     if (isUpdate ? DhcpIpv6InfoManager::UpdateAddr(dhcpIpv6Info, std::string(addr), type) :
283         DhcpIpv6InfoManager::RemoveAddr(dhcpIpv6Info, std::string(addr))) {
284         PublishIpv6Result();
285     }
286 }
287 
AddIpv6Address(char * ipv6addr,int len)288 AddrType DhcpIpv6Client::AddIpv6Address(char *ipv6addr, int len)
289 {
290     AddrType type = AddrType::UNKNOW;
291     if (!ipv6addr) {
292         DHCP_LOGE("AddIpv6Address ipv6addr is nullptr!");
293         return type;
294     }
295     // get the local interface index and MAC address
296     int ifaceIndex = 0;
297     unsigned char ifaceMac[MAC_ADDR_LEN];
298     if (GetLocalInterface(interfaceName.c_str(), &ifaceIndex, ifaceMac, nullptr) != DHCP_OPT_SUCCESS) {
299         DHCP_LOGE("GetLocalInterface failed for interface: %{public}s", interfaceName.c_str());
300         return type;
301     }
302     if (IsGlobalIpv6Address(ipv6addr, len)) {
303         if (IsEui64ModeIpv6Address(ipv6addr, len, ifaceMac, MAC_ADDR_LEN)) {
304             DHCP_LOGI("AddIpv6Address add globalAddr %{public}s", Ipv6Anonymize(ipv6addr).c_str());
305             type = AddrType::GLOBAL;
306         }  else {
307             DHCP_LOGI("AddIpv6Address add randIpv6Addr %{public}s", Ipv6Anonymize(ipv6addr).c_str());
308             type = AddrType::RAND;
309         }
310     } else if (IsUniqueLocalIpv6Address(ipv6addr, len)) {
311         if (IsEui64ModeIpv6Address(ipv6addr, len, ifaceMac, MAC_ADDR_LEN)) {
312             DHCP_LOGI("AddIpv6Address add uniqueLocalAddr1 %{public}s", Ipv6Anonymize(ipv6addr).c_str());
313             type = AddrType::UNIQUE;
314         }  else {
315             DHCP_LOGI("AddIpv6Address add uniqueLocalAddr2 %{public}s", Ipv6Anonymize(ipv6addr).c_str());
316             type = AddrType::UNIQUE2;
317         }
318     } else {
319         DHCP_LOGI("AddIpv6Address add unknow %{public}s", Ipv6Anonymize(ipv6addr).c_str());
320     }
321     return type;
322 }
323 
IsEui64ModeIpv6Address(const char * ipv6addr,int len,const unsigned char * ifaceMac,int macLen)324 bool DhcpIpv6Client::IsEui64ModeIpv6Address(const char *ipv6addr, int len, const unsigned char *ifaceMac, int macLen)
325 {
326     if (ipv6addr == nullptr || len <= 0 || len > DHCP_INET6_ADDRSTRLEN) {
327         DHCP_LOGE("Invalid input: ipv6addr is null or len is non-positive");
328         return false;
329     }
330 
331     if (ifaceMac == nullptr || macLen != MAC_ADDR_LEN) {
332         DHCP_LOGE("Invalid input: ifaceMac is null or macLen is not equal to MAC_ADDR_LEN");
333         return false;
334     }
335 
336     // normalize the IPv6 address
337     struct in6_addr addr;
338     if (inet_pton(AF_INET6, ipv6addr, &addr) != 1) {
339         DHCP_LOGE("inet_pton failed for IPv6 address: %{public}s", Ipv6Anonymize(ipv6addr).c_str());
340         return false;
341     }
342 
343     // get last 64 bits of the IPv6 address
344     const int LEN = 8;
345     uint8_t ipv6Iid[LEN];
346     if (memcpy_s(ipv6Iid, LEN, &addr.s6_addr[LEN], LEN) != EOK) {
347         DHCP_LOGE("Failed to copy last 64 bits of IPv6 address: %{public}s", Ipv6Anonymize(ipv6addr).c_str());
348         return false;
349     }
350 
351     // check for EMU-64 format:
352     const uint8_t EUI64_BIT_3ST = 0xFF;
353     const uint8_t EUI64_BIT_4TH = 0XFE;
354     if (ipv6Iid[INDEX3] != EUI64_BIT_3ST || ipv6Iid[INDEX4] != EUI64_BIT_4TH) {
355         // EUI-64 format requires the IID to contain FF:FE at the 4th and 5th bytes
356         DHCP_LOGE("IPv6 address %{public}s is not in EUI-64 format", Ipv6Anonymize(ipv6addr).c_str());
357         return false;
358     }
359 
360     // reconstruct the MAC address from the IPv6 IID
361     uint8_t reconstructedMac[MAC_ADDR_LEN] = {0};
362     const uint8_t U_L_BIT = 0x02;
363     reconstructedMac[INDEX0] = ipv6Iid[INDEX0] ^ U_L_BIT; // 反转U/L位
364     reconstructedMac[INDEX1] = ipv6Iid[INDEX1];
365     reconstructedMac[INDEX2] = ipv6Iid[INDEX2];
366     reconstructedMac[INDEX3] = ipv6Iid[INDEX5];
367     reconstructedMac[INDEX4] = ipv6Iid[INDEX6];
368     reconstructedMac[INDEX5] = ipv6Iid[INDEX7];
369 
370     // compare the reconstructed MAC address with the interface MAC address
371     bool isMatch = (memcmp(ifaceMac, reconstructedMac, MAC_ADDR_LEN) == 0);
372 
373     DHCP_LOGI("IsEui64ModeIpv6Address EUI-64 check for %{public}s  %{public}s",
374               Ipv6Anonymize(ipv6addr).c_str(), isMatch ? "match" : "mismatch");
375     return isMatch;
376 }
377 
onIpv6DnsAddEvent(void * data,int len,int ifaIndex)378 void DhcpIpv6Client::onIpv6DnsAddEvent(void* data, int len, int ifaIndex)
379 {
380     int currIndex = static_cast<int>(if_nametoindex(interfaceName.c_str()));
381     if (currIndex != ifaIndex) {
382         DHCP_LOGE("dnsevent ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
383         return;
384     }
385     dhcpIpv6Info.status |= (1 << 1);
386     if (!data) {
387         DHCP_LOGE("onIpv6DnsAddEvent failed, data invalid.");
388         return;
389     }
390     struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *)(data);
391     uint16_t optlen = opthdr->nd_opt_len;
392     if (optlen * CHAR_BIT > len) {
393         DHCP_LOGE("dns len invalid optlen:%{public}d > len:%{public}d", optlen, len);
394         return;
395     }
396     if (opthdr->nd_opt_type != ND_OPT_RDNSS) {
397         DHCP_LOGE("dns nd_opt_type invalid:%{public}d", opthdr->nd_opt_type);
398         return;
399     }
400     if ((optlen < ND_OPT_MIN_LEN) || !(optlen & 0x1)) {
401         DHCP_LOGE("dns optLen invalid:%{public}d", optlen);
402         return;
403     }
404     int numaddrs = (optlen - 1) / 2;
405     struct nd_opt_rdnss *rndsopt = (struct nd_opt_rdnss *)opthdr;
406     //RDNSS Lifetime
407     const uint32_t lifetime = ntohl(rndsopt->nd_opt_rdnss_lifetime);
408     DHCP_LOGI("dns opt lifetime %{public}u", lifetime);
409     struct in6_addr *addrs = (struct in6_addr *)(rndsopt + 1);
410     std::vector<std::string> dnsAddrVector;
411     for (int i = 0; i < numaddrs; i++) {
412         char dnsAddr[DHCP_INET6_ADDRSTRLEN] = {0};
413         inet_ntop(AF_INET6, addrs + i, dnsAddr, DHCP_INET6_ADDRSTRLEN);
414         dnsAddrVector.push_back(dnsAddr);
415     }
416     bool changed = dhcpIpv6DnsRepository_->AddServers(lifetime, dnsAddrVector);
417     if (changed) {
418         DHCP_LOGI("onIpv6DnsAddEvent dns servers changed");
419         dhcpIpv6DnsRepository_->SetCurrentServers(dhcpIpv6Info);
420         dhcpIpv6Info.lifetime = lifetime;
421         PublishIpv6Result();
422     }
423 }
424 
OnIpv6RouteUpdateEvent(char * gateway,char * dst,int ifaIndex,bool isAdd)425 void DhcpIpv6Client::OnIpv6RouteUpdateEvent(char* gateway, char* dst, int ifaIndex, bool isAdd)
426 {
427     int currIndex = static_cast<int>(if_nametoindex(interfaceName.c_str()));
428     if (currIndex != ifaIndex) {
429         DHCP_LOGE("route ifaindex invalid, %{public}d != %{public}d", currIndex, ifaIndex);
430         return;
431     }
432     DHCP_LOGI("OnIpv6RouteUpdateEvent gateway:%{private}s, dst:%{private}s, ifindex:%{public}d isAdd: %{public}d",
433         gateway, dst, ifaIndex, isAdd ? 1:0);
434     if (!gateway || !dst) {
435         DHCP_LOGE("OnIpv6RouteUpdateEvent input invalid.");
436         return;
437     }
438     bool isChanged = false;
439     if (strlen(dst) == 0 && strlen(gateway) != 0) {
440         if (isAdd) {
441             isChanged = DhcpIpv6InfoManager::AddRoute(dhcpIpv6Info, std::string(gateway));
442         } else {
443             isChanged = DhcpIpv6InfoManager::RemoveRoute(dhcpIpv6Info, std::string(gateway));
444         }
445     }
446     if (isChanged) {
447         PublishIpv6Result();
448     }
449 }
450 
createKernelSocket(void)451 int32_t DhcpIpv6Client::createKernelSocket(void)
452 {
453     int32_t sz = KERNEL_BUFF_SIZE;
454     int32_t on = 1;
455     int32_t sockFd = socket(AF_NETLINK, SOCK_RAW, 0);
456     if (sockFd < 0) {
457         DHCP_LOGE("dhcp6 create socket failed.");
458         return -1;
459     }
460     if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
461         DHCP_LOGE("setsockopt socket SO_RCVBUFFORCE failed.");
462         close(sockFd);
463         return -1;
464     }
465     if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0) {
466         DHCP_LOGE("setsockopt socket SO_RCVBUF failed.");
467         close(sockFd);
468         return -1;
469     }
470     if (setsockopt(sockFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
471         DHCP_LOGE("setsockopt socket SO_PASSCRED failed.");
472         close(sockFd);
473         return -1;
474     }
475     struct timeval timeout = {1, 0};
476     if (setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
477         DHCP_LOGE("setsockopt socket SO_RCVTIMEO failed.");
478     }
479     struct sockaddr saddr;
480     (void)memset_s(&saddr, sizeof(saddr), 0, sizeof(saddr));
481     setSocketFilter(&saddr);
482     if (bind(sockFd, &saddr, sizeof(saddr)) < 0) {
483         DHCP_LOGE("bind kernel socket failed.");
484         close(sockFd);
485         return -1;
486     }
487     return sockFd;
488 }
489 
Reset()490 void DhcpIpv6Client::Reset()
491 {
492     dhcpIpv6Info.Clear();
493     dhcpIpv6DnsRepository_->Clear();
494 }
495 
getIpv6RouteAddr()496 void DhcpIpv6Client::getIpv6RouteAddr()
497 {
498     int len = ROUTE_BUFF_SIZE;
499     char buffer[ROUTE_BUFF_SIZE] = {0};
500     fillRouteData(buffer, len);
501     if (send(ipv6SocketFd, buffer, len, 0) < 0) {
502         DHCP_LOGE("getIpv6RouteAddr send route info failed.");
503     }
504     DHCP_LOGE("getIpv6RouteAddr send info ok");
505 }
506 
StartIpv6()507 int DhcpIpv6Client::StartIpv6()
508 {
509     DHCP_LOGI("StartIpv6 enter. %{public}s", interfaceName.c_str());
510     Reset();
511     ipv6SocketFd = createKernelSocket();
512     if (ipv6SocketFd < 0) {
513         runFlag_ = false;
514         DHCP_LOGE("StartIpv6 ipv6SocketFd < 0 failed!");
515         return -1;
516     }
517     uint8_t *buff = (uint8_t*)malloc(KERNEL_BUFF_SIZE * sizeof(uint8_t));
518     if (buff == NULL) {
519         DHCP_LOGE("StartIpv6 ipv6 malloc buff failed.");
520         close(ipv6SocketFd);
521         runFlag_ = false;
522         return -1;
523     }
524     struct timeval timeout = {0};
525     fd_set rSet;
526     timeout.tv_sec = 0;
527     timeout.tv_usec = SELECT_TIMEOUT_US;
528     while (runFlag_.load()) {
529         (void)memset_s(buff, KERNEL_BUFF_SIZE * sizeof(uint8_t), 0, KERNEL_BUFF_SIZE * sizeof(uint8_t));
530         FD_ZERO(&rSet);
531         if (ipv6SocketFd < 0) {
532             DHCP_LOGE("error: ipv6SocketFd < 0");
533             break;
534         }
535         FD_SET(ipv6SocketFd, &rSet);
536         int iRet = select(ipv6SocketFd + 1, &rSet, NULL, NULL, &timeout);
537         if (iRet < 0) {
538             if ((iRet == -1) && (errno == EINTR)) {
539                 DHCP_LOGD("StartIpv6 select errno:%{public}d, a signal was caught!", errno);
540             } else {
541                 DHCP_LOGD("StartIpv6 failed, iRet:%{public}d error:%{public}d", iRet, errno);
542             }
543             continue;
544         }
545         if (!FD_ISSET(ipv6SocketFd, &rSet)) {
546             continue;
547         }
548         int32_t len = recv(ipv6SocketFd, buff, KERNEL_BUFF_SIZE, 0);
549         if (len < 0) {
550             DHCP_LOGE("StartIpv6 recv kernel socket failed %{public}d.", errno);
551             sleep(1);
552             continue;
553         } else if (len == 0) {
554             continue;
555         }
556         handleKernelEvent(buff, len);
557     }
558     close(ipv6SocketFd);
559     ipv6SocketFd = 0;
560     free(buff);
561     buff = NULL;
562     DHCP_LOGI("DhcpIpv6Client thread exit.");
563     return 0;
564 }
565 
DhcpIpv6Start()566 void *DhcpIpv6Client::DhcpIpv6Start()
567 {
568     SetAcceptRa(ACCEPT_OVERRULE_FORWORGING);
569     int result = StartIpv6();
570     if (result < 0) {
571         DHCP_LOGE("dhcp6 run failed.");
572     }
573     return NULL;
574 }
575 
SetAcceptRa(const std::string & content)576 void DhcpIpv6Client::SetAcceptRa(const std::string &content)
577 {
578     std::string fileName = IPV6_ACCEPT_RA_CONFIG_PATH + interfaceName + '/' + ACCEPT_RA;
579     if (!IsValidPath(fileName)) {
580         DHCP_LOGE("invalid path:%{public}s", fileName.c_str());
581         return;
582     }
583     std::ofstream outf(fileName, std::ios::out);
584     if (!outf) {
585         DHCP_LOGE("SetAcceptRa, write content [%{public}s] to file [%{public}s] failed. error: %{public}d.",
586             content.c_str(), fileName.c_str(), errno);
587         return;
588     }
589     outf.write(content.c_str(), content.length());
590     outf.close();
591     DHCP_LOGI("SetAcceptRa, write content [%{public}s] to file [%{public}s] success.",
592         content.c_str(), fileName.c_str());
593 }
594 
PublishIpv6Result()595 void DhcpIpv6Client::PublishIpv6Result()
596 {
597     std::lock_guard<std::mutex> lock(ipv6CallbackMutex_);
598     if (onIpv6AddressChanged_ != nullptr) {
599         onIpv6AddressChanged_(interfaceName, dhcpIpv6Info);
600     }
601 }
602 
DhcpIPV6Stop(void)603 void DhcpIpv6Client::DhcpIPV6Stop(void)
604 {
605     DHCP_LOGI("DhcpIPV6Stop exit ipv6 thread, runFlag:%{public}d", runFlag_.load());
606     if (!runFlag_.load()) {
607         return;
608     }
609     runFlag_ = false;
610     if (ipv6Thread_ && ipv6Thread_->joinable()) {
611         ipv6Thread_->join();
612         ipv6Thread_ = nullptr;
613     }
614     std::lock_guard<std::mutex> lock(ipv6CallbackMutex_);
615     onIpv6AddressChanged_ = nullptr;
616 }
617 
IsGlobalIpv6Address(const char * ipv6addr,int len)618 bool DhcpIpv6Client::IsGlobalIpv6Address(const char *ipv6addr, int len)
619 {
620     if (ipv6addr == nullptr || len <= 0 || len > DHCP_INET6_ADDRSTRLEN) {
621         DHCP_LOGE("IsGlobalIpv6Address ipv6addr is nullptr or len invalid!");
622         return false;
623     }
624     struct in6_addr addr = IN6ADDR_ANY_INIT;
625     if (inet_pton(AF_INET6, ipv6addr, &addr) != 1) {
626         DHCP_LOGE("inet_pton failed for ipv6addr:%{public}s", Ipv6Anonymize(ipv6addr).c_str());
627         return false;
628     }
629 
630     // 2001:db8::/32 is documentation address, not global
631     const uint8_t docAddrPrefix[4] = {0x20, 0x01, 0x0d, 0xb8};
632     // Check if the first 4 bytes match the documentation address prefix
633     if (memcmp(addr.s6_addr, docAddrPrefix, sizeof(docAddrPrefix)) == 0) {
634         DHCP_LOGI("IsGlobalIpv6Address addr is documentation address.");
635         return false;
636     }
637     const uint8_t globalUnicastPrefix = 0x20;
638     const uint8_t mask =  0xE0; // 0b11100000
639     // Check if the first byte matches the global unicast prefix
640     // Global Unicast Address: 2000::/3 (0x20 ~ 0x3F)
641     if ((addr.s6_addr[0] & mask) == globalUnicastPrefix) {
642         DHCP_LOGI("IsGlobalIpv6Address addr:%{public}s is global address.", Ipv6Anonymize(ipv6addr).c_str());
643         return true;
644     }
645     return false;
646 }
647 
IsUniqueLocalIpv6Address(const char * ipv6addr,int len)648 bool DhcpIpv6Client::IsUniqueLocalIpv6Address(const char *ipv6addr, int len)
649 {
650     if (ipv6addr == nullptr || len <= 0 || len > DHCP_INET6_ADDRSTRLEN) {
651         DHCP_LOGE("IsUniqueLocalIpv6Address ipv6addr is nullptr or len invalid!");
652         return false;
653     }
654     struct in6_addr addr = IN6ADDR_ANY_INIT;
655     if (inet_pton(AF_INET6, ipv6addr, &addr) != 1) {
656         DHCP_LOGE("inet_pton failed for ipv6addr:%{public}s", Ipv6Anonymize(ipv6addr).c_str());
657         return false;
658     }
659     // Unique Local Address: fc00::/7 (0xfc or 0xfd)
660     const uint8_t uniqueLocalPrefix = 0xFC;
661     const uint8_t mask = 0xFE; // 0b11111110
662     if ((addr.s6_addr[0] & mask) == uniqueLocalPrefix) {
663         return true;
664     }
665     DHCP_LOGI("IsUniqueLocalIpv6Address addr:%{public}s is not unique local address.",
666         Ipv6Anonymize(ipv6addr).c_str());
667     return false;
668 }
669 }  // namespace DHCP
670 }  // namespace OHOS