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