1 /*
2  * Copyright (c) 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 #include "nat464_service.h"
16 
17 #include <algorithm>
18 #include <arpa/inet.h>
19 #include <netinet/in.h>
20 #include <string>
21 
22 #include "ffrt.h"
23 #include "inet_addr.h"
24 #include "net_all_capabilities.h"
25 #include "net_interface_config.h"
26 #include "net_manager_constants.h"
27 #include "net_mgr_log_wrapper.h"
28 #include "netsys_controller.h"
29 
30 namespace OHOS {
31 namespace NetManagerStandard {
Nat464Service(int32_t netId,const std::string & v6Iface)32 Nat464Service::Nat464Service(int32_t netId, const std::string &v6Iface)
33 {
34     netId_ = netId;
35     v6Iface_ = v6Iface;
36     v4TunIface_ = std::string(CLAT_PREFIX) + v6Iface;
37     tryStopDiscovery_ = false;
38     discoveryCycleMs_ = INITIAL_DISCOVERY_CYCLE_MS;
39     discoveryIter_ = 1;
40     serviceState_ = NAT464_SERVICE_STATE_IDLE;
41 }
42 
MaybeUpdateV6Iface(const std::string & v6Iface)43 void Nat464Service::MaybeUpdateV6Iface(const std::string &v6Iface)
44 {
45     if (serviceState_ == NAT464_SERVICE_STATE_IDLE) {
46         v6Iface_ = v6Iface;
47         v4TunIface_ = std::string(CLAT_PREFIX) + v6Iface;
48     }
49 }
50 
UpdateService(Nat464UpdateFlag updateFlag)51 void Nat464Service::UpdateService(Nat464UpdateFlag updateFlag)
52 {
53     auto handle = serviceUpdateQueue_.submit_h([this, updateFlag]() { UpdateServiceState(updateFlag); },
54                                                ffrt::task_attr().name("UpdateNat464ServiceState"));
55     serviceUpdateQueue_.wait(handle);
56 }
57 
UpdateServiceState(Nat464UpdateFlag updateFlag)58 void Nat464Service::UpdateServiceState(Nat464UpdateFlag updateFlag)
59 {
60     NETMGR_LOG_I("update nat464 service state");
61     switch (serviceState_) {
62         case NAT464_SERVICE_STATE_IDLE:
63             if (updateFlag == NAT464_SERVICE_CONTINUE) {
64                 StartPrefixDiscovery();
65                 serviceState_ = NAT464_SERVICE_STATE_DISCOVERING;
66             }
67             break;
68 
69         case NAT464_SERVICE_STATE_DISCOVERING:
70             if (updateFlag == NAT464_SERVICE_STOP) {
71                 StopPrefixDiscovery();
72                 serviceState_ = NAT464_SERVICE_STATE_IDLE;
73             }
74             if (updateFlag == NAT464_SERVICE_CONTINUE && !nat64PrefixFromDns_.address_.empty()) {
75                 StartService();
76                 serviceState_ = NAT464_SERVICE_STATE_RUNNING;
77             }
78             break;
79 
80         case NAT464_SERVICE_STATE_RUNNING:
81             if (updateFlag == NAT464_SERVICE_STOP) {
82                 StopService();
83                 serviceState_ = NAT464_SERVICE_STATE_IDLE;
84                 break;
85             }
86             break;
87     }
88 }
89 
StartPrefixDiscovery()90 void Nat464Service::StartPrefixDiscovery()
91 {
92     NETMGR_LOG_I("start to discover prefix64 from DNS64 server");
93     ffrt::submit([this]() { DiscoverPrefix(); }, {}, {},
94                  ffrt::task_attr().name(("Prefix64DiscoveryIter" + std::to_string(discoveryIter_)).c_str()));
95 }
96 
DiscoverPrefix()97 void Nat464Service::DiscoverPrefix()
98 {
99     if (tryStopDiscovery_) {
100         NETMGR_LOG_I("stop flag is true, stop cycle");
101         tryStopDiscovery_ = false;
102         discoveryCycleMs_ = INITIAL_DISCOVERY_CYCLE_MS;
103         discoveryIter_ = 1;
104         return;
105     }
106     if (GetPrefixFromDns64()) {
107         NETMGR_LOG_I("Get prefix64 from DNS64 server, stop cycle");
108         discoveryCycleMs_ = INITIAL_DISCOVERY_CYCLE_MS;
109         discoveryIter_ = 1;
110         UpdateService(NAT464_SERVICE_CONTINUE);
111     } else if (discoveryCycleMs_ > MAX_DISCOVERY_CYCLE_MS) {
112         NETMGR_LOG_W("Fail to get prefix64 from DNS64 after %{public}u iterations, stop cycle", discoveryIter_);
113     } else {
114         NETMGR_LOG_I("Fail to get prefix64 from DNS64 server, try again after %{public}u ms", discoveryCycleMs_);
115         ffrt::this_task::sleep_for(std::chrono::milliseconds(discoveryCycleMs_));
116         discoveryIter_ += 1;
117         discoveryCycleMs_ *= DISCOVERY_CYCLE_MULTIPLIER;
118         ffrt::submit([this]() { DiscoverPrefix(); }, {}, {},
119                      ffrt::task_attr().name(("Prefix64DiscoveryIter" + std::to_string(discoveryIter_)).c_str()));
120     }
121 }
122 
GetPrefixFromDns64()123 bool Nat464Service::GetPrefixFromDns64()
124 {
125     addrinfo hint = {};
126     addrinfo *result;
127     hint.ai_family = AF_INET6;
128 
129     queryparam qparam = {};
130     qparam.qp_netid = netId_;
131     qparam.qp_type = 1;
132 
133     int32_t ret = getaddrinfo_ext(IPV4_ONLY_HOST, NULL, &hint, &result, &qparam);
134     if (ret != 0) {
135         NETMGR_LOG_W("fail to get v6Addr of the well-known ipv4-only host from dns, errno: %{public}d", ret);
136         return false;
137     }
138 
139     INetAddr prefixAddr;
140     for (addrinfo *tmp = result; tmp != nullptr; tmp = tmp->ai_next) {
141         if (tmp->ai_family != AF_INET6) {
142             continue;
143         }
144         auto addr = reinterpret_cast<sockaddr_in6 *>(tmp->ai_addr);
145         char addrstr[INET6_ADDRSTRLEN];
146         inet_ntop(AF_INET6, &addr->sin6_addr, addrstr, sizeof(addrstr));
147         prefixAddr.address_ = addrstr;
148         prefixAddr.family_ = tmp->ai_family;
149         prefixAddr.prefixlen_ = CLAT_PREFIX_BYTE_LEN * CHAR_BIT;
150         break;
151     }
152     freeaddrinfo(result);
153 
154     nat64PrefixFromDns_ = prefixAddr;
155     return true;
156 }
157 
StopPrefixDiscovery()158 void Nat464Service::StopPrefixDiscovery()
159 {
160     tryStopDiscovery_ = true;
161 }
162 
StartService()163 void Nat464Service::StartService()
164 {
165     if (serviceState_ == NAT464_SERVICE_STATE_RUNNING) {
166         NETMGR_LOG_W("Nat464 service already started");
167         return;
168     }
169 
170     int32_t ret = NetsysController::GetInstance().StartClat(v6Iface_, netId_, nat64PrefixFromDns_.address_);
171     if (ret != NETMANAGER_SUCCESS) {
172         NETMGR_LOG_W("fail to start clat, error no: %{public}d", ret);
173         return;
174     }
175 }
176 
StopService()177 void Nat464Service::StopService()
178 {
179     NetsysController::GetInstance().StopClat(v6Iface_);
180     nat64PrefixFromDns_ = INetAddr();
181 }
182 
183 } // namespace NetManagerStandard
184 } // namespace OHOS
185