• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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