• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "securec.h"
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("invalid 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("invalid 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("invalid 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("invalid msglen:%{public}d", hdrMsg->nlmsg_len);
84         return;
85     }
86     // Ignore static routes we've set up ourselves.
87     if ((rtMsg->rtm_protocol != RTPROT_KERNEL && rtMsg->rtm_protocol != RTPROT_RA) ||
88      // We're only interested in global unicast routes.
89         (rtMsg->rtm_scope != RT_SCOPE_UNIVERSE) || (rtMsg->rtm_type != RTN_UNICAST) ||
90         // We don't support source routing.
91         // Cloned routes aren't real routes.
92         (rtMsg->rtm_src_len != 0) || (rtMsg->rtm_flags & RTM_F_CLONED)) {
93         DHCP_LOGE("invalid arg");
94         return;
95     }
96     char dst[DHCP_INET6_ADDRSTRLEN] = {0};
97     char gateway[DHCP_INET6_ADDRSTRLEN] = {0};
98     int32_t rtmFamily = rtMsg->rtm_family;
99     size_t size = RTM_PAYLOAD(hdrMsg);
100     int ifindex = -1;
101     rtattr *rtaInfo = NULL;
102     for (rtaInfo = RTM_RTA(rtMsg); RTA_OK(rtaInfo, (int)size); rtaInfo = RTA_NEXT(rtaInfo, size)) {
103         switch (rtaInfo->rta_type) {
104             case RTA_GATEWAY:
105                 if (rtaInfo->rta_len < (RTA_LENGTH(IPV6_LENGTH_BYTES))) {
106                     return;
107                 }
108                 if (GetIpFromS6Address(RTA_DATA(rtaInfo), rtmFamily, gateway, sizeof(gateway)) != 0) {
109                     DHCP_LOGE("inet_ntop RTA_GATEWAY failed.");
110                     return;
111                 }
112                 break;
113             case RTA_DST:
114                 if (rtaInfo->rta_len < (RTA_LENGTH(IPV6_LENGTH_BYTES))) {
115                     return;
116                 }
117                 if (GetIpFromS6Address(RTA_DATA(rtaInfo), rtmFamily, dst, sizeof(dst)) != 0) {
118                     DHCP_LOGE("inet_ntop RTA_DST failed.");
119                     return;
120                 }
121                 break;
122             case RTA_OIF:
123                 if (rtaInfo->rta_len < (RTA_LENGTH(sizeof(int32_t)))) {
124                     return;
125                 }
126                 ifindex = *(reinterpret_cast<int32_t*>(RTA_DATA(rtaInfo)));
127                 break;
128             default:
129                 break;
130         }
131     }
132     OnIpv6RouteUpdateEvent(gateway, dst, ifindex, hdrMsg->nlmsg_type == RTM_NEWROUTE);
133 }
134 
parseNewneighMessage(void * msg)135 void DhcpIpv6Client::parseNewneighMessage(void* msg)
136 {
137     if (!msg) {
138         return;
139     }
140     struct nlmsghdr *nlh = (struct nlmsghdr*)msg;
141     if (nlh->nlmsg_len < sizeof(struct ndmsg) + sizeof(struct nlmsghdr)) {
142         return;
143     }
144     struct ndmsg *ndm = (struct ndmsg *)NLMSG_DATA(nlh);
145     if (!ndm) {
146         return;
147     }
148     if (ndm->ndm_family != KERNEL_SOCKET_IFA_FAMILY ||
149         ndm->ndm_state != NUD_REACHABLE) {
150         return;
151     }
152     struct rtattr *rta = RTM_RTA(ndm);
153     int rtl = static_cast<int>(RTM_PAYLOAD(nlh));
154     while (RTA_OK(rta, rtl)) {
155         if (rta->rta_type == NDA_DST) {
156             if (rta->rta_len < (RTA_LENGTH(IPV6_LENGTH_BYTES))) {
157                 return;
158             }
159             struct in6_addr *addr = (struct in6_addr *)RTA_DATA(rta);
160             char gateway[DHCP_INET6_ADDRSTRLEN] = {0};
161             if (GetIpFromS6Address(addr, ndm->ndm_family, gateway,
162                 DHCP_INET6_ADDRSTRLEN) != 0) {
163                 DHCP_LOGE("inet_ntop routeAddr failed.");
164                 return;
165             }
166             DHCP_LOGD("parseNewneighMessage: %{public}s", gateway);
167             break;
168         }
169         rta = RTA_NEXT(rta, rtl);
170     }
171 }
172 
fillRouteData(char * buff,int & len)173 void DhcpIpv6Client::fillRouteData(char* buff, int &len)
174 {
175     if (!buff) {
176         return;
177     }
178     struct nlmsghdr *nlh = (struct nlmsghdr *)buff;
179     nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct ndmsg));
180     nlh->nlmsg_type = RTM_GETNEIGH;
181     nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
182     nlh->nlmsg_seq = 1;
183     nlh->nlmsg_pid = static_cast<unsigned int>(getpid());
184     len = nlh->nlmsg_len;
185 }
186 
handleKernelEvent(const uint8_t * data,int len)187 void DhcpIpv6Client::handleKernelEvent(const uint8_t* data, int len)
188 {
189     if (!data || len < static_cast<int32_t>(sizeof(struct nlmsghdr))) {
190         DHCP_LOGE("handleKernelEvent failed, data invalid, len:%{public}d.", len);
191         return;
192     }
193     struct nlmsghdr *nlh = (struct nlmsghdr*)data;
194     while (nlh && NLMSG_OK(nlh, len) && nlh->nlmsg_type != NLMSG_DONE) {
195         DHCP_LOGD("handleKernelEvent nlmsg_type:%{public}d.", nlh->nlmsg_type);
196         if (nlh->nlmsg_type == RTM_NEWADDR) {
197             DHCP_LOGI("handleKernelEvent nlmsg_type: RTM_NEWADDR.");
198             ParseAddrMessage((void *)nlh);
199         } else if (nlh->nlmsg_type == RTM_DELADDR) {
200             DHCP_LOGI("handleKernelEvent nlmsg_type: RTM_DELADDR");
201             ParseAddrMessage((void *)nlh);
202         } else if (nlh->nlmsg_type == RTM_NEWNDUSEROPT) {
203             DHCP_LOGI("handleKernelEvent nlmsg_type: RTM_NEWNDUSEROPT.");
204             if (nlh->nlmsg_len < (sizeof(struct nlmsghdr) + sizeof(struct nduseroptmsg))) {
205                 DHCP_LOGE("handleKernelEvent nlmsg_len:%{public}u is invalid.", nlh->nlmsg_len);
206                 return;
207             }
208             struct nduseroptmsg* ndmsg = (struct nduseroptmsg*)NLMSG_DATA(nlh);
209             size_t optsize = NLMSG_PAYLOAD(nlh, sizeof(*ndmsg));
210             parseNdUserOptMessage((void*)ndmsg, optsize);
211         } else if (nlh->nlmsg_type == RTM_NEWROUTE) {
212             DHCP_LOGI("handleKernelEvent nlmsg_type: RTM_NEWROUTE.");
213             parseNDRouteMessage((void*)nlh);
214         } else if (nlh->nlmsg_type == RTM_DELROUTE) {
215             DHCP_LOGI("handleKernelEvent nlmsg_type: RTM_DELROUTE");
216             parseNDRouteMessage((void*)nlh);
217         } else if (nlh->nlmsg_type == RTM_NEWNEIGH) {
218             parseNewneighMessage((void*)nlh);
219         }
220         nlh = NLMSG_NEXT(nlh, len);
221     }
222 }
ParseAddrMessage(void * msg)223 void DhcpIpv6Client::ParseAddrMessage(void *msg)
224 {
225     if (msg == nullptr) {
226         DHCP_LOGE("ParseAddrMessage msg is nullptr.");
227         return;
228     }
229 
230     struct nlmsghdr *hdrMsg = (struct nlmsghdr*)msg;
231     if (hdrMsg->nlmsg_len < (sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg))) {
232         DHCP_LOGE("ParseAddrMessage nlmsg_len:%{public}u is invalid.", hdrMsg->nlmsg_len);
233         return;
234     }
235 
236     int32_t nlType = hdrMsg->nlmsg_type;
237     if (nlType != RTM_NEWADDR && nlType != RTM_DELADDR) {
238         DHCP_LOGE("ParseAddrMessage on incorrect message nlType 0x%{public}x\n", nlType);
239         return;
240     }
241     ifaddrmsg *addrMsg = reinterpret_cast<ifaddrmsg *>(NLMSG_DATA(hdrMsg));
242     char addresses[DHCP_INET6_ADDRSTRLEN];
243     memset_s(addresses, DHCP_INET6_ADDRSTRLEN, 0, DHCP_INET6_ADDRSTRLEN);
244     int scope = IPV6_ADDR_LINKLOCAL;
245     int32_t len = IFA_PAYLOAD(hdrMsg);
246     for (rtattr *rtAttr = IFA_RTA(addrMsg); RTA_OK(rtAttr, len); rtAttr = RTA_NEXT(rtAttr, len)) {
247         if (rtAttr == nullptr) {
248             DHCP_LOGE("Invalid ifaddrmsg\n");
249             return;
250         }
251         if (rtAttr->rta_type == IFA_ADDRESS) {
252             if (rtAttr->rta_len < RTA_LENGTH(IPV6_LENGTH_BYTES)) {
253                 DHCP_LOGI("handleKernelEvent rta_len:%{public}u is invalid.", rtAttr->rta_len);
254                 continue;
255             }
256             if (GetIpFromS6Address(RTA_DATA(rtAttr), addrMsg->ifa_family, addresses, DHCP_INET6_ADDRSTRLEN) != 0) {
257                 DHCP_LOGE("inet_ntop addresses failed.");
258                 return;
259             }
260             scope = GetAddrScope(RTA_DATA(rtAttr));
261             DHCP_LOGI("ParseAddrMessage %{private}s\n", addresses);
262         }
263     }
264     if (addresses[0] == '\0') {
265         return;
266     }
267     OnIpv6AddressUpdateEvent(addresses, DHCP_INET6_ADDRSTRLEN, addrMsg->ifa_prefixlen, addrMsg->ifa_index,
268         scope, nlType == RTM_NEWADDR);
269     return;
270 }
271 }  // namespace DHCP
272 }  // namespace OHOS
273