• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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