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