1/*
2 * Copyright (c) 2021-2024 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_utils.h"
17
18#include <arpa/inet.h>
19
20#include "net_mgr_log_wrapper.h"
21#include "netsys_controller.h"
22
23namespace OHOS {
24namespace NetManagerStandard {
25static constexpr const char *IPV6_DEFAULT_PRIFX = "fe80::";
26static constexpr const char *IPV6_DEFAULT_GATEWAY = "::";
27static constexpr int32_t IPV6_PRIFX_LEN = 64;
28static constexpr int32_t IPV4_PRIFX_LEN = 32;
29static constexpr int32_t IPV6_UINT_LEN = 16;
30static constexpr int32_t IPV4_UINT_LEN = 4;
31static constexpr int32_t IP_PER_UINT_SIZE = 8;
32static constexpr int32_t IP_PER_UINT_MASK = 0xFF;
33
34int32_t RouteUtils::AddRoutesToLocal(const std::string &iface, const std::list<Route> &routes)
35{
36    std::list<Route>::const_iterator iter;
37    for (iter = routes.begin(); iter != routes.end(); ++iter) {
38        if (!(iter->rtnType_ == RTN_UNICAST && iter->destination_.prefixlen_ == 0)) {
39            NETMGR_LOG_D("AddRoutesToLocalNetwork: dest addr, gw addr");
40            AddRoute(LOCAL_NET_ID, *iter);
41        }
42    }
43
44    Route ipv6Rt;
45    ipv6Rt.iface_ = iface;
46    ipv6Rt.destination_.type_ = INetAddr::IPV6;
47    ipv6Rt.destination_.address_ = IPV6_DEFAULT_PRIFX;
48    ipv6Rt.destination_.prefixlen_ = IPV6_PRIFX_LEN;
49    ipv6Rt.gateway_.address_ = IPV6_DEFAULT_GATEWAY;
50    ipv6Rt.gateway_.prefixlen_ = 0;
51    ipv6Rt.hasGateway_ = false;
52    ipv6Rt.rtnType_ = RTN_UNICAST;
53    ipv6Rt.isDefaultRoute_ = false;
54    return AddRoute(LOCAL_NET_ID, ipv6Rt);
55}
56
57int32_t RouteUtils::RemoveRoutesFromLocal(const std::list<Route> &routes)
58{
59    std::list<Route>::const_iterator iter;
60    for (iter = routes.begin(); iter != routes.end(); ++iter) {
61        RemoveRoute(LOCAL_NET_ID, *iter);
62    }
63
64    return 0;
65}
66
67int32_t RouteUtils::AddRoute(int32_t netId, const Route &route)
68{
69    return ModifyRoute(ROUTE_ADD, netId, route);
70}
71
72int32_t RouteUtils::RemoveRoute(int32_t netId, const Route &route)
73{
74    return ModifyRoute(ROUTE_REMOVE, netId, route);
75}
76
77int32_t RouteUtils::UpdateRoutes(int32_t netId, const NetLinkInfo &newnl, const NetLinkInfo &oldnl)
78{
79    std::list<Route> added;
80    std::list<Route> updated;
81    std::list<Route> removed;
82    std::list<Route>::const_iterator itero;
83    std::list<Route>::const_iterator itern;
84    std::list<Route>::const_iterator iterf;
85
86    for (itero = oldnl.routeList_.begin(); itero != oldnl.routeList_.end(); ++itero) {
87        iterf = std::find(newnl.routeList_.begin(), newnl.routeList_.end(), *itero);
88        if (iterf == newnl.routeList_.end()) {
89            removed.push_back(*itero);
90        } else {
91            if (itero->rtnType_ != iterf->rtnType_ || itero->mtu_ != iterf->mtu_) {
92                updated.push_back(*iterf);
93            }
94        }
95    }
96
97    for (itern = newnl.routeList_.begin(); itern != newnl.routeList_.end(); ++itern) {
98        if (std::find(oldnl.routeList_.begin(), oldnl.routeList_.end(), *itern) == oldnl.routeList_.end()) {
99            added.push_back(*itern);
100        }
101    }
102
103    for (itern = added.begin(); itern != added.end(); ++itern) {
104        if (itern->hasGateway_) {
105            continue;
106        }
107        AddRoute(netId, *itern);
108    }
109
110    for (itern = added.begin(); itern != added.end(); ++itern) {
111        if (!itern->hasGateway_) {
112            continue;
113        }
114        AddRoute(netId, *itern);
115    }
116
117    for (itern = removed.begin(); itern != removed.end(); ++itern) {
118        RemoveRoute(netId, *itern);
119    }
120
121    return (!added.empty() || !updated.empty() || !removed.empty()) ? 1 : 0;
122}
123
124int32_t RouteUtils::ModifyRoute(routeOperateType op, int32_t netId, const Route &route)
125{
126    int32_t ret = -1;
127    std::string nextHop;
128    std::string dest;
129
130    NETMGR_LOG_D("ModifyRoute: netId[%{public}d], dest addr, gw addr", netId);
131
132    switch (route.rtnType_) {
133        case RTN_UNICAST:
134            if (route.hasGateway_) {
135                nextHop = route.gateway_.address_;
136            }
137            break;
138        case RTN_UNREACHABLE:
139            nextHop = NEXTHOP_UNREACHABLE;
140            break;
141        case RTN_THROW:
142            nextHop = NEXTHOP_THROW;
143            break;
144        default:
145            break;
146    }
147
148    ToPrefixString(route.destination_.address_, route.destination_.prefixlen_, dest);
149    if (dest.empty()) {
150        NETMGR_LOG_E("route dest is empty.");
151        return ret;
152    }
153
154    switch (op) {
155        case ROUTE_ADD:
156            ret = NetsysController::GetInstance().NetworkAddRoute(netId, route.iface_, dest, nextHop);
157            break;
158        case ROUTE_REMOVE:
159            ret = NetsysController::GetInstance().NetworkRemoveRoute(netId, route.iface_, dest, nextHop);
160            break;
161        default:
162            break;
163    }
164
165    return ret;
166}
167
168void RouteUtils::ToPrefixString(const std::string &src, int32_t prefixLen, std::string &dest)
169{
170    dest = MaskAddress(src, prefixLen);
171    NETMGR_LOG_D("ToPrefixString: src addr, src prefixlen[%{public}d], mask dest addr", prefixLen);
172    if (!dest.empty()) {
173        dest += "/";
174        dest += std::to_string(prefixLen);
175    }
176}
177
178std::string RouteUtils::MaskAddress(const std::string &addr, int32_t prefixLen)
179{
180    int32_t netScope = 0;
181    int32_t hostScope = 0;
182    uint8_t mask = 0;
183    uint8_t array[IPV6_UINT_LEN] = {0};
184    char str[INET6_ADDRSTRLEN] = {0};
185    int32_t af = prefixLen > IPV4_PRIFX_LEN ? AF_INET6 : AF_INET;
186    int32_t arrayLen = (af == AF_INET ? IPV4_UINT_LEN : IPV6_UINT_LEN);
187
188    netScope = prefixLen / IP_PER_UINT_SIZE;
189    hostScope = prefixLen % IP_PER_UINT_SIZE;
190    mask = (uint8_t)(IP_PER_UINT_MASK << (IP_PER_UINT_SIZE - hostScope));
191
192    if (inet_pton(af, addr.c_str(), array) != 1) {
193        return std::string("");
194    }
195
196    if (netScope < arrayLen) {
197        array[netScope] = (uint8_t)(array[netScope] & mask);
198    }
199
200    netScope++;
201    for (; netScope < arrayLen; netScope++) {
202        array[netScope] = 0;
203    }
204
205    if (inet_ntop(af, array, str, INET6_ADDRSTRLEN) == nullptr) {
206        return std::string("");
207    }
208
209    return std::string(str);
210}
211} // namespace NetManagerStandard
212} // namespace OHOS
213