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