• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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.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 
16 #include <arpa/inet.h>
17 #include <asm/types.h>
18 #include <cstdlib>
19 #include <cstring>
20 #include <iostream>
21 #include <linux/fib_rules.h>
22 #include <linux/netlink.h>
23 #include <linux/rtnetlink.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/uio.h>
28 #include <unistd.h>
29 #ifdef SUPPORT_SYSVPN
30 #include <net/if.h>
31 #endif
32 #include "netnative_log_wrapper.h"
33 #include "securec.h"
34 
35 #include "netlink_socket.h"
36 namespace OHOS {
37 namespace nmd {
38 #ifdef SUPPORT_SYSVPN
39 constexpr const char* XFRM_TYPE_NAME = "xfrm";
40 #endif
41 
SendNetlinkMsgToKernel(struct nlmsghdr * msg,uint32_t table)42 int32_t SendNetlinkMsgToKernel(struct nlmsghdr *msg, uint32_t table)
43 {
44     if (msg == nullptr) {
45         NETNATIVE_LOGE("[NetlinkSocket] msg can not be null ");
46         return -1;
47     }
48     int32_t kernelSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
49     if (kernelSocket == -1) {
50         NETNATIVE_LOGE("[NetlinkSocket] create socket failed: %{public}d", errno);
51         return -1;
52     }
53     struct iovec ioVector;
54     ioVector.iov_base = msg;
55     ioVector.iov_len = msg->nlmsg_len;
56 
57     struct msghdr msgHeader;
58     (void)memset_s(&msgHeader, sizeof(msgHeader), 0, sizeof(msgHeader));
59 
60     struct sockaddr_nl kernel;
61     (void)memset_s(&kernel, sizeof(kernel), 0, sizeof(kernel));
62     kernel.nl_family = AF_NETLINK;
63     kernel.nl_groups = 0;
64 
65     msgHeader.msg_name = &kernel;
66     msgHeader.msg_namelen = sizeof(kernel);
67     msgHeader.msg_iov = &ioVector;
68     msgHeader.msg_iovlen = 1;
69 
70     ssize_t msgState = sendmsg(kernelSocket, &msgHeader, 0);
71     if (msgState == -1) {
72         NETNATIVE_LOGE("[NetlinkSocket] msg can not be null ");
73         close(kernelSocket);
74         return -1;
75     } else if (msgState == 0) {
76         NETNATIVE_LOGE("[NetlinkSocket] 0 bytes send.");
77         close(kernelSocket);
78         return -1;
79     }
80     NETNATIVE_LOG_D("[NetlinkSocket] msgState is %{public}zd", msgState);
81     if (msg->nlmsg_flags & NLM_F_DUMP) {
82         msgState = GetInfoFromKernel(kernelSocket, msg->nlmsg_type, table);
83     }
84     if (msgState != 0) {
85         NETNATIVE_LOGE("netlink read socket[%{public}d] failed, msgState=%{public}zd", kernelSocket, msgState);
86     }
87     close(kernelSocket);
88     return msgState;
89 }
90 
91 #ifdef SUPPORT_SYSVPN
AddAttribute(struct nlmsghdr * msghdr,int type,const void * data,size_t len)92 static void AddAttribute(struct nlmsghdr *msghdr, int type, const void *data, size_t len)
93 {
94     struct rtattr *attr = reinterpret_cast<struct rtattr*>(
95         reinterpret_cast<char*>(msghdr) + NLMSG_ALIGN(msghdr->nlmsg_len));
96     attr->rta_type = type;
97     attr->rta_len = RTA_LENGTH(len);
98     if (memcpy_s(RTA_DATA(attr), NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN), data, len) != 0) {
99         NETNATIVE_LOGE("[AddRoute]: string copy failed");
100     }
101     msghdr->nlmsg_len = NLMSG_ALIGN(msghdr->nlmsg_len) + RTA_ALIGN(attr->rta_len);
102 }
103 
AddNestedStart(struct nlmsghdr * msghdr,int type)104 static struct rtattr *AddNestedStart(struct nlmsghdr *msghdr, int type)
105 {
106     struct rtattr *nested = reinterpret_cast<struct rtattr*>(
107         reinterpret_cast<char*>(msghdr) + NLMSG_ALIGN(msghdr->nlmsg_len));
108     nested->rta_type = type;
109     nested->rta_len = RTA_LENGTH(0);
110     msghdr->nlmsg_len = NLMSG_ALIGN(msghdr->nlmsg_len) + RTA_ALIGN(nested->rta_len);
111     return nested;
112 }
113 
AddNestedEnd(struct nlmsghdr * msghdr,struct rtattr * nested)114 static void AddNestedEnd(struct nlmsghdr *msghdr, struct rtattr *nested)
115 {
116     nested->rta_len = reinterpret_cast<char*>(msghdr) + NLMSG_ALIGN(msghdr->nlmsg_len) -
117                        reinterpret_cast<char*>(nested);
118 }
119 
CreateVpnIfByNetlink(const char * name,uint32_t ifNameId,const char * phys,uint32_t mtu=0)120 int32_t CreateVpnIfByNetlink(const char *name, uint32_t ifNameId, const char *phys, uint32_t mtu = 0)
121 {
122     NETNATIVE_LOGI("CreateVpnIfByNetlink %{public}s, %{public}d, %{public}d", name, ifNameId, mtu);
123     uint32_t ifindex = 0;
124     if (phys) {
125         ifindex = if_nametoindex(phys);
126         if (!ifindex) {
127             NETNATIVE_LOGE("physical interface '%{public}s' not found", phys);
128             return -1;
129         }
130     }
131     std::unique_ptr<char[]> msghdrBuf = std::make_unique<char[]>(NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN));
132     struct nlmsghdr *msghdr = reinterpret_cast<struct nlmsghdr *>(msghdrBuf.get());
133     errno_t result = memset_s(msghdr, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN), 0, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN));
134     if (result != 0) {
135         NETNATIVE_LOGE("[NetlinkMessage]: memset result %{public}d", result);
136     }
137     rtmsg msg;
138     msg.rtm_family = AF_INET;
139     int32_t copeResult = memcpy_s(NLMSG_DATA(msghdr), sizeof(struct rtmsg), &msg, sizeof(struct rtmsg));
140     if (copeResult != 0) {
141         NETNATIVE_LOGE("[AddRoute]: string copy failed result %{public}d", copeResult);
142     }
143     msghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
144     msghdr->nlmsg_type = RTM_NEWLINK;
145     msghdr->nlmsg_len = static_cast<uint32_t>(NLMSG_LENGTH(sizeof(struct ifinfomsg)));
146 
147     AddAttribute(msghdr, IFLA_IFNAME, name, strlen(name) + 1);
148 
149     if (mtu > 0) {
150         AddAttribute(msghdr, IFLA_MTU, &mtu, sizeof(mtu));
151     }
152     struct rtattr *linkinfo = AddNestedStart(msghdr, IFLA_LINKINFO);
153     AddAttribute(msghdr, IFLA_INFO_KIND, XFRM_TYPE_NAME, strlen(XFRM_TYPE_NAME) + 1);
154     struct rtattr *info_data = AddNestedStart(msghdr, IFLA_INFO_DATA);
155     AddAttribute(msghdr, IFLA_XFRM_IF_ID, &ifNameId, sizeof(ifNameId));
156     AddAttribute(msghdr, IFLA_XFRM_LINK, &ifindex, sizeof(ifindex));
157 
158     AddNestedEnd(msghdr, info_data);
159     AddNestedEnd(msghdr, linkinfo);
160     return SendNetlinkMsgToKernel(msghdr);
161 }
162 
DeleteVpnIfByNetlink(const char * name)163 int32_t DeleteVpnIfByNetlink(const char *name)
164 {
165     std::unique_ptr<char[]> msghdrBuf = std::make_unique<char[]>(NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN));
166     struct nlmsghdr *msghdr = reinterpret_cast<struct nlmsghdr *>(msghdrBuf.get());
167     errno_t result = memset_s(msghdr, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN), 0, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN));
168     if (result != 0) {
169         NETNATIVE_LOGE("[NetlinkMessage]: memset result %{public}d", result);
170     }
171     rtmsg msg;
172     msg.rtm_family = AF_INET;
173     int32_t copeResult = memcpy_s(NLMSG_DATA(msghdr), sizeof(struct rtmsg), &msg, sizeof(struct rtmsg));
174     if (copeResult != 0) {
175         NETNATIVE_LOGE("[AddRoute]: string copy failed result %{public}d", copeResult);
176     }
177     msghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
178     msghdr->nlmsg_type = RTM_DELLINK;
179     msghdr->nlmsg_len = static_cast<uint32_t>(NLMSG_LENGTH(sizeof(struct ifinfomsg)));
180     AddAttribute(msghdr, IFLA_IFNAME, name, strlen(name) + 1);
181     return SendNetlinkMsgToKernel(msghdr);
182 }
183 #endif
184 
ClearRouteInfo(uint16_t clearThing,uint32_t table)185 int32_t ClearRouteInfo(uint16_t clearThing, uint32_t table)
186 {
187     if (clearThing != RTM_GETROUTE && clearThing != RTM_GETRULE) {
188         NETNATIVE_LOGE("ClearRouteInfo %{public}d type error", clearThing);
189         return -1;
190     }
191     // Request the kernel to send a list of all routes or rules.
192     std::unique_ptr<char[]> msghdrBuf = std::make_unique<char[]>(NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN));
193     struct nlmsghdr *msghdr = reinterpret_cast<struct nlmsghdr *>(msghdrBuf.get());
194     errno_t result = memset_s(msghdr, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN), 0, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN));
195     if (result != 0) {
196         NETNATIVE_LOGE("[NetlinkMessage]: memset result %{public}d", result);
197     }
198     rtmsg msg;
199     msg.rtm_family = AF_INET;
200     int32_t copeResult = memcpy_s(NLMSG_DATA(msghdr), sizeof(struct rtmsg), &msg, sizeof(struct rtmsg));
201     if (copeResult != 0) {
202         NETNATIVE_LOGE("[AddRoute]: string copy failed result %{public}d", copeResult);
203     }
204     msghdr->nlmsg_len = static_cast<uint32_t>(NLMSG_LENGTH(sizeof(struct rtmsg)));
205     msghdr->nlmsg_type = clearThing;
206     msghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
207     return SendNetlinkMsgToKernel(msghdr);
208 }
209 
GetInfoFromKernel(int32_t sock,uint16_t clearThing,uint32_t table)210 int32_t GetInfoFromKernel(int32_t sock, uint16_t clearThing, uint32_t table)
211 {
212     char readBuffer[KERNEL_BUFFER_SIZE] = {0};
213     // Read the information returned by the kernel through the socket.
214     ssize_t readedInfos = read(sock, readBuffer, sizeof(readBuffer));
215     if (readedInfos < 0) {
216         return -errno;
217     }
218     while (readedInfos > 0) {
219         uint32_t readLength = static_cast<uint32_t>(readedInfos);
220         // Traverse and read the information returned by the kernel for item by item processing.
221         for (nlmsghdr *nlmsgHeader = reinterpret_cast<nlmsghdr *>(readBuffer); NLMSG_OK(nlmsgHeader, readLength);
222              nlmsgHeader = NLMSG_NEXT(nlmsgHeader, readLength)) {
223             if (nlmsgHeader->nlmsg_type == NLMSG_ERROR) {
224                 nlmsgerr *err = reinterpret_cast<nlmsgerr *>(NLMSG_DATA(nlmsgHeader));
225                 NETNATIVE_LOG_D("netlink read socket[%{public}d] failed error = %{public}d", sock, err->error);
226                 return err->error;
227             } else if (nlmsgHeader->nlmsg_type == NLMSG_DONE) {
228                 return 0;
229             } else {
230                 DealInfoFromKernel(nlmsgHeader, clearThing, table);
231             }
232         }
233         readedInfos = read(sock, readBuffer, sizeof(readBuffer));
234         if (readedInfos < 0) {
235             return -errno;
236         }
237     }
238     return 0;
239 }
240 
DealInfoFromKernel(nlmsghdr * nlmsgHeader,uint16_t clearThing,uint32_t table)241 void DealInfoFromKernel(nlmsghdr *nlmsgHeader, uint16_t clearThing, uint32_t table)
242 {
243     if (nlmsgHeader == nullptr) {
244         NETNATIVE_LOGE("nlmsgHeader is nullptr");
245         return;
246     }
247     struct nlmsghdr *msg = nlmsgHeader;
248     msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
249     if (clearThing == RTM_GETRULE) {
250         msg->nlmsg_type = RTM_DELRULE;
251         if (GetRouteProperty(nlmsgHeader, FRA_PRIORITY) != static_cast<int32_t>(LOCAL_PRIORITY)) {
252             return;
253         }
254     } else if (clearThing == RTM_GETROUTE) {
255         msg->nlmsg_type = RTM_DELROUTE;
256         if (GetRouteProperty(nlmsgHeader, RTA_TABLE) != static_cast<int32_t>(table)) {
257             return;
258         }
259     }
260     SendNetlinkMsgToKernel(msg);
261 }
262 
GetRouteProperty(const nlmsghdr * nlmsgHeader,int32_t property)263 int32_t GetRouteProperty(const nlmsghdr *nlmsgHeader, int32_t property)
264 {
265     if (nlmsgHeader == nullptr) {
266         NETNATIVE_LOGE("nlmsgHeader is nullptr");
267         return -1;
268     }
269     uint32_t rtaLength = RTM_PAYLOAD(nlmsgHeader);
270     rtmsg *infoMsg = reinterpret_cast<rtmsg *>(NLMSG_DATA(nlmsgHeader));
271     for (rtattr *infoRta = reinterpret_cast<rtattr *> RTM_RTA(infoMsg); RTA_OK(infoRta, rtaLength);
272          infoRta = RTA_NEXT(infoRta, rtaLength)) {
273         if (infoRta->rta_type == property) {
274             return *(reinterpret_cast<uint32_t *>(RTA_DATA(infoRta)));
275         }
276     }
277     return 0;
278 }
279 } // namespace nmd
280 } // namespace OHOS
281