• 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_utils.h"
17 
18 #include <netinet/tcp.h>
19 #include <poll.h>
20 #include <sys/socket.h>
21 
22 #include "securec.h"
23 #include "netstack_log.h"
24 #include "socket_exec.h"
25 #include "socket_exec_common.h"
26 
27 namespace OHOS {
28 namespace NetStack {
29 namespace Socks5 {
GetAddressLen(const Socket::NetAddress & netAddress)30 socklen_t Socks5Utils::GetAddressLen(const Socket::NetAddress &netAddress)
31 {
32     const bool isIpv4{Socket::NetAddress::Family::IPv4 == netAddress.GetFamily()};
33     const socklen_t addrLen{isIpv4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6)};
34     return addrLen;
35 }
36 
Send(int32_t socketId,const char * data,size_t size,sockaddr * addr,socklen_t addrLen)37 bool Socks5Utils::Send(int32_t socketId, const char *data, size_t size, sockaddr *addr, socklen_t addrLen)
38 {
39     return PollSendData(socketId, data, size, addr, addrLen);
40 }
41 
Recv(int32_t socketId,sockaddr * addr,socklen_t addrLen)42 std::pair<bool, Socks5Buffer> Socks5Utils::Recv(int32_t socketId, sockaddr *addr, socklen_t addrLen)
43 {
44     const int32_t bufferSize = ConfirmBufferSize(socketId);
45     auto buf = std::make_unique<char[]>(bufferSize);
46     constexpr int32_t pollTimeout{500};
47     const int32_t timeoutMs = ConfirmSocketTimeoutMs(socketId, SO_RCVTIMEO, pollTimeout);
48     while (true) {
49         pollfd fds[1] = {{socketId, POLLIN, 0}};
50         const int ret = poll(fds, 1, timeoutMs);
51         if (ret < 0) {
52             if (errno == EINTR) {
53                 continue;
54             }
55             NETSTACK_LOGE("socks5 poll to recv failed, socket is %{public}d, errno is %{public}d", socketId, errno);
56             break;
57         } else if (ret == 0) {
58             continue;
59         }
60         socklen_t tempAddrLen{addrLen};
61         const int32_t recvLen = recvfrom(socketId, buf.get(), bufferSize, 0, addr, &tempAddrLen);
62         if (recvLen > 0) {
63             Socks5Buffer msg{};
64             msg.assign(buf.get(), recvLen);
65             return {true, msg};
66         }
67         const int32_t errCode{errno};
68         if ((errCode == EAGAIN) || (errCode == EINTR)) {
69             continue;
70         }
71         PrintRecvErrMsg(socketId, errCode, recvLen, "Recv");
72         break;
73     }
74     return {false, ""};
75 }
76 
PrintRecvErrMsg(int32_t socketId,const int32_t errCode,const int32_t recvLen,const std::string & tag)77 void Socks5Utils::PrintRecvErrMsg(int32_t socketId, const int32_t errCode, const int32_t recvLen,
78     const std::string &tag)
79 {
80     if ((errCode == 0) && (recvLen == 0)) {
81         NETSTACK_LOGI("[%{public}s] socks5 closed by peer, socket:%{public}d, recvLen:%{public}d", tag.c_str(),
82             socketId, recvLen);
83     } else {
84         NETSTACK_LOGE("[%{public}s] socks5 recv fail, socket:%{public}d, recvLen:%{public}d, errno:%{public}d",
85                       tag.c_str(), socketId, recvLen, errCode);
86     }
87 }
88 
RequestProxyServer(std::shared_ptr<Socks5Instance> & socks5Inst,std::int32_t socketId,const std::pair<sockaddr *,socklen_t> & addrInfo,Socks5Request * req,Socks5Response * rsp)89 bool Socks5Utils::RequestProxyServer(std::shared_ptr<Socks5Instance> &socks5Inst, std::int32_t socketId,
90     const std::pair<sockaddr *, socklen_t> &addrInfo, Socks5Request *req, Socks5Response *rsp)
91 {
92     if ((req == nullptr) || (rsp == nullptr)) {
93         NETSTACK_LOGE("socks5 req or rsp is null, socket is %{public}d", socketId);
94         return false;
95     }
96     const Socks5Buffer msg{req->Serialize()};
97     const size_t msgSize{msg.size()};
98     if (msgSize == 0U) {
99         socks5Inst->UpdateErrorInfo(Socks5Status::SOCKS5_SERIALIZE_ERROR);
100         NETSTACK_LOGE("socks5 fail to serialize, socket is %{public}d", socketId);
101         return false;
102     }
103     sockaddr *addr{addrInfo.first};
104     const socklen_t addrLen{addrInfo.second};
105     if (!Socks5Utils::Send(socketId, msg.data(), msgSize, addr, addrLen)) {
106         socks5Inst->UpdateErrorInfo(Socks5Status::SOCKS5_FAIL_TO_SEND_MSG);
107         NETSTACK_LOGE("socks5 fail to send message, socket is %{public}d", socketId);
108         return false;
109     }
110 
111     std::pair<bool, Socks5Buffer> result = Socks5Utils::Recv(socketId, addr, addrLen);
112     if (!result.first) {
113         socks5Inst->UpdateErrorInfo(Socks5Status::SOCKS5_FAIL_TO_RECV_MSG);
114         NETSTACK_LOGE("socks5 fail to recv message, socket is %{public}d", socketId);
115         return false;
116     }
117 
118     if (!rsp->Deserialize(result.second.data(), result.second.size())) {
119         socks5Inst->UpdateErrorInfo(Socks5Status::SOCKS5_DESERIALIZE_ERROR);
120         NETSTACK_LOGE("socks5 fail to deserialize, socket is %{public}d", socketId);
121         return false;
122     }
123     return true;
124 }
125 
GetStatusMessage(Socks5Status status)126 std::string Socks5Utils::GetStatusMessage(Socks5Status status)
127 {
128     auto iter = g_errStatusMap.find(status);
129     if (iter != g_errStatusMap.end()) {
130         return iter->second;
131     }
132     return "Unknown status.";
133 }
134 
SetProxyAuthError(BaseContext * context,std::shared_ptr<Socks5::Socks5Instance> & socks5Inst)135 void Socks5Utils::SetProxyAuthError(BaseContext *context, std::shared_ptr<Socks5::Socks5Instance> &socks5Inst)
136 {
137     const int32_t errCode = socks5Inst->GetErrorCode();
138     const std::string errMsg = socks5Inst->GetErrorMessage();
139     NETSTACK_LOGE("socks5 auth failed, errCode:%{public}d, errMsg::%{public}s", errCode, errMsg.c_str());
140     context->SetError(errCode, errMsg);
141 }
142 }  // Socks5
143 }  // NetStack
144 }  // OHOS
145