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_package.h"
17
18 #include <netinet/in.h>
19
20 #include "netstack_log.h"
21 #include "socks5_instance.h"
22 #include "socks5_none_method.h"
23 #include "socks5_passwd_method.h"
24 #include "socks5_utils.h"
25 #include "securec.h"
26
27 namespace OHOS {
28 namespace NetStack {
29 namespace Socks5 {
30
31 /*
32 +----+----------+----------+
33 |VER | NMETHODS | METHODS |
34 +----+----------+----------+
35 | 1 | 1 | 1 to 255 |
36 +----+----------+----------+ */
Serialize()37 std::string Socks5MethodRequest::Serialize()
38 {
39 std::string serialized;
40 serialized.resize(2 + methods_.size()); // 2 = VER + NMETHODS
41 serialized[0] = version_;
42 serialized[1] = static_cast<uint8_t>(methods_.size());
43
44 size_t pos = 2;
45 for (const auto& method : methods_) {
46 serialized[pos++] = static_cast<uint8_t>(method);
47 }
48
49 return serialized;
50 }
51
52 /*
53 +----+--------+
54 |VER | METHOD |
55 +----+--------+
56 | 1 | 1 |
57 +----+--------+ */
Deserialize(const void * data,size_t len)58 bool Socks5MethodResponse::Deserialize(const void *data, size_t len)
59 {
60 if (len < 2) { // 2 = VER + METHOD
61 return false;
62 }
63
64 const uint8_t *buffer = static_cast<const uint8_t*>(data);
65 version_ = buffer[0];
66 method_ = buffer[1];
67
68 return true;
69 }
70
71 /*
72 +----+------+----------+------+----------+
73 |VER | ULEN | UNAME | PLEN | PASSWD |
74 +----+------+----------+------+----------+
75 | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
76 +----+------+----------+------+----------+ */
Serialize()77 std::string Socks5AuthRequest::Serialize()
78 {
79 std::string serialized;
80 serialized.resize(3 + username_.length() + password_.length()); // 3 = VER + ULEN + PLEN
81 serialized[0] = version_;
82 serialized[1] = static_cast<uint8_t>(username_.length());
83
84 size_t pos = 2;
85 if (memcpy_s(&serialized[pos], serialized.size() - pos, username_.c_str(), username_.length()) != EOK) {
86 NETSTACK_LOGE("memcpy_s failed!");
87 return "";
88 }
89
90 pos += username_.length();
91 serialized[pos++] = static_cast<uint8_t>(password_.length());
92 if (memcpy_s(&serialized[pos], serialized.size() - pos, password_.c_str(), password_.length()) != EOK) {
93 NETSTACK_LOGE("memcpy_s failed!");
94 return "";
95 }
96
97 return serialized;
98 }
99
100 /*
101 +----+--------+
102 |VER | STATUS |
103 +----+--------+
104 | 1 | 1 |
105 +----+--------+ */
Deserialize(const void * data,size_t len)106 bool Socks5AuthResponse::Deserialize(const void *data, size_t len)
107 {
108 if (len < 2) { // 2 = VER + STATUS
109 return false;
110 }
111
112 const uint8_t *buffer = static_cast<const uint8_t*>(data);
113 version_ = buffer[0];
114 status_ = buffer[1];
115
116 return true;
117 }
118
CopyAddrToStr(Socks5AddrType addrType,std::string & destAddr,std::string & serialized,size_t pos)119 static int CopyAddrToStr(Socks5AddrType addrType, std::string &destAddr, std::string &serialized, size_t pos)
120 {
121 switch (addrType) {
122 case Socks5AddrType::IPV4: {
123 struct in_addr ipv4Address;
124 if (inet_pton(AF_INET, destAddr.c_str(), &ipv4Address) <= 0) {
125 NETSTACK_LOGE("inet_pton failed!");
126 return -1;
127 }
128 if (memcpy_s(&serialized[pos], serialized.size() - pos, &ipv4Address, sizeof(ipv4Address)) != EOK) {
129 NETSTACK_LOGE("memcpy_s failed!");
130 return -1;
131 }
132 return pos + sizeof(ipv4Address);
133 }
134 case Socks5AddrType::DOMAIN_NAME: {
135 uint8_t domainLength = static_cast<uint8_t>(destAddr.length());
136 serialized[pos] = domainLength;
137 if (memcpy_s(&serialized[pos + 1], serialized.size() - pos - 1, destAddr.c_str(), domainLength) != EOK) {
138 NETSTACK_LOGE("memcpy_s failed!");
139 return -1;
140 }
141 return pos + 1 + domainLength;
142 }
143 case Socks5AddrType::IPV6: {
144 struct in6_addr ipv6Address;
145 if (inet_pton(AF_INET6, destAddr.c_str(), &ipv6Address) <= 0) {
146 NETSTACK_LOGE("inet_pton failed!");
147 return -1;
148 }
149 if (memcpy_s(&serialized[pos], serialized.size() - pos, &ipv6Address, sizeof(ipv6Address)) != EOK) {
150 NETSTACK_LOGE("memcpy_s failed!");
151 return -1;
152 }
153 return pos + sizeof(ipv6Address);
154 }
155 }
156 return -1;
157 }
158
ResizeStrByAType(Socks5AddrType addrType,std::string & destAddr,size_t otherLen,std::string & serialized)159 static void ResizeStrByAType(Socks5AddrType addrType, std::string &destAddr, size_t otherLen,
160 std::string &serialized)
161 {
162 switch (addrType) {
163 case Socks5AddrType::IPV4:
164 serialized.resize(otherLen + IPV4_LEN);
165 break;
166 case Socks5AddrType::DOMAIN_NAME:
167 serialized.resize(otherLen + destAddr.length() + 1); // 1: size of DOMAIN_LEN
168 break;
169 case Socks5AddrType::IPV6:
170 serialized.resize(otherLen + IPV6_LEN);
171 break;
172 }
173 }
174
175 /*
176 +----+-----+-------+------+----------+----------+
177 |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
178 +----+-----+-------+------+----------+----------+
179 | 1 | 1 | X'00' | 1 | Variable | 2 |
180 +----+-----+-------+------+----------+----------+ */
Serialize()181 std::string Socks5ProxyRequest::Serialize()
182 {
183 int excludeStrLen = 6; // 6 = VER + CMD + RSV + ATYP + DST.PORT
184 std::string serialized;
185
186 ResizeStrByAType(addrType_, destAddr_, excludeStrLen, serialized);
187
188 serialized[0] = version_;
189 serialized[1] = static_cast<uint8_t>(cmd_);
190 serialized[2] = reserved_; // 2: RSV
191 serialized[3] = static_cast<uint8_t>(addrType_); // 3: ATYP
192
193 int pos = CopyAddrToStr(addrType_, destAddr_, serialized, 4); // 4: DST.ADDR
194 if (pos < 0) {
195 return "";
196 }
197
198 uint16_t netPort = htons(destPort_);
199 if (memcpy_s(&serialized[pos], serialized.size() - pos, &netPort, sizeof(netPort)) != EOK) {
200 NETSTACK_LOGE("memcpy_s failed!");
201 return "";
202 }
203
204 return serialized;
205 }
206
GetAddrLen(Socks5AddrType addrType,const uint8_t * buffer,size_t domainLenIdx)207 static size_t GetAddrLen(Socks5AddrType addrType, const uint8_t *buffer, size_t domainLenIdx)
208 {
209 switch (addrType) {
210 case Socks5AddrType::IPV4:
211 return IPV4_LEN;
212 case Socks5AddrType::DOMAIN_NAME:
213 return buffer[domainLenIdx] + 1; // DOMAIN_LEN + DOMAIN
214 case Socks5AddrType::IPV6:
215 return IPV6_LEN;
216 }
217 return 0;
218 }
219
GetAddrStr(Socks5AddrType addrType,const uint8_t * buffer,size_t hdrLen,size_t domainIdx,std::string & destAddr)220 static void GetAddrStr(Socks5AddrType addrType, const uint8_t *buffer, size_t hdrLen,
221 size_t domainIdx, std::string &destAddr)
222 {
223 switch (addrType) {
224 case Socks5AddrType::IPV4: {
225 char ipv4Str[INET_ADDRSTRLEN];
226 inet_ntop(AF_INET, &buffer[hdrLen], ipv4Str, sizeof(ipv4Str));
227 destAddr = ipv4Str;
228 break;
229 }
230 case Socks5AddrType::DOMAIN_NAME: {
231 uint8_t domainLength = buffer[hdrLen];
232 destAddr.assign(reinterpret_cast<const char *>(&buffer[domainIdx]), domainLength);
233 break;
234 }
235 case Socks5AddrType::IPV6: {
236 char ipv6Str[INET6_ADDRSTRLEN];
237 inet_ntop(AF_INET6, &buffer[hdrLen], ipv6Str, sizeof(ipv6Str));
238 destAddr = ipv6Str;
239 break;
240 }
241 }
242 }
243
244 /*
245 +----+-----+-------+------+----------+----------+
246 |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
247 +----+-----+-------+------+----------+----------+
248 | 1 | 1 | X'00' | 1 | Variable | 2 |
249 +----+-----+-------+------+----------+----------+ */
Deserialize(const void * data,size_t len)250 bool Socks5ProxyResponse::Deserialize(const void *data, size_t len)
251 {
252 const int hdrLen = 4; // 4 = VER + REP + RSV + ATYP
253 if (len < hdrLen + 2) { // 2 = PORT
254 return false;
255 }
256
257 const uint8_t *buffer = static_cast<const uint8_t*>(data);
258
259 version_ = buffer[0];
260 status_ = buffer[1];
261 reserved_ = buffer[2]; // 2: index of RSV
262 addrType_ = static_cast<Socks5AddrType>(buffer[3]); // 3: index of ATYP
263
264 size_t addrLen = GetAddrLen(addrType_, buffer, 4); // 4: index of domain len
265 if (addrLen == 0 || len < hdrLen + addrLen + 2) { // 2: PORT size
266 return false;
267 }
268
269 GetAddrStr(addrType_, buffer, hdrLen, 5, destAddr_); // 5: index of DOMAIN
270 destPort_ = (buffer[len - 2] << 8) | buffer[len - 1]; // 8: char bits, 2: port size
271 return true;
272 }
273
274 /*
275 +----+------+------+----------+----------+----------+
276 |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
277 +----+------+------+----------+----------+----------+
278 | 2 | 1 | 1 | Variable | 2 | Variable |
279 +----+------+------+----------+----------+----------+ */
Serialize()280 std::string Socks5UdpHeader::Serialize()
281 {
282 int excludeStrLen = 6; // 6 = RSV + FRAG + ATYP + DST.PORT
283 std::string serialized;
284 ResizeStrByAType(addrType_, destAddr_, excludeStrLen, serialized);
285
286 if (memcpy_s(&serialized[0], serialized.size(), &reserved_, sizeof(reserved_)) != EOK) {
287 NETSTACK_LOGE("memcpy_s failed!");
288 return "";
289 }
290 serialized[2] = frag_; // 2: FRAG
291 serialized[3] = static_cast<uint8_t>(addrType_); // 3: ATYP
292
293 int pos = CopyAddrToStr(addrType_, destAddr_, serialized, 4); // 4: DST.ADDR
294 if (pos < 0) {
295 return "";
296 }
297
298 uint16_t netPort = htons(dstPort_);
299 if (memcpy_s(&serialized[pos], serialized.size() - pos, &netPort, sizeof(netPort)) != EOK) {
300 NETSTACK_LOGE("memcpy_s failed!");
301 return "";
302 }
303
304 return serialized;
305 }
306
307 /*
308 +----+------+------+----------+----------+----------+
309 |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
310 +----+------+------+----------+----------+----------+
311 | 2 | 1 | 1 | Variable | 2 | Variable |
312 +----+------+------+----------+----------+----------+ */
Deserialize(const void * data,size_t len)313 bool Socks5UdpHeader::Deserialize(const void *data, size_t len)
314 {
315 const int hdrLen = 4; // 4 = RSV + FRAG + ATYP
316 const uint8_t *buffer = static_cast<const uint8_t*>(data);
317 if ((len < hdrLen + 2) || (buffer[2] | buffer[1] | (buffer[0] != 0))) { // 2: index of FRAG
318 return false;
319 }
320
321 addrType_ = static_cast<Socks5AddrType>(buffer[3]); // 3: index of ATYP
322
323 size_t addrLen = GetAddrLen(addrType_, buffer, 4); // 4: index of domain len
324 if (addrLen == 0 || len < hdrLen + addrLen + 2) { // 2: port size
325 return false;
326 }
327
328 GetAddrStr(addrType_, buffer, hdrLen, 5, destAddr_); // 5: index of DOMAIN
329 dstPort_ = (buffer[len - 2] << 8) | buffer[len - 1]; // 8: char bits, 2: port size
330 return true;
331 }
332
333 } // Socks5
334 } // NetStack
335 } // OHOS