1 /*
2 * Copyright (c) 2023 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 "setup_context.h"
17
18 #include <new>
19 #include <string>
20 #include <vector>
21
22 #include "inet_addr.h"
23 #include "napi_utils.h"
24 #include "net_manager_constants.h"
25 #include "netmanager_base_common_utils.h"
26 #include "netmgr_ext_log_wrapper.h"
27 #include "route.h"
28
29 namespace OHOS {
30 namespace NetManagerStandard {
31 namespace {
32 constexpr uint8_t NET_FAMILY_IPV4 = 1;
33 constexpr uint8_t NET_FAMILY_IPV6 = 2;
34 constexpr int32_t NET_MASK_MAX_LENGTH = 32;
35 constexpr int32_t IPV6_NET_PREFIX_MAX_LENGTH = 128;
36 constexpr int32_t PARAM_JUST_OPTIONS = 1;
37 constexpr int32_t PARAM_OPTIONS_AND_CALLBACK = 2;
38 constexpr const char *CONFIG_ADDRESSES = "addresses";
39 constexpr const char *CONFIG_ROUTES = "routes";
40 constexpr const char *NET_ADDRESS = "address";
41 constexpr const char *NET_FAMILY = "family";
42 constexpr const char *NET_PORT = "port";
43 constexpr const char *NET_PREFIXLENGTH = "prefixLength";
44 constexpr const char *NET_INTERFACE = "interface";
45 constexpr const char *NET_DESTINATION = "destination";
46 constexpr const char *NET_GATEWAY = "gateway";
47 constexpr const char *NET_HAS_GATEWAY = "hasGateway";
48 constexpr const char *NET_ISDEFAULTROUTE = "isDefaultRoute";
49 constexpr const char *CONFIG_DNSADDRESSES = "dnsAddresses";
50 constexpr const char *CONFIG_SEARCHDOMAINS = "searchDomains";
51 constexpr const char *CONFIG_MTU = "mtu";
52 constexpr const char *CONFIG_ISIPV4ACCEPTED = "isIPv4Accepted";
53 constexpr const char *CONFIG_ISIPV6ACCEPTED = "isIPv6Accepted";
54 constexpr const char *CONFIG_ISLEGACY = "isLegacy";
55 constexpr const char *CONFIG_ISMETERED = "isMetered";
56 constexpr const char *CONFIG_ISBLOCKING = "isBlocking";
57 constexpr const char *CONFIG_TRUSTEDAPPLICATIONS = "trustedApplications";
58 constexpr const char *CONFIG_BLOCKEDAPPLICATIONS = "blockedApplications";
CheckParamsType(napi_env env,napi_value * params,size_t paramsCount)59 bool CheckParamsType(napi_env env, napi_value *params, size_t paramsCount)
60 {
61 switch (paramsCount) {
62 case PARAM_JUST_OPTIONS:
63 return (NapiUtils::GetValueType(env, params[0]) == napi_object);
64 case PARAM_OPTIONS_AND_CALLBACK:
65 return ((NapiUtils::GetValueType(env, params[0]) == napi_object) &&
66 (NapiUtils::GetValueType(env, params[1]) == napi_function));
67 default:
68 return false;
69 }
70 }
71
GetStringFromJsMandatoryItem(napi_env env,napi_value object,const std::string & key,std::string & value)72 bool GetStringFromJsMandatoryItem(napi_env env, napi_value object, const std::string &key, std::string &value)
73 {
74 if (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, object, key)) != napi_string) {
75 NETMGR_EXT_LOG_E("param [%{public}s] type is mismatch", key.c_str());
76 return false;
77 }
78 value = NapiUtils::GetStringPropertyUtf8(env, object, key);
79 return (value.empty()) ? false : true;
80 }
81
GetStringFromJsOptionItem(napi_env env,napi_value object,const std::string & key,std::string & value)82 void GetStringFromJsOptionItem(napi_env env, napi_value object, const std::string &key, std::string &value)
83 {
84 if (NapiUtils::HasNamedProperty(env, object, key)) {
85 if (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, object, key)) == napi_string) {
86 value = NapiUtils::GetStringPropertyUtf8(env, object, key);
87 NETMGR_EXT_LOG_I("%{public}s: %{public}s", key.c_str(), value.c_str());
88 } else {
89 NETMGR_EXT_LOG_E("param [%{public}s] type is mismatch", key.c_str());
90 }
91 }
92 }
93
GetUint8FromJsOptionItem(napi_env env,napi_value object,const std::string & key,uint8_t & value)94 void GetUint8FromJsOptionItem(napi_env env, napi_value object, const std::string &key, uint8_t &value)
95 {
96 if (NapiUtils::HasNamedProperty(env, object, key)) {
97 if (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, object, key)) == napi_number) {
98 value = static_cast<uint8_t>(NapiUtils::GetUint32Property(env, object, key));
99 NETMGR_EXT_LOG_I("%{public}s: %{public}d", key.c_str(), value);
100 } else {
101 NETMGR_EXT_LOG_E("param [%{public}s] type is mismatch", key.c_str());
102 }
103 }
104 }
105
GetBoolFromJsOptionItem(napi_env env,napi_value object,const std::string & key,bool & value)106 void GetBoolFromJsOptionItem(napi_env env, napi_value object, const std::string &key, bool &value)
107 {
108 if (NapiUtils::HasNamedProperty(env, object, key)) {
109 if (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, object, key)) == napi_boolean) {
110 value = NapiUtils::GetBooleanProperty(env, object, key);
111 NETMGR_EXT_LOG_I("%{public}s: %{public}d", key.c_str(), value);
112 } else {
113 NETMGR_EXT_LOG_E("param [%{public}s] type is mismatch", key.c_str());
114 }
115 }
116 }
117 } // namespace
118
SetUpContext(napi_env env,EventManager * manager)119 SetUpContext::SetUpContext(napi_env env, EventManager *manager) : BaseContext(env, manager) {}
120
ParseParams(napi_value * params,size_t paramsCount)121 void SetUpContext::ParseParams(napi_value *params, size_t paramsCount)
122 {
123 if (!CheckParamsType(GetEnv(), params, paramsCount)) {
124 NETMGR_EXT_LOG_E("params type is mismatch");
125 SetNeedThrowException(true);
126 SetErrorCode(NETMANAGER_EXT_ERR_PARAMETER_ERROR);
127 return;
128 }
129 if (!ParseVpnConfig(params)) {
130 NETMGR_EXT_LOG_E("parse vpn config from js failed");
131 SetNeedThrowException(true);
132 SetErrorCode(NETMANAGER_EXT_ERR_PARAMETER_ERROR);
133 return;
134 }
135 if (paramsCount == PARAM_OPTIONS_AND_CALLBACK) {
136 SetParseOK(SetCallback(params[1]) == napi_ok);
137 return;
138 }
139 SetParseOK(true);
140 }
141
ParseVpnConfig(napi_value * params)142 bool SetUpContext::ParseVpnConfig(napi_value *params)
143 {
144 vpnConfig_ = new (std::nothrow) VpnConfig();
145 if (vpnConfig_ == nullptr) {
146 NETMGR_EXT_LOG_E("vpnConfig is nullptr");
147 return false;
148 }
149 if (!ParseAddrRouteParams(params[0]) || !ParseChoiceableParams(params[0])) {
150 return false;
151 }
152 return true;
153 }
154
ParseAddressFamily(napi_env env,napi_value netAddress,uint8_t & family)155 static bool ParseAddressFamily(napi_env env, napi_value netAddress, uint8_t &family)
156 {
157 // The value is 1 for IPv4 and 2 for IPv6. The default value is 1.
158 if (!NapiUtils::HasNamedProperty(env, netAddress, NET_FAMILY)) {
159 family = AF_INET;
160 return true;
161 }
162 GetUint8FromJsOptionItem(env, netAddress, NET_FAMILY, family);
163 if (family == NET_FAMILY_IPV4) {
164 family = AF_INET;
165 return true;
166 } else if (family == NET_FAMILY_IPV6) {
167 family = AF_INET6;
168 return true;
169 } else {
170 NETMGR_EXT_LOG_E("family %{public}u is mismatch", family);
171 return false;
172 }
173 }
174
ParseAddress(napi_env env,napi_value address,struct INetAddr & iNetAddr)175 static bool ParseAddress(napi_env env, napi_value address, struct INetAddr &iNetAddr)
176 {
177 napi_value netAddress = NapiUtils::GetNamedProperty(env, address, NET_ADDRESS);
178 if (NapiUtils::GetValueType(env, netAddress) != napi_object) {
179 NETMGR_EXT_LOG_E("param address type is mismatch");
180 return false;
181 }
182
183 if (!GetStringFromJsMandatoryItem(env, netAddress, NET_ADDRESS, iNetAddr.address_)) {
184 NETMGR_EXT_LOG_E("get address-address failed");
185 return false;
186 }
187
188 bool isIpv6 = CommonUtils::IsValidIPV6(iNetAddr.address_);
189 if (!isIpv6) {
190 if (!CommonUtils::IsValidIPV4(iNetAddr.address_)) {
191 NETMGR_EXT_LOG_E("invalid ip address");
192 return false;
193 }
194 }
195
196 if (!ParseAddressFamily(env, netAddress, iNetAddr.family_)) {
197 return false;
198 }
199
200 GetUint8FromJsOptionItem(env, netAddress, NET_PORT, iNetAddr.port_);
201
202 if (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, address, NET_PREFIXLENGTH)) != napi_number) {
203 NETMGR_EXT_LOG_E("param [%{public}s] type is mismatch", NET_PREFIXLENGTH);
204 return false;
205 }
206 iNetAddr.prefixlen_ = static_cast<uint8_t>(NapiUtils::GetUint32Property(env, address, NET_PREFIXLENGTH));
207 if (isIpv6 && iNetAddr.prefixlen_ == 0) {
208 iNetAddr.prefixlen_ = CommonUtils::Ipv6PrefixLen(iNetAddr.address_);
209 }
210
211 NETMGR_EXT_LOG_I("isIpv6:%{public}d, %{public}s: %{public}d", isIpv6, NET_PREFIXLENGTH, iNetAddr.prefixlen_);
212
213 uint32_t prefix = iNetAddr.prefixlen_;
214 if (prefix == 0 || prefix >= (isIpv6 ? IPV6_NET_PREFIX_MAX_LENGTH : NET_MASK_MAX_LENGTH)) {
215 NETMGR_EXT_LOG_E("prefix: %{public}d error", prefix);
216 return false;
217 }
218 if (!isIpv6) {
219 uint32_t maskUint = (0xFFFFFFFF << (NET_MASK_MAX_LENGTH - prefix));
220 uint32_t ipAddrUint = CommonUtils::ConvertIpv4Address(iNetAddr.address_);
221 uint32_t subNetAddress = ipAddrUint & maskUint;
222 uint32_t boardcastAddress = subNetAddress | (~maskUint);
223 if ((ipAddrUint == subNetAddress) || (ipAddrUint == boardcastAddress)) {
224 NETMGR_EXT_LOG_E("invalid ip address");
225 return false;
226 }
227 }
228 return true;
229 }
230
ParseDestination(napi_env env,napi_value jsRoute,struct INetAddr & iNetAddr)231 static bool ParseDestination(napi_env env, napi_value jsRoute, struct INetAddr &iNetAddr)
232 {
233 napi_value destination = NapiUtils::GetNamedProperty(env, jsRoute, NET_DESTINATION);
234 if (NapiUtils::GetValueType(env, destination) != napi_object) {
235 NETMGR_EXT_LOG_E("param destination type is mismatch");
236 return false;
237 }
238
239 napi_value netAddress = NapiUtils::GetNamedProperty(env, destination, NET_ADDRESS);
240 if (NapiUtils::GetValueType(env, netAddress) != napi_object) {
241 NETMGR_EXT_LOG_E("param address type is mismatch");
242 return false;
243 }
244
245 if (!GetStringFromJsMandatoryItem(env, netAddress, NET_ADDRESS, iNetAddr.address_)) {
246 NETMGR_EXT_LOG_E("get destination-address failed");
247 return false;
248 }
249
250 if (!CommonUtils::IsValidIPV4(iNetAddr.address_) && !CommonUtils::IsValidIPV6(iNetAddr.address_)) {
251 NETMGR_EXT_LOG_E("invalid ip address");
252 return false;
253 }
254
255 if (!ParseAddressFamily(env, netAddress, iNetAddr.family_)) {
256 return false;
257 }
258 GetUint8FromJsOptionItem(env, netAddress, NET_PORT, iNetAddr.port_);
259 GetUint8FromJsOptionItem(env, destination, NET_PREFIXLENGTH, iNetAddr.prefixlen_);
260 return true;
261 }
262
ParseGateway(napi_env env,napi_value jsRoute,struct INetAddr & iNetAddr)263 static bool ParseGateway(napi_env env, napi_value jsRoute, struct INetAddr &iNetAddr)
264 {
265 napi_value gateway = NapiUtils::GetNamedProperty(env, jsRoute, NET_GATEWAY);
266 if (NapiUtils::GetValueType(env, gateway) != napi_object) {
267 NETMGR_EXT_LOG_E("param gateway type is mismatch");
268 return false;
269 }
270
271 GetStringFromJsMandatoryItem(env, gateway, NET_ADDRESS, iNetAddr.address_);
272
273 if (!ParseAddressFamily(env, gateway, iNetAddr.family_)) {
274 return false;
275 }
276 GetUint8FromJsOptionItem(env, gateway, NET_PORT, iNetAddr.port_);
277 return true;
278 }
279
ParseRoute(napi_env env,napi_value jsRoute,Route & route)280 static bool ParseRoute(napi_env env, napi_value jsRoute, Route &route)
281 {
282 GetStringFromJsOptionItem(env, jsRoute, NET_INTERFACE, route.iface_);
283
284 if (!ParseDestination(env, jsRoute, route.destination_)) {
285 NETMGR_EXT_LOG_E("ParseDestination failed");
286 return false;
287 }
288 if (!ParseGateway(env, jsRoute, route.gateway_)) {
289 NETMGR_EXT_LOG_E("ParseGateway failed");
290 return false;
291 }
292
293 GetBoolFromJsOptionItem(env, jsRoute, NET_HAS_GATEWAY, route.hasGateway_);
294 GetBoolFromJsOptionItem(env, jsRoute, NET_ISDEFAULTROUTE, route.isDefaultRoute_);
295 return true;
296 }
297
ParseAddrRouteParams(napi_value config)298 bool SetUpContext::ParseAddrRouteParams(napi_value config)
299 {
300 // parse addresses.
301 if (NapiUtils::HasNamedProperty(GetEnv(), config, CONFIG_ADDRESSES)) {
302 napi_value addrArray = NapiUtils::GetNamedProperty(GetEnv(), config, CONFIG_ADDRESSES);
303 if (!NapiUtils::IsArray(GetEnv(), addrArray)) {
304 NETMGR_EXT_LOG_E("addresses is not array");
305 return false;
306 }
307 uint32_t addrLength = NapiUtils::GetArrayLength(GetEnv(), addrArray);
308 for (uint32_t i = 0; i < addrLength; ++i) { // set length limit.
309 INetAddr iNetAddr;
310 if (!ParseAddress(GetEnv(), NapiUtils::GetArrayElement(GetEnv(), addrArray, i), iNetAddr)) {
311 NETMGR_EXT_LOG_E("ParseAddress failed");
312 return false;
313 }
314 vpnConfig_->addresses_.emplace_back(iNetAddr);
315 bool isIpv6 = CommonUtils::IsValidIPV6(iNetAddr.address_);
316 vpnConfig_->isAcceptIPv4_ = !isIpv6;
317 vpnConfig_->isAcceptIPv6_ = isIpv6;
318 }
319 }
320
321 // parse routes.
322 if (NapiUtils::HasNamedProperty(GetEnv(), config, CONFIG_ROUTES)) {
323 napi_value routes = NapiUtils::GetNamedProperty(GetEnv(), config, CONFIG_ROUTES);
324 if (!NapiUtils::IsArray(GetEnv(), routes)) {
325 NETMGR_EXT_LOG_E("routes is not array");
326 return false;
327 }
328 uint32_t routesLength = NapiUtils::GetArrayLength(GetEnv(), routes);
329 for (uint32_t idx = 0; idx < routesLength; ++idx) { // set length limit.
330 struct Route routeInfo;
331 if (!ParseRoute(GetEnv(), NapiUtils::GetArrayElement(GetEnv(), routes, idx), routeInfo)) {
332 NETMGR_EXT_LOG_E("ParseRoute failed");
333 return false;
334 }
335 vpnConfig_->routes_.emplace_back(routeInfo);
336 }
337 }
338 return true;
339 }
340
ParseOptionArrayString(napi_env env,napi_value config,const std::string & key,std::vector<std::string> & vector)341 static bool ParseOptionArrayString(napi_env env, napi_value config, const std::string &key,
342 std::vector<std::string> &vector)
343 {
344 if (NapiUtils::HasNamedProperty(env, config, key)) {
345 napi_value array = NapiUtils::GetNamedProperty(env, config, key);
346 if (!NapiUtils::IsArray(env, array)) {
347 NETMGR_EXT_LOG_E("param [%{public}s] is not array", key.c_str());
348 return false;
349 }
350 uint32_t arrayLength = NapiUtils::GetArrayLength(env, array);
351 for (uint32_t i = 0; i < arrayLength; ++i) {
352 std::string item = NapiUtils::GetStringFromValueUtf8(env, NapiUtils::GetArrayElement(env, array, i));
353 NETMGR_EXT_LOG_D("%{public}s: %{public}s", key.c_str(), item.c_str());
354 vector.push_back(item);
355 }
356 }
357 return true;
358 }
359
ParseChoiceableParams(napi_value config)360 bool SetUpContext::ParseChoiceableParams(napi_value config)
361 {
362 ParseOptionArrayString(GetEnv(), config, CONFIG_DNSADDRESSES, vpnConfig_->dnsAddresses_);
363 ParseOptionArrayString(GetEnv(), config, CONFIG_SEARCHDOMAINS, vpnConfig_->searchDomains_);
364
365 if (NapiUtils::HasNamedProperty(GetEnv(), config, CONFIG_MTU)) {
366 if (NapiUtils::GetValueType(GetEnv(), NapiUtils::GetNamedProperty(GetEnv(), config, CONFIG_MTU)) ==
367 napi_number) {
368 vpnConfig_->mtu_ = NapiUtils::GetInt32Property(GetEnv(), config, CONFIG_MTU);
369 NETMGR_EXT_LOG_I("%{public}s: %{public}d", CONFIG_MTU, vpnConfig_->mtu_);
370 } else {
371 NETMGR_EXT_LOG_E("param [%{public}s] type is mismatch", CONFIG_MTU);
372 }
373 }
374
375 GetBoolFromJsOptionItem(GetEnv(), config, CONFIG_ISIPV4ACCEPTED, vpnConfig_->isAcceptIPv4_);
376 GetBoolFromJsOptionItem(GetEnv(), config, CONFIG_ISIPV6ACCEPTED, vpnConfig_->isAcceptIPv6_);
377 GetBoolFromJsOptionItem(GetEnv(), config, CONFIG_ISLEGACY, vpnConfig_->isLegacy_);
378 GetBoolFromJsOptionItem(GetEnv(), config, CONFIG_ISMETERED, vpnConfig_->isMetered_);
379 GetBoolFromJsOptionItem(GetEnv(), config, CONFIG_ISBLOCKING, vpnConfig_->isBlocking_);
380
381 ParseOptionArrayString(GetEnv(), config, CONFIG_TRUSTEDAPPLICATIONS, vpnConfig_->acceptedApplications_);
382 ParseOptionArrayString(GetEnv(), config, CONFIG_BLOCKEDAPPLICATIONS, vpnConfig_->refusedApplications_);
383 return true;
384 }
385 } // namespace NetManagerStandard
386 } // namespace OHOS
387