1 /*
2 * Copyright (C) 2021-2022 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.0
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 "dhcp_ipv6_client.h"
16
17 #include <unistd.h>
18 #include <linux/rtnetlink.h>
19 #include "dhcp_logger.h"
20
21 namespace OHOS {
22 namespace DHCP {
23 DEFINE_DHCPLOG_DHCP_LABEL("WifiDhcpIpv6Event");
24
25 const int KERNEL_SOCKET_FAMILY = 16;
26 const int KERNEL_SOCKET_IFA_FAMILY = 10;
27 const int KERNEL_ICMP_TYPE = 134;
28 const int IPV6_LENGTH_BYTES = 16;
29 constexpr int ND_OPT_HDR_LENGTH_BYTES = 2;
30
setSocketFilter(void * addr)31 void DhcpIpv6Client::setSocketFilter(void* addr)
32 {
33 if (!addr) {
34 DHCP_LOGE("setSocketFilter failed, addr invalid.");
35 return;
36 }
37 struct sockaddr_nl *nladdr = (struct sockaddr_nl*)addr;
38 nladdr->nl_family = KERNEL_SOCKET_FAMILY;
39 nladdr->nl_pid = 0;
40 nladdr->nl_groups = RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE | (1 << (RTNLGRP_ND_USEROPT - 1));
41 }
42
parseNdUserOptMessage(void * data,int len)43 void DhcpIpv6Client::parseNdUserOptMessage(void* data, int len)
44 {
45 if (!data) {
46 DHCP_LOGE("parseNdUserOptMessage failed, msg invalid.");
47 return;
48 }
49 if (len < (static_cast<int>(sizeof(struct nduseroptmsg)) + ND_OPT_HDR_LENGTH_BYTES)) {
50 DHCP_LOGE("parseNdUserOptMessage invalid len:%{public}d.", len);
51 return;
52 }
53 struct nduseroptmsg *msg = (struct nduseroptmsg *)data;
54 if (msg->nduseropt_opts_len > len) {
55 DHCP_LOGE("invliad len msg->nduseropt_opts_len:%{public}d > len:%{public}d",
56 msg->nduseropt_opts_len, len);
57 return;
58 }
59 int optlen = msg->nduseropt_opts_len;
60 if (msg->nduseropt_family != KERNEL_SOCKET_IFA_FAMILY) {
61 DHCP_LOGE("invliad nduseropt_family:%{public}d", msg->nduseropt_family);
62 return;
63 }
64 if (msg->nduseropt_icmp_type != KERNEL_ICMP_TYPE || msg->nduseropt_icmp_code != 0) {
65 DHCP_LOGE("invliad nduseropt_icmp_type:%{public}d, nduseropt_icmp_type:%{public}d",
66 msg->nduseropt_icmp_type, msg->nduseropt_icmp_code);
67 return;
68 }
69 onIpv6DnsAddEvent((void*)(msg + 1), optlen, msg->nduseropt_ifindex);
70 }
71
parseNDRouteMessage(void * msg)72 void DhcpIpv6Client::parseNDRouteMessage(void* msg)
73 {
74 if (msg == NULL) {
75 return;
76 }
77 struct nlmsghdr *hdrMsg = (struct nlmsghdr*)msg;
78 if (hdrMsg->nlmsg_len < sizeof(struct ndmsg) + sizeof(struct rtmsg)) {
79 return;
80 }
81 struct rtmsg* rtMsg = reinterpret_cast<struct rtmsg*>(NLMSG_DATA(hdrMsg));
82 if (hdrMsg->nlmsg_len < sizeof(struct rtmsg) + NLMSG_LENGTH(0)) {
83 DHCP_LOGE("invliad msglen:%{public}d", hdrMsg->nlmsg_len);
84 return;
85 }
86 if ((rtMsg->rtm_protocol != RTPROT_KERNEL && rtMsg->rtm_protocol != RTPROT_RA) ||
87 (rtMsg->rtm_scope != RT_SCOPE_UNIVERSE) || (rtMsg->rtm_type != RTN_UNICAST) ||
88 (rtMsg->rtm_src_len != 0) || (rtMsg->rtm_flags & RTM_F_CLONED)) {
89 DHCP_LOGE("invliad arg");
90 return;
91 }
92 char dst[DHCP_INET6_ADDRSTRLEN] = {0};
93 char gateway[DHCP_INET6_ADDRSTRLEN] = {0};
94 int32_t rtmFamily = rtMsg->rtm_family;
95 size_t size = RTM_PAYLOAD(hdrMsg);
96 int ifindex = -1;
97 rtattr *rtaInfo = NULL;
98 for (rtaInfo = RTM_RTA(rtMsg); RTA_OK(rtaInfo, (int)size); rtaInfo = RTA_NEXT(rtaInfo, size)) {
99 switch (rtaInfo->rta_type) {
100 case RTA_GATEWAY:
101 if (rtaInfo->rta_len < (RTA_LENGTH(IPV6_LENGTH_BYTES))) {
102 return;
103 }
104 if (GetIpFromS6Address(RTA_DATA(rtaInfo), rtmFamily, gateway, sizeof(gateway)) != 0) {
105 DHCP_LOGE("inet_ntop RTA_GATEWAY failed.");
106 return;
107 }
108 break;
109 case RTA_DST:
110 if (rtaInfo->rta_len < (RTA_LENGTH(IPV6_LENGTH_BYTES))) {
111 return;
112 }
113 if (GetIpFromS6Address(RTA_DATA(rtaInfo), rtmFamily, dst, sizeof(dst)) != 0) {
114 DHCP_LOGE("inet_ntop RTA_DST failed.");
115 return;
116 }
117 break;
118 case RTA_OIF:
119 if (rtaInfo->rta_len < (RTA_LENGTH(sizeof(int32_t)))) {
120 return;
121 }
122 ifindex = *(reinterpret_cast<int32_t*>(RTA_DATA(rtaInfo)));
123 break;
124 default:
125 break;
126 }
127 }
128 onIpv6RouteAddEvent(gateway, dst, ifindex);
129 }
130
parseNewneighMessage(void * msg)131 void DhcpIpv6Client::parseNewneighMessage(void* msg)
132 {
133 if (!msg) {
134 return;
135 }
136 struct nlmsghdr *nlh = (struct nlmsghdr*)msg;
137 if (nlh->nlmsg_len < sizeof(struct ndmsg) + sizeof(struct nlmsghdr)) {
138 return;
139 }
140 struct ndmsg *ndm = (struct ndmsg *)NLMSG_DATA(nlh);
141 if (!ndm) {
142 return;
143 }
144 if (ndm->ndm_family != KERNEL_SOCKET_IFA_FAMILY ||
145 ndm->ndm_state != NUD_REACHABLE) {
146 return;
147 }
148 struct rtattr *rta = RTM_RTA(ndm);
149 int rtl = static_cast<int>(RTM_PAYLOAD(nlh));
150 while (RTA_OK(rta, rtl)) {
151 if (rta->rta_type == NDA_DST) {
152 if (rta->rta_len < (RTA_LENGTH(IPV6_LENGTH_BYTES))) {
153 return;
154 }
155 struct in6_addr *addr = (struct in6_addr *)RTA_DATA(rta);
156 char gateway[DHCP_INET6_ADDRSTRLEN] = {0};
157 char dst[DHCP_INET6_ADDRSTRLEN] = {0};
158 if (GetIpFromS6Address(addr, ndm->ndm_family, gateway,
159 DHCP_INET6_ADDRSTRLEN) != 0) {
160 DHCP_LOGE("inet_ntop routeAddr failed.");
161 return;
162 }
163 onIpv6RouteAddEvent(gateway, dst, ndm->ndm_ifindex);
164 DHCP_LOGD("getIpv6RouteAddr: %{public}s", gateway);
165 break;
166 }
167 rta = RTA_NEXT(rta, rtl);
168 }
169 }
170
fillRouteData(char * buff,int & len)171 void DhcpIpv6Client::fillRouteData(char* buff, int &len)
172 {
173 if (!buff) {
174 return;
175 }
176 struct nlmsghdr *nlh = (struct nlmsghdr *)buff;
177 nlh->nlmsg_len = NLMSG_SPACE(static_cast<unsigned int>(sizeof(struct ndmsg)));
178 nlh->nlmsg_type = RTM_GETNEIGH;
179 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
180 nlh->nlmsg_seq = 1;
181 nlh->nlmsg_pid = static_cast<unsigned int>(getpid());
182 len = nlh->nlmsg_len;
183 }
184
handleKernelEvent(const uint8_t * data,int len)185 void DhcpIpv6Client::handleKernelEvent(const uint8_t* data, int len)
186 {
187 if (!data || len < static_cast<int32_t>(sizeof(struct nlmsghdr))) {
188 DHCP_LOGE("handleKernelEvent failed, data invalid, len:%{public}d.", len);
189 return;
190 }
191 struct nlmsghdr *nlh = (struct nlmsghdr*)data;
192 while (nlh && NLMSG_OK(nlh, len) && nlh->nlmsg_type != NLMSG_DONE) {
193 DHCP_LOGD("handleKernelEvent nlmsg_type:%{public}d.", nlh->nlmsg_type);
194 if (nlh->nlmsg_type == RTM_NEWADDR) {
195 ParseAddrMessage((void *)nlh);
196 } else if (nlh->nlmsg_type == RTM_NEWNDUSEROPT) {
197 if (nlh->nlmsg_len < (sizeof(struct nlmsghdr) + sizeof(struct nduseroptmsg))) {
198 DHCP_LOGE("handleKernelEvent nlmsg_len:%{public}u is invalid.", nlh->nlmsg_len);
199 return;
200 }
201 struct nduseroptmsg* ndmsg = (struct nduseroptmsg*)NLMSG_DATA(nlh);
202 size_t optsize = NLMSG_PAYLOAD(nlh, sizeof(*ndmsg));
203 parseNdUserOptMessage((void*)ndmsg, optsize);
204 } else if (nlh->nlmsg_type == RTM_NEWROUTE) {
205 parseNDRouteMessage((void*)nlh);
206 } else if (nlh->nlmsg_type == RTM_NEWNEIGH) {
207 parseNewneighMessage((void*)nlh);
208 }
209 nlh = NLMSG_NEXT(nlh, len);
210 }
211 }
212
ParseAddrMessage(void * msg)213 void DhcpIpv6Client::ParseAddrMessage(void *msg)
214 {
215 if (msg == nullptr) {
216 DHCP_LOGE("ParseAddrMessage msg is nullptr.");
217 return;
218 }
219
220 struct nlmsghdr *nlh = (struct nlmsghdr*)msg;
221 if (nlh->nlmsg_len < (sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg))) {
222 DHCP_LOGE("ParseAddrMessage nlmsg_len:%{public}u is invalid.", nlh->nlmsg_len);
223 return;
224 }
225
226 struct ifaddrmsg *ifa = (struct ifaddrmsg*)NLMSG_DATA(nlh);
227 struct rtattr *rth = IFA_RTA(ifa);
228 int rtl = static_cast<int>(IFA_PAYLOAD(nlh));
229 while (rtl && RTA_OK(rth, rtl)) {
230 if (rth->rta_type != IFA_ADDRESS || ifa->ifa_family != KERNEL_SOCKET_IFA_FAMILY) {
231 rth = RTA_NEXT(rth, rtl);
232 continue;
233 }
234 if (rth->rta_len < RTA_LENGTH(IPV6_LENGTH_BYTES)) {
235 DHCP_LOGI("handleKernelEvent rta_len:%{public}u is invalid.", rth->rta_len);
236 rth = RTA_NEXT(rth, rtl);
237 continue;
238 }
239 onIpv6AddressAddEvent(RTA_DATA(rth), ifa->ifa_prefixlen, ifa->ifa_index);
240 rth = RTA_NEXT(rth, rtl);
241 }
242 }
243 } // namespace DHCP
244 } // namespace OHOS
245