1 /*
2 * Copyright (c) 2021 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 "route_controller.h"
17 #include <cstring>
18 #include <iostream>
19 #include <map>
20 #include <mutex>
21 #include <netlink_socket.h>
22 #include <sstream>
23 #include <unistd.h>
24 #include <arpa/inet.h>
25 #include <net/if.h>
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
28 #include <sys/uio.h>
29 #include <linux/fib_rules.h>
30 #include <linux/netlink.h>
31 #include <linux/rtnetlink.h>
32 #include "securec.h"
33 #include "bitcast.h"
34 #include "netlink_manager.h"
35 #include "netlink_msg.h"
36 #include "netnative_log_wrapper.h"
37
38 namespace OHOS {
39 namespace nmd {
40 namespace {
41 constexpr uint32_t OUTPUT_MAX = 128;
42 constexpr uint32_t BIT_32_LEN = 32;
43 constexpr uint32_t BIT_MAX_LEN = 255;
44 constexpr uint32_t DECIMAL_DIGITAL = 10;
45 constexpr uint32_t BYTE_ALIGNMENT = 8;
46 constexpr uint32_t THOUSAND_LEN = 1000;
47
48 constexpr uint32_t RULE_LOCAL_NETWORK_PRI = 18000;
49 constexpr uint32_t RULE_DEFAULT_NETWORK_PRI = 19000;
50
51 constexpr uint32_t ROUTE_LOCAL_NETWORK_TABLE = 100;
52 }
53 std::map<std::string, uint32_t> RouteController::interfaceToTable;
54
RouteController()55 RouteController::RouteController()
56 {
57 int status = ModifyRule(RTM_NEWRULE, ROUTE_LOCAL_NETWORK_TABLE, FR_ACT_TO_TBL, RULE_LOCAL_NETWORK_PRI);
58 if (status < 0) {
59 NETNATIVE_LOGE("RouteController::RouteController, add rule error");
60 }
61 }
62
~RouteController()63 RouteController::~RouteController() {}
64
ModifyRule(uint32_t type,uint32_t table,uint8_t action,uint32_t priority)65 int RouteController::ModifyRule(uint32_t type, uint32_t table, uint8_t action, uint32_t priority)
66 {
67 nmd::NetlinkSocket netLinker;
68 netLinker.Create(NETLINK_ROUTE);
69 nmd::NetlinkMsg nlmsg(NLM_F_CREATE | NLM_F_EXCL, nmd::NETLINK_MAX_LEN, NetlinkManager::GetPid());
70
71 struct fib_rule_hdr msg = {0};
72
73 msg.action = action;
74 msg.family = AF_INET;
75 msg.table = RT_TABLE_UNSPEC;
76
77 nlmsg.AddRule(type, msg);
78 nlmsg.AddAttr32(FRA_PRIORITY, priority);
79 nlmsg.AddAttr32(FRA_TABLE, table);
80
81 return netLinker.SendNetlinkMsgToKernel(nlmsg.GetNetLinkMessage());
82 }
83
AddInterfaceToDefaultNetwork(const char * interfaceName,NetworkPermission permission)84 int RouteController::AddInterfaceToDefaultNetwork(const char *interfaceName, NetworkPermission permission)
85 {
86 NETNATIVE_LOGI("Entry RouteController::AddInterfaceToDefaultNetwork, %{public}s", interfaceName);
87
88 uint32_t table = GetRouteTableForInterface(interfaceName);
89 if (table == RT_TABLE_UNSPEC) {
90 return -ESRCH;
91 }
92
93 return ModifyRule(RTM_NEWRULE, table, FR_ACT_TO_TBL, RULE_DEFAULT_NETWORK_PRI);
94 }
95
RemoveInterfaceFromDefaultNetwork(const char * interfaceName,NetworkPermission permission)96 int RouteController::RemoveInterfaceFromDefaultNetwork(const char *interfaceName, NetworkPermission permission)
97 {
98 NETNATIVE_LOGI("Entry RouteController::AddInterfaceToDefaultNetwork, %{public}s", interfaceName);
99
100 uint32_t table = GetRouteTableForInterface(interfaceName);
101 if (table == RT_TABLE_UNSPEC) {
102 return -ESRCH;
103 }
104
105 return ModifyRule(RTM_DELRULE, table, FR_ACT_TO_TBL, RULE_DEFAULT_NETWORK_PRI);
106 }
107
ReadAddrGw(const char * addr,InetAddr * res)108 int nmd::RouteController::ReadAddrGw(const char *addr, InetAddr *res)
109 {
110 std::string addressString(addr);
111 if (strchr(addr, ':')) {
112 res->family = AF_INET6;
113 res->bitlen = OUTPUT_MAX;
114 } else {
115 res->family = AF_INET;
116 res->bitlen = BIT_32_LEN;
117 }
118
119 return inet_pton(res->family, addressString.c_str(), res->data);
120 }
121
ReadAddr(const char * addr,InetAddr * res)122 int nmd::RouteController::ReadAddr(const char *addr, InetAddr *res)
123 {
124 const char *slashStr = strchr(addr, '/');
125 if (slashStr == nullptr) {
126 return -EINVAL;
127 }
128
129 const char *maskLenStr = slashStr + 1;
130 if (*maskLenStr == 0) {
131 return -EINVAL;
132 }
133
134 char *endptr = nullptr;
135 unsigned templen = strtoul(maskLenStr, &endptr, DECIMAL_DIGITAL);
136 if ((endptr == nullptr) || (templen > BIT_MAX_LEN)) {
137 return -EINVAL;
138 }
139 res->prefixlen = templen;
140
141 std::string addressString(addr, slashStr - addr);
142 if (strchr(addr, ':')) {
143 res->family = AF_INET6;
144 res->bitlen = OUTPUT_MAX;
145 } else {
146 res->family = AF_INET;
147 res->bitlen = BIT_32_LEN;
148 }
149
150 return inet_pton(res->family, addressString.c_str(), res->data);
151 }
152
AddRoute(int netId,std::string interfaceName,std::string destination,std::string nextHop)153 int nmd::RouteController::AddRoute(int netId, std::string interfaceName, std::string destination, std::string nextHop)
154 {
155 NETNATIVE_LOGE("Entry nmd::RouteController::AddRoute");
156
157 nmd::NetlinkSocket netLinker;
158 netLinker.Create(NETLINK_ROUTE);
159 nmd::NetlinkMsg nlmsg(NLM_F_CREATE | NLM_F_EXCL, nmd::NETLINK_MAX_LEN, NetlinkManager::GetPid());
160
161 struct rtmsg msg;
162 (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
163
164 msg.rtm_family = AF_INET;
165 msg.rtm_dst_len = BIT_32_LEN;
166 msg.rtm_protocol = RTPROT_STATIC;
167 msg.rtm_scope = RT_SCOPE_UNIVERSE;
168 msg.rtm_type = RTN_UNICAST;
169 msg.rtm_table = RT_TABLE_UNSPEC;
170
171 unsigned int table;
172 if (netId == nmd::LOCAL_NETWORK_NETID) {
173 table = ROUTE_LOCAL_NETWORK_TABLE;
174 } else {
175 table = GetRouteTableForInterface(interfaceName.c_str());
176 if (table == RT_TABLE_UNSPEC) {
177 return -1;
178 }
179 }
180
181 InetAddr dst;
182 int readAddrResult = ReadAddr(destination.c_str(), &dst);
183 if (readAddrResult != 1) {
184 NETNATIVE_LOGE("dest parse failed:%{public}d", readAddrResult);
185 return -1;
186 }
187 msg.rtm_family = dst.family;
188 msg.rtm_dst_len = dst.prefixlen;
189 if (dst.family == AF_INET) {
190 msg.rtm_scope = RT_SCOPE_LINK;
191 } else if (dst.family == AF_INET6) {
192 msg.rtm_scope = RT_SCOPE_UNIVERSE;
193 }
194 NETNATIVE_LOGI("msg.rtm_dst_len:%{public}d, table:%{public}u", dst.prefixlen, table);
195
196 InetAddr gw;
197 readAddrResult = ReadAddrGw(nextHop.c_str(), &gw);
198 if (readAddrResult != 1) {
199 NETNATIVE_LOGE("gw parse failed:%{public}d", readAddrResult);
200 return -1;
201 }
202 if (gw.bitlen != 0) {
203 msg.rtm_scope = RT_SCOPE_UNIVERSE;
204 msg.rtm_family = gw.family;
205 }
206
207 unsigned int index = if_nametoindex(interfaceName.c_str());
208
209 nlmsg.AddRoute(RTM_NEWROUTE, msg);
210 nlmsg.AddAttr32(RTA_TABLE, table);
211 nlmsg.AddAttr(RTA_DST, (void *)dst.data, dst.bitlen / BYTE_ALIGNMENT);
212 nlmsg.AddAttr(RTA_GATEWAY, (void *)gw.data, gw.bitlen / BYTE_ALIGNMENT);
213 nlmsg.AddAttr32(RTA_OIF, index);
214
215 netLinker.SendNetlinkMsgToKernel(nlmsg.GetNetLinkMessage());
216 NETNATIVE_LOGI("nmd::RouteController::AddRoute:%{public}d %{public}s", netId, interfaceName.c_str());
217
218 return 1;
219 }
220
RemoveRoute(int netId,std::string interfaceName,std::string destination,std::string nextHop)221 int RouteController::RemoveRoute(int netId, std::string interfaceName, std::string destination, std::string nextHop)
222 {
223 nmd::NetlinkSocket netLinker;
224 netLinker.Create(NETLINK_ROUTE);
225 nmd::NetlinkMsg nlmsg(NLM_F_CREATE | NLM_F_EXCL, nmd::NETLINK_MAX_LEN, NetlinkManager::GetPid());
226
227 struct rtmsg msg;
228 (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
229
230 msg.rtm_family = AF_INET;
231 msg.rtm_dst_len = BIT_32_LEN;
232 msg.rtm_scope = RT_SCOPE_UNIVERSE;
233 msg.rtm_table = RT_TABLE_UNSPEC;
234
235 unsigned int table;
236 if (netId == nmd::LOCAL_NETWORK_NETID) {
237 table = ROUTE_LOCAL_NETWORK_TABLE;
238 } else {
239 table = GetRouteTableForInterface(interfaceName.c_str());
240 if (table == RT_TABLE_UNSPEC) {
241 return -1;
242 }
243 }
244
245 InetAddr dst;
246 int readAddrResult = ReadAddr(destination.c_str(), &dst);
247 if (readAddrResult != 1) {
248 NETNATIVE_LOGE("dest parse failed:%{public}d", readAddrResult);
249 return -1;
250 }
251 msg.rtm_family = dst.family;
252 msg.rtm_dst_len = dst.prefixlen;
253 if (dst.family == AF_INET) {
254 msg.rtm_scope = RT_SCOPE_LINK;
255 } else if (dst.family == AF_INET6) {
256 msg.rtm_scope = RT_SCOPE_UNIVERSE;
257 }
258
259 InetAddr gw;
260 readAddrResult = ReadAddrGw(nextHop.c_str(), &gw);
261 if (readAddrResult != 1) {
262 NETNATIVE_LOGE("gw parse failed:%{public}d", readAddrResult);
263 return -1;
264 }
265 if (gw.bitlen != 0) {
266 msg.rtm_scope = 0;
267 msg.rtm_family = gw.family;
268 }
269
270 unsigned int index = if_nametoindex(interfaceName.c_str());
271
272 nlmsg.AddRoute(RTM_DELROUTE, msg);
273 nlmsg.AddAttr32(RTA_TABLE, table);
274 nlmsg.AddAttr(RTA_DST, (void *)dst.data, dst.bitlen / BYTE_ALIGNMENT);
275 nlmsg.AddAttr(RTA_GATEWAY, (void *)gw.data, gw.bitlen / BYTE_ALIGNMENT);
276 nlmsg.AddAttr32(RTA_OIF, index);
277
278 netLinker.SendNetlinkMsgToKernel(nlmsg.GetNetLinkMessage());
279 NETNATIVE_LOGI("nmd::RouteController::RemoveRoute:%{public}d %{public}s", netId, interfaceName.c_str());
280
281 return 1;
282 }
283
GetRouteTableForInterface(const char * interfaceName)284 uint32_t RouteController::GetRouteTableForInterface(const char *interfaceName)
285 {
286 auto iter = interfaceToTable.find(interfaceName);
287 if (iter != interfaceToTable.end()) {
288 return iter->second;
289 }
290
291 uint32_t table = if_nametoindex(interfaceName);
292 if (table == 0) {
293 NETNATIVE_LOGE(
294 "[RouteController] cannot find interface %{public}s, error:%{public}d", interfaceName, errno);
295 return RT_TABLE_UNSPEC;
296 }
297 table += THOUSAND_LEN;
298 interfaceToTable[interfaceName] = table;
299 return table;
300 }
301 } // namespace nmd
302 } // namespace OHOS