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