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