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