1 /*
2 * Copyright (c) 2025 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 "socks5_instance.h"
17
18 #include <arpa/inet.h>
19 #include <unistd.h>
20 #include <netinet/tcp.h>
21
22 #include "netstack_log.h"
23 #include "socket_exec.h"
24 #include "socket_exec_common.h"
25 #include "socks5_none_method.h"
26 #include "socks5_passwd_method.h"
27 #include "socks5_package.h"
28 #include "socks5_utils.h"
29 #include "securec.h"
30
31 static constexpr const int INET_SOCKS5_UDP_HEADER_LEN = 10;
32
33 static constexpr const int INET6_SOCKS5_UDP_HEADER_LEN = 22;
34
35 static constexpr const int SOCKS5_DO_CONNECT_COUNT_MAX = 3;
36
37 namespace OHOS {
38 namespace NetStack {
39 namespace Socks5 {
40
UpdateErrorInfo(Socks5Status status)41 void Socks5Instance::UpdateErrorInfo(Socks5Status status)
42 {
43 errorCode_ = static_cast<int32_t>(status);
44 auto iter = g_errStatusMap.find(status);
45 if (iter != g_errStatusMap.end()) {
46 errorMessage_ = iter->second;
47 } else {
48 errorMessage_.clear();
49 }
50 }
51
UpdateErrorInfo(int32_t errCode,const std::string & errMessage)52 void Socks5Instance::UpdateErrorInfo(int32_t errCode, const std::string &errMessage)
53 {
54 errorCode_ = errCode;
55 errorMessage_ = errMessage;
56 }
57
SetSocks5Option(const std::shared_ptr<Socks5Option> & opt)58 void Socks5Instance::SetSocks5Option(const std::shared_ptr<Socks5Option> &opt)
59 {
60 options_ = opt;
61 }
62
SetDestAddress(const Socket::NetAddress & dest)63 void Socks5Instance::SetDestAddress(const Socket::NetAddress &dest)
64 {
65 this->dest_ = dest;
66 }
67
IsConnected() const68 bool Socks5Instance::IsConnected() const
69 {
70 return state_ == Socks5AuthState::SUCCESS;
71 }
72
DoConnect(Socks5Command command)73 bool Socks5Instance::DoConnect(Socks5Command command)
74 {
75 if (doConnectCount_++ > SOCKS5_DO_CONNECT_COUNT_MAX) {
76 NETSTACK_LOGE("socks5 instance connect count over %{public}d times socket:%{public}d",
77 SOCKS5_DO_CONNECT_COUNT_MAX, socketId_);
78 return false;
79 }
80
81 if (!RequestMethod(SOCKS5_METHODS)) {
82 NETSTACK_LOGE("socks5 instance fail to request method socket:%{public}d", socketId_);
83 return false;
84 }
85 if (method_ == nullptr) {
86 NETSTACK_LOGE("socks5 instance method is null socket:%{public}d", socketId_);
87 UpdateErrorInfo(Socks5Status::SOCKS5_METHOD_NEGO_ERROR);
88 return false;
89 }
90 if (!method_->RequestAuth(socketId_, options_->username_, options_->password_, options_->proxyAddress_)) {
91 NETSTACK_LOGE("socks5 instance fail to auth socket:%{public}d", socketId_);
92 return false;
93 }
94 const std::pair<bool, Socks5ProxyResponse> result{method_->RequestProxy(socketId_, command, dest_,
95 options_->proxyAddress_)};
96 if (!result.first) {
97 NETSTACK_LOGE("socks5 instance fail to request proxy socket:%{public}d", socketId_);
98 return false;
99 }
100 proxyBindAddr_.SetAddress(result.second.destAddr_, false);
101 proxyBindAddr_.SetPort(result.second.destPort_);
102 if (result.second.addrType_ == Socks5AddrType::IPV4) {
103 proxyBindAddr_.SetFamilyByJsValue(static_cast<uint32_t>(Socket::NetAddress::Family::IPv4));
104 } else if (result.second.addrType_ == Socks5AddrType::IPV6) {
105 proxyBindAddr_.SetFamilyByJsValue(static_cast<uint32_t>(Socket::NetAddress::Family::IPv6));
106 } else if (result.second.addrType_ == Socks5AddrType::DOMAIN_NAME) {
107 proxyBindAddr_.SetFamilyByJsValue(static_cast<uint32_t>(Socket::NetAddress::Family::DOMAIN_NAME));
108 } else {
109 NETSTACK_LOGE("socks5 instance get unknow addrType:%{public}d socket:%{public}d",
110 static_cast<uint32_t>(result.second.addrType_), socketId_);
111 }
112 state_ = Socks5AuthState::SUCCESS;
113 return true;
114 }
115
GetErrorCode() const116 int32_t Socks5Instance::GetErrorCode() const
117 {
118 return errorCode_;
119 }
120
GetErrorMessage() const121 std::string Socks5Instance::GetErrorMessage() const
122 {
123 return errorMessage_;
124 }
125
OnProxySocketError()126 void Socks5Instance::OnProxySocketError()
127 {
128 NETSTACK_LOGE("socks5 instance tcp error socket:%{public}d", socketId_);
129 state_ = Socks5AuthState::FAIL;
130 }
131
SetSocks5Instance(const std::shared_ptr<Socks5Instance> & socks5Inst)132 void Socks5Instance::SetSocks5Instance(const std::shared_ptr<Socks5Instance> &socks5Inst)
133 {
134 socks5Instance_ = socks5Inst;
135 }
136
GetProxyBindAddress() const137 Socket::NetAddress Socks5Instance::GetProxyBindAddress() const
138 {
139 return proxyBindAddr_;
140 }
141
GetSocketId() const142 int Socks5Instance::GetSocketId() const
143 {
144 return socketId_;
145 }
146
ConnectProxy()147 bool Socks5Instance::ConnectProxy()
148 {
149 const socklen_t addrLen{Socks5Utils::GetAddressLen(options_->proxyAddress_.netAddress_)};
150 // use default value
151 const uint32_t timeoutMSec{0U};
152 if (!NonBlockConnect(socketId_, options_->proxyAddress_.addr_, addrLen, timeoutMSec)) {
153 NETSTACK_LOGE("socks5 instance fail to connect proxy");
154 UpdateErrorInfo(Socks5Status::SOCKS5_FAIL_TO_CONNECT_PROXY);
155 return false;
156 }
157 return true;
158 }
159
CloseSocket()160 void Socks5Instance::CloseSocket()
161 {
162 if (socketId_ != SOCKS5_INVALID_SOCKET_FD) {
163 NETSTACK_LOGI("socks5 instance close socket:%{public}d", socketId_);
164 static_cast<void>(::close(socketId_));
165 socketId_ = SOCKS5_INVALID_SOCKET_FD;
166 }
167 }
168
SocketRecvHandle(int socketId,std::pair<std::unique_ptr<char[]> &,int> & bufInfo,std::pair<sockaddr *,socklen_t> & addrInfo,const Socket::SocketExec::MessageCallback & callback)169 static bool SocketRecvHandle(int socketId, std::pair<std::unique_ptr<char[]> &, int> &bufInfo,
170 std::pair<sockaddr *, socklen_t> &addrInfo, const Socket::SocketExec::MessageCallback &callback)
171 {
172 const auto recvLen = recv(socketId, bufInfo.first.get(), bufInfo.second, 0);
173 if (recvLen > 0) {
174 return true;
175 }
176 const int32_t errCode{errno};
177 if ((errCode == EAGAIN) || (errCode == EINTR)) {
178 return true;
179 }
180 Socks5::Socks5Utils::PrintRecvErrMsg(socketId, errCode, recvLen, "SocketRecvHandle");
181
182 auto manager = callback.GetEventManager();
183 if (manager != nullptr) {
184 manager->GetProxyData()->OnProxySocketError();
185 } else {
186 NETSTACK_LOGE("manager is error");
187 }
188 return false;
189 }
190
GetProxySocketRecvCallback() const191 Socket::SocketExec::SocketRecvCallback Socks5Instance::GetProxySocketRecvCallback() const
192 {
193 return SocketRecvHandle;
194 }
195
RequestMethod(const std::vector<Socks5MethodType> & methods)196 bool Socks5Instance::RequestMethod(const std::vector<Socks5MethodType> &methods)
197 {
198 Socks5MethodRequest request{};
199 request.version_ = SOCKS5_VERSION;
200 request.methods_ = methods;
201
202 const socklen_t addrLen{Socks5Utils::GetAddressLen(options_->proxyAddress_.netAddress_)};
203 const std::pair<sockaddr *, socklen_t> addrInfo{options_->proxyAddress_.addr_, addrLen};
204 Socks5MethodResponse response{};
205 if (!Socks5Utils::RequestProxyServer(socks5Instance_, socketId_, addrInfo, &request, &response)) {
206 NETSTACK_LOGE("RequestMethod failed, socket: %{public}d", socketId_);
207 return false;
208 }
209 Socks5MethodType methodType{static_cast<Socks5MethodType>(response.method_)};
210 method_ = CreateSocks5MethodByType(methodType);
211 return true;
212 }
213
CreateSocks5MethodByType(Socks5MethodType type) const214 std::shared_ptr<Socks5Method> Socks5Instance::CreateSocks5MethodByType(Socks5MethodType type) const
215 {
216 if (type == Socks5MethodType::NO_AUTH) {
217 return std::make_shared<Socks5NoneMethod>(socks5Instance_);
218 } else if (type == Socks5MethodType::PASSWORD) {
219 return std::make_shared<Socks5PasswdMethod>(socks5Instance_);
220 } else if (type == Socks5MethodType::GSSAPI) {
221 NETSTACK_LOGE("socks5 instance not support GSSAPI now");
222 return nullptr;
223 } else {
224 NETSTACK_LOGE("socks5 instance no method type:%{public}d", static_cast<int32_t>(type));
225 return nullptr;
226 }
227 }
228
Socks5TcpInstance(int32_t socketId)229 Socks5TcpInstance::Socks5TcpInstance(int32_t socketId)
230 {
231 socketId_ = socketId;
232 }
233
Connect()234 bool Socks5TcpInstance::Connect()
235 {
236 NETSTACK_LOGD("socks5 tcp instance auth socket:%{public}d", socketId_);
237 UpdateErrorInfo(0, "");
238 if (state_ == Socks5AuthState::SUCCESS) {
239 NETSTACK_LOGD("socks5 tcp instance auth already socket:%{public}d", socketId_);
240 return true;
241 }
242 if (!ConnectProxy()) {
243 CloseSocket();
244 return false;
245 }
246 if (!DoConnect(Socks5Command::TCP_CONNECTION)) {
247 CloseSocket();
248 return false;
249 }
250 NETSTACK_LOGI("socks5 tcp instance auth successfully socket:%{public}d", socketId_);
251 return true;
252 }
253
RemoveHeader(void * data,size_t & len,int af)254 bool Socks5Instance::RemoveHeader(void *data, size_t &len, int af)
255 {
256 return false;
257 }
258
AddHeader()259 void Socks5Instance::AddHeader()
260 {
261 }
262
GetHeader()263 std::string Socks5Instance::GetHeader()
264 {
265 return std::string();
266 }
267
SetHeader(std::string header)268 void Socks5Instance::SetHeader(std::string header)
269 {
270 }
271
Close()272 void Socks5Instance::Close()
273 {
274 }
275
~Socks5UdpInstance()276 Socks5UdpInstance::~Socks5UdpInstance()
277 {
278 CloseSocket();
279 }
280
Connect()281 bool Socks5UdpInstance::Connect()
282 {
283 NETSTACK_LOGD("socks5 udp instance auth");
284 UpdateErrorInfo(0, "");
285
286 if (state_ == Socks5AuthState::SUCCESS) {
287 NETSTACK_LOGD("socks5 udp instance auth already");
288 return true;
289 }
290 if (!CreateSocket()) {
291 return false;
292 }
293 if (!ConnectProxy()) {
294 CloseSocket();
295 return false;
296 }
297 if (!DoConnect(Socks5Command::UDP_ASSOCIATE)) {
298 CloseSocket();
299 return false;
300 }
301 NETSTACK_LOGI("socks5 udp instance auth successfully socket:%{public}d", socketId_);
302 return true;
303 }
304
CreateSocket()305 bool Socks5UdpInstance::CreateSocket()
306 {
307 socketId_ = Socket::ExecCommonUtils::MakeTcpSocket(options_->proxyAddress_.netAddress_.GetSaFamily());
308 if (socketId_ == SOCKS5_INVALID_SOCKET_FD) {
309 NETSTACK_LOGE("socks5 udp instance fail to make tcp socket");
310 UpdateErrorInfo(Socks5Status::SOCKS5_MAKE_SOCKET_ERROR);
311 return false;
312 }
313
314 int keepalive = 1;
315 if (setsockopt(socketId_, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) < 0) {
316 NETSTACK_LOGE("socks5 udp instance fail to set keepalive");
317 return false;
318 }
319
320 return true;
321 }
322
RemoveHeader(void * data,size_t & len,int af)323 bool Socks5UdpInstance::RemoveHeader(void *data, size_t &len, int af)
324 {
325 size_t headerLen = af == AF_INET ? INET_SOCKS5_UDP_HEADER_LEN : INET6_SOCKS5_UDP_HEADER_LEN;
326 Socks5UdpHeader header{};
327
328 if (data == nullptr || !header.Deserialize(data, len)) {
329 NETSTACK_LOGE("not a valid socks5 udp header");
330 return false;
331 }
332
333 if (len < headerLen) {
334 NETSTACK_LOGE("fail to remove udp header");
335 return false;
336 }
337
338 len -= headerLen;
339
340 if (memmove_s(data, len, static_cast<uint8_t *>(data) + headerLen, len) != EOK) {
341 NETSTACK_LOGE("memory copy failed");
342 return false;
343 }
344
345 return true;
346 }
347
AddHeader()348 void Socks5UdpInstance::AddHeader()
349 {
350 const Socket::NetAddress::Family family{dest_.GetFamily()};
351 Socks5::Socks5AddrType addrType;
352
353 if (family == Socket::NetAddress::Family::IPv4) {
354 addrType = Socks5::Socks5AddrType::IPV4;
355 } else if (family == Socket::NetAddress::Family::IPv6) {
356 addrType = Socks5::Socks5AddrType::IPV6;
357 } else if (family == Socket::NetAddress::Family::DOMAIN_NAME) {
358 addrType = Socks5::Socks5AddrType::DOMAIN_NAME;
359 } else {
360 NETSTACK_LOGE("socks5 udp protocol address type error");
361 return ;
362 }
363
364 Socks5::Socks5UdpHeader header{};
365 header.addrType_ = addrType;
366 header.destAddr_ = dest_.GetAddress();
367 header.dstPort_ = dest_.GetPort();
368
369 SetHeader(header.Serialize());
370 }
371
SetHeader(std::string header)372 void Socks5UdpInstance::SetHeader(std::string header)
373 {
374 header_ = header;
375 }
376
Close()377 void Socks5UdpInstance::Close()
378 {
379 CloseSocket();
380 }
381
GetHeader()382 std::string Socks5UdpInstance::GetHeader()
383 {
384 return header_;
385 }
386
Socks5TlsInstance(int32_t socketId)387 Socks5TlsInstance::Socks5TlsInstance(int32_t socketId)
388 {
389 socketId_ = socketId;
390 }
391
Connect()392 bool Socks5TlsInstance::Connect()
393 {
394 NETSTACK_LOGD("socks5 tls instance auth socket:%{public}d", socketId_);
395 UpdateErrorInfo(0, "");
396 if (state_ == Socks5AuthState::SUCCESS) {
397 NETSTACK_LOGD("socks5 tls instance auth already socket:%{public}d", socketId_);
398 return true;
399 }
400 Socket::ExecCommonUtils::MakeNonBlock(socketId_);
401 if (!ConnectProxy()) {
402 CloseSocket();
403 return false;
404 }
405 if (!DoConnect(Socks5Command::TCP_CONNECTION)) {
406 CloseSocket();
407 return false;
408 }
409 NETSTACK_LOGI("socks5 tls instance auth successfully socket:%{public}d", socketId_);
410 return true;
411 }
412 } // Socks5
413 } // NetStack
414 } // OHOS
415