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 "napi/native_api.h"
17 #include "hilog/log.h"
18
19 #include <cstring>
20 #include <thread>
21 #include <js_native_api.h>
22 #include <js_native_api_types.h>
23 #include <unistd.h>
24 #include <netinet/in.h>
25 #include <sys/socket.h>
26 #include <thread>
27 #include <sys/time.h>
28
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32
33 #define MAKE_FILE_NAME (strrchr(__FILE__, '/') + 1)
34
35 #define NETMANAGER_VPN_LOGE(fmt, ...) \
36 OH_LOG_Print(LOG_APP, LOG_ERROR, 0x15b0, "NetMgrVpn", "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME, \
37 __LINE__, ##__VA_ARGS__)
38
39 #define NETMANAGER_VPN_LOGI(fmt, ...) \
40 OH_LOG_Print(LOG_APP, LOG_INFO, 0x15b0, "NetMgrVpn", "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME, \
41 __LINE__, ##__VA_ARGS__)
42
43 #define NETMANAGER_VPN_LOGD(fmt, ...) \
44 OH_LOG_Print(LOG_APP, LOG_DEBUG, 0x15b0, "NetMgrVpn", "vpn [%{public}s %{public}d] " fmt, MAKE_FILE_NAME, \
45 __LINE__, ##__VA_ARGS__)
46
47 constexpr int BUFFER_SIZE = 2048;
48 constexpr int ERRORAGAIN = 11;
49
50 struct FdInfo {
51 int32_t tunFd = 0;
52 int32_t tunnelFd = 0;
53 struct sockaddr_in serverAddr;
54 };
55
56 static FdInfo g_fdInfo;
57 static bool g_threadRunF = false;
58 static std::thread g_threadt1;
59 static std::thread g_threadt2;
60
61 static constexpr const int MAX_STRING_LENGTH = 1024;
GetStringFromValueUtf8(napi_env env,napi_value value)62 static std::string GetStringFromValueUtf8(napi_env env, napi_value value)
63 {
64 std::string result;
65 char str[MAX_STRING_LENGTH] = {0};
66 size_t length = 0;
67 napi_get_value_string_utf8(env, value, str, MAX_STRING_LENGTH, &length);
68 if (length > 0) {
69 return result.append(str, length);
70 }
71 return result;
72 }
73
HandleReadTunfd(FdInfo fdInfo)74 static void HandleReadTunfd(FdInfo fdInfo)
75 {
76 uint8_t buffer[BUFFER_SIZE] = {0};
77 while (g_threadRunF) {
78 if (fdInfo.tunFd <= 0) {
79 sleep(1);
80 continue;
81 }
82
83 int ret = read(fdInfo.tunFd, buffer, sizeof(buffer));
84 if (ret <= 0) {
85 if (errno != ERRORAGAIN) {
86 sleep(1);
87 }
88 continue;
89 }
90
91 // Read the data from the virtual network interface and send it to the client through a TCP tunnel.
92 NETMANAGER_VPN_LOGD("buffer: %{public}s, len: %{public}d", buffer, ret);
93 ret = sendto(fdInfo.tunnelFd, buffer, ret, 0,
94 reinterpret_cast<struct sockaddr *>(&fdInfo.serverAddr), sizeof(fdInfo.serverAddr));
95 if (ret <= 0) {
96 NETMANAGER_VPN_LOGE("send to server[%{public}s:%{public}d] failed, ret: %{public}d, error: %{public}s",
97 inet_ntoa(fdInfo.serverAddr.sin_addr), ntohs(fdInfo.serverAddr.sin_port), ret,
98 strerror(errno));
99 continue;
100 }
101 }
102 }
103
HandleTcpReceived(FdInfo fdInfo)104 static void HandleTcpReceived(FdInfo fdInfo)
105 {
106 int addrlen = sizeof(struct sockaddr_in);
107 uint8_t buffer[BUFFER_SIZE] = {0};
108 while (g_threadRunF) {
109 if (fdInfo.tunnelFd <= 0) {
110 sleep(1);
111 continue;
112 }
113
114 int length = recvfrom(fdInfo.tunnelFd, buffer, sizeof(buffer), 0,
115 reinterpret_cast<struct sockaddr *>(&fdInfo.serverAddr),
116 reinterpret_cast<socklen_t *>(&addrlen));
117 if (length < 0) {
118 if (errno != EAGAIN) {
119 NETMANAGER_VPN_LOGE("read tun device error: %{public}d %{public}d", errno, fdInfo.tunnelFd);
120 }
121 continue;
122 }
123
124 NETMANAGER_VPN_LOGI("from [%{public}s:%{public}d] data: %{public}s, len: %{public}d",
125 inet_ntoa(fdInfo.serverAddr.sin_addr), ntohs(fdInfo.serverAddr.sin_port), buffer, length);
126 int ret = write(fdInfo.tunFd, buffer, length);
127 if (ret <= 0) {
128 NETMANAGER_VPN_LOGE("error Write To Tunfd, errno: %{public}d", errno);
129 }
130 }
131 }
132
TcpConnect(napi_env env,napi_callback_info info)133 static napi_value TcpConnect(napi_env env, napi_callback_info info)
134 {
135 size_t numArgs = 2;
136 size_t argc = numArgs;
137 napi_value args[2] = {nullptr};
138 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
139
140 int32_t port = 0;
141 napi_get_value_int32(env, args[1], &port);
142 std::string ipAddr = GetStringFromValueUtf8(env, args[0]);
143
144 NETMANAGER_VPN_LOGI("ip: %{public}s port: %{public}d", ipAddr.c_str(), port);
145
146 int32_t sockFd = socket(AF_INET, SOCK_DGRAM, 0);
147 if (sockFd == -1) {
148 NETMANAGER_VPN_LOGE("socket() error");
149 return 0;
150 }
151
152 struct timeval timeout = {1, 0};
153 setsockopt(sockFd, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char *>(&timeout), sizeof(struct timeval));
154
155 memset(&g_fdInfo.serverAddr, 0, sizeof(g_fdInfo.serverAddr));
156 g_fdInfo.serverAddr.sin_family = AF_INET;
157 g_fdInfo.serverAddr.sin_addr.s_addr = inet_addr(ipAddr.c_str()); // server's IP addr
158 g_fdInfo.serverAddr.sin_port = htons(port); // port
159
160 NETMANAGER_VPN_LOGI("Connection successful\n");
161
162 napi_value tunnelFd;
163 napi_create_int32(env, sockFd, &tunnelFd);
164 return tunnelFd;
165 }
166
StartVpn(napi_env env,napi_callback_info info)167 static napi_value StartVpn(napi_env env, napi_callback_info info)
168 {
169 size_t numArgs = 2;
170 size_t argc = numArgs;
171 napi_value args[2] = {nullptr};
172 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
173
174 napi_get_value_int32(env, args[0], &g_fdInfo.tunFd);
175 napi_get_value_int32(env, args[1], &g_fdInfo.tunnelFd);
176
177 if (g_threadRunF) {
178 g_threadRunF = false;
179 g_threadt1.join();
180 g_threadt2.join();
181 }
182
183 g_threadRunF = true;
184 std::thread tt1(HandleReadTunfd, g_fdInfo);
185 std::thread tt2(HandleTcpReceived, g_fdInfo);
186
187 g_threadt1 = std::move(tt1);
188 g_threadt2 = std::move(tt2);
189
190 NETMANAGER_VPN_LOGI("StartVpn successful\n");
191
192 napi_value retValue;
193 napi_create_int32(env, 0, &retValue);
194 return retValue;
195 }
196
StopVpn(napi_env env,napi_callback_info info)197 static napi_value StopVpn(napi_env env, napi_callback_info info)
198 {
199 size_t argc = 1;
200 napi_value args[1] = {nullptr};
201 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
202
203 int32_t tunnelFd;
204 napi_get_value_int32(env, args[0], &tunnelFd);
205 if (tunnelFd) {
206 close(tunnelFd);
207 tunnelFd = 0;
208 }
209
210 if (g_threadRunF) {
211 g_threadRunF = false;
212 g_threadt1.join();
213 g_threadt2.join();
214 }
215
216 NETMANAGER_VPN_LOGI("StopVpn successful\n");
217
218 napi_value retValue;
219 napi_create_int32(env, 0, &retValue);
220 return retValue;
221 }
222
223 EXTERN_C_START
Init(napi_env env,napi_value exports)224 static napi_value Init(napi_env env, napi_value exports)
225 {
226 napi_property_descriptor desc[] = {
227 {"tcpConnect", nullptr, TcpConnect, nullptr, nullptr, nullptr, napi_default, nullptr},
228 {"startVpn", nullptr, StartVpn, nullptr, nullptr, nullptr, napi_default, nullptr},
229 {"stopVpn", nullptr, StopVpn, nullptr, nullptr, nullptr, napi_default, nullptr},
230 };
231 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
232 return exports;
233 }
234 EXTERN_C_END
235
236 static napi_module demoModule = {
237 .nm_version = 1,
238 .nm_flags = 0,
239 .nm_filename = nullptr,
240 .nm_register_func = Init,
241 .nm_modname = "entry",
242 .nm_priv = ((void *)0),
243 .reserved = {0},
244 };
245
RegisterEntryModule(void)246 extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
247 {
248 NETMANAGER_VPN_LOGI("vpn 15b0 HELLO ~~~~~~~~~~");
249 napi_module_register(&demoModule);
250 }
251