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 30#include "netnative_log_wrapper.h" 31#include "securec.h" 32 33#include "netlink_socket.h" 34namespace OHOS { 35namespace nmd { 36int32_t SendNetlinkMsgToKernel(struct nlmsghdr *msg, uint32_t table) 37{ 38 if (msg == nullptr) { 39 NETNATIVE_LOGE("[NetlinkSocket] msg can not be null "); 40 return -1; 41 } 42 int32_t kernelSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 43 if (kernelSocket == -1) { 44 NETNATIVE_LOGE("[NetlinkSocket] create socket failed: %{public}d", errno); 45 return -1; 46 } 47 struct iovec ioVector; 48 ioVector.iov_base = msg; 49 ioVector.iov_len = msg->nlmsg_len; 50 51 struct msghdr msgHeader; 52 (void)memset_s(&msgHeader, sizeof(msgHeader), 0, sizeof(msgHeader)); 53 54 struct sockaddr_nl kernel; 55 (void)memset_s(&kernel, sizeof(kernel), 0, sizeof(kernel)); 56 kernel.nl_family = AF_NETLINK; 57 kernel.nl_groups = 0; 58 59 msgHeader.msg_name = &kernel; 60 msgHeader.msg_namelen = sizeof(kernel); 61 msgHeader.msg_iov = &ioVector; 62 msgHeader.msg_iovlen = 1; 63 64 ssize_t msgState = sendmsg(kernelSocket, &msgHeader, 0); 65 if (msgState == -1) { 66 NETNATIVE_LOGE("[NetlinkSocket] msg can not be null "); 67 close(kernelSocket); 68 return -1; 69 } else if (msgState == 0) { 70 NETNATIVE_LOGE("[NetlinkSocket] 0 bytes send."); 71 close(kernelSocket); 72 return -1; 73 } 74 NETNATIVE_LOG_D("[NetlinkSocket] msgState is %{public}zd", msgState); 75 if (msg->nlmsg_flags & NLM_F_DUMP) { 76 msgState = GetInfoFromKernel(kernelSocket, msg->nlmsg_type, table); 77 } 78 if (msgState != 0) { 79 NETNATIVE_LOGE("netlink read socket[%{public}d] failed, msgState=%{public}zd", kernelSocket, msgState); 80 } 81 close(kernelSocket); 82 return msgState; 83} 84 85int32_t ClearRouteInfo(uint16_t clearThing, uint32_t table) 86{ 87 if (clearThing != RTM_GETROUTE && clearThing != RTM_GETRULE) { 88 NETNATIVE_LOGE("ClearRouteInfo %{public}d type error", clearThing); 89 return -1; 90 } 91 // Request the kernel to send a list of all routes or rules. 92 std::unique_ptr<char[]> msghdrBuf = std::make_unique<char[]>(NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN)); 93 struct nlmsghdr *msghdr = reinterpret_cast<struct nlmsghdr *>(msghdrBuf.get()); 94 errno_t result = memset_s(msghdr, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN), 0, NLMSG_SPACE(NETLINKMESSAGE_MAX_LEN)); 95 if (result != 0) { 96 NETNATIVE_LOGE("[NetlinkMessage]: memset result %{public}d", result); 97 } 98 rtmsg msg; 99 msg.rtm_family = AF_INET; 100 int32_t copeResult = memcpy_s(NLMSG_DATA(msghdr), sizeof(struct rtmsg), &msg, sizeof(struct rtmsg)); 101 if (copeResult != 0) { 102 NETNATIVE_LOGE("[AddRoute]: string copy failed result %{public}d", copeResult); 103 } 104 msghdr->nlmsg_len = static_cast<uint32_t>(NLMSG_LENGTH(sizeof(struct rtmsg))); 105 msghdr->nlmsg_type = clearThing; 106 msghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 107 return SendNetlinkMsgToKernel(msghdr); 108} 109 110int32_t GetInfoFromKernel(int32_t sock, uint16_t clearThing, uint32_t table) 111{ 112 char readBuffer[KERNEL_BUFFER_SIZE] = {0}; 113 // Read the information returned by the kernel through the socket. 114 ssize_t readedInfos = read(sock, readBuffer, sizeof(readBuffer)); 115 if (readedInfos < 0) { 116 return -errno; 117 } 118 while (readedInfos > 0) { 119 uint32_t readLength = static_cast<uint32_t>(readedInfos); 120 // Traverse and read the information returned by the kernel for item by item processing. 121 for (nlmsghdr *nlmsgHeader = reinterpret_cast<nlmsghdr *>(readBuffer); NLMSG_OK(nlmsgHeader, readLength); 122 nlmsgHeader = NLMSG_NEXT(nlmsgHeader, readLength)) { 123 if (nlmsgHeader->nlmsg_type == NLMSG_ERROR) { 124 nlmsgerr *err = reinterpret_cast<nlmsgerr *>(NLMSG_DATA(nlmsgHeader)); 125 NETNATIVE_LOG_D("netlink read socket[%{public}d] failed error = %{public}d", sock, err->error); 126 return err->error; 127 } else if (nlmsgHeader->nlmsg_type == NLMSG_DONE) { 128 return 0; 129 } else { 130 DealInfoFromKernel(nlmsgHeader, clearThing, table); 131 } 132 } 133 readedInfos = read(sock, readBuffer, sizeof(readBuffer)); 134 if (readedInfos < 0) { 135 return -errno; 136 } 137 } 138 return 0; 139} 140 141void DealInfoFromKernel(nlmsghdr *nlmsgHeader, uint16_t clearThing, uint32_t table) 142{ 143 if (nlmsgHeader == nullptr) { 144 NETNATIVE_LOGE("nlmsgHeader is nullptr"); 145 return; 146 } 147 struct nlmsghdr *msg = nlmsgHeader; 148 msg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 149 if (clearThing == RTM_GETRULE) { 150 msg->nlmsg_type = RTM_DELRULE; 151 if (GetRouteProperty(nlmsgHeader, FRA_PRIORITY) != static_cast<int32_t>(LOCAL_PRIORITY)) { 152 return; 153 } 154 } else if (clearThing == RTM_GETROUTE) { 155 msg->nlmsg_type = RTM_DELROUTE; 156 if (GetRouteProperty(nlmsgHeader, RTA_TABLE) != static_cast<int32_t>(table)) { 157 return; 158 } 159 } 160 SendNetlinkMsgToKernel(msg); 161} 162 163int32_t GetRouteProperty(const nlmsghdr *nlmsgHeader, int32_t property) 164{ 165 if (nlmsgHeader == nullptr) { 166 NETNATIVE_LOGE("nlmsgHeader is nullptr"); 167 return -1; 168 } 169 uint32_t rtaLength = RTM_PAYLOAD(nlmsgHeader); 170 rtmsg *infoMsg = reinterpret_cast<rtmsg *>(NLMSG_DATA(nlmsgHeader)); 171 for (rtattr *infoRta = reinterpret_cast<rtattr *> RTM_RTA(infoMsg); RTA_OK(infoRta, rtaLength); 172 infoRta = RTA_NEXT(infoRta, rtaLength)) { 173 if (infoRta->rta_type == property) { 174 return *(reinterpret_cast<uint32_t *>(RTA_DATA(infoRta))); 175 } 176 } 177 return 0; 178} 179} // namespace nmd 180} // namespace OHOS 181