• 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_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