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 <sys/time.h>
17 #include <algorithm>
18 #include <arpa/inet.h>
19 #include <cerrno>
20 #include <csignal>
21 #include <cstring>
22 #include <fcntl.h>
23 #include <iostream>
24 #include <netdb.h>
25 #include <poll.h>
26 #include <random>
27 #include <securec.h>
28 #include <sstream>
29 #include <sys/socket.h>
30 #include <thread>
31 #include <unistd.h>
32 #include <vector>
33
34 #include "netmanager_base_log.h"
35 #include "net_pac_local_proxy_server.h"
36 #include "netmanager_base_common_utils.h"
37 #include "securec.h"
38
39 namespace OHOS {
40 namespace NetManagerStandard {
41 namespace {
42 constexpr int HTTPS_PORT = 443;
43 constexpr int HTTP_PORT = 80;
44 constexpr int TIME_OUT = 30;
45 constexpr int TIME_OUT_S = 10;
46 constexpr int THREAD_COUNT = 4;
47 constexpr int BUFFER_SIZE = 8192;
48 constexpr int BACKLOG = 128;
49 constexpr int MAX_HEADER_SIZE = 8192;
50 constexpr int MS_1 = 1000;
51 constexpr const char DEFAULT_URL[] = "127.0.0.1";
52 constexpr const char CONNECT_STR[] = "CONNECT";
53 constexpr const char PROTOCOL_SEPARATOR[] = "://";
54 constexpr const char HTTPS_PREFIX[] = "https://";
55 constexpr const char HTTP_PREFIX[] = "http://";
56 constexpr const char HOST_STR[] = "Host: ";
57 constexpr const char COLON_STR[] = ":";
58 constexpr const char SPACE_STR[] = " ";
59 constexpr const char PATH_STR[] = "/";
60 constexpr const char EMPTY_STR[] = "";
61 constexpr const char WHITESPACE_STR[] = " \t";
62 constexpr const char CRLF[] = "\r\n";
63 constexpr const char CRLF2[] = "\r\n\r\n";
64 constexpr const char HTTP_1_1_200[] = "HTTP/1.1 200";
65 constexpr const char HTTP_1_1[] = " HTTP/1.1\r\n";
66 constexpr const char PROXY_CONNECTION[] = "Proxy-Connection: Keep-Alive\r\n\r\n";
67 constexpr const char HTTP_1_1_400[] = "HTTP/1.1 400 Bad Request\r\n\r\n";
68 constexpr const char HTTP_1_1_502[] = "HTTP/1.1 502 Bad Gateway\r\n\r\n";
69 constexpr const char HTTP_1_1_200_CONNECTED[] = "HTTP/1.1 200 Connection Established\r\n\r\n";
70 constexpr const char DIRECT_STR[] = "DIRECT";
71 constexpr const char SOCKS_STR[] = "SOCKS";
72 constexpr const char SOCK5_STR[] = "SOCK5";
73 constexpr const char SOCK4_STR[] = "SOCK4";
74 constexpr const char PROXY_STR[] = "PROXY";
75 constexpr const char HTTP_STR[] = "HTTP";
76 constexpr const char HTTPS_STR[] = "HTTPS";
77 constexpr char SPACE_CHAR = ' ';
78 constexpr char COLON_CHAR = ':';
79 constexpr char PATH_CHAR = '/';
80 constexpr char NULL_CHAR = '\0';
81 constexpr char SEMICOLON_CHAR = ';';
82 } // namespace
83
ProxyServer(int port,int numThreads)84 ProxyServer::ProxyServer(int port, int numThreads)
85 : port_(port), serverSocket_(-1), numThreads_(numThreads), running_(false)
86 {
87 if (numThreads_ <= 0) {
88 numThreads_ = static_cast<size_t>(std::thread::hardware_concurrency());
89 if (numThreads_ <= 0) {
90 numThreads_ = THREAD_COUNT;
91 }
92 }
93 }
94
~ProxyServer()95 ProxyServer::~ProxyServer()
96 {
97 Stop();
98 }
99
SendAll(int sockfd,const void * buffer,size_t length,int32_t flag)100 ssize_t ProxyServer::SendAll(int sockfd, const void* buffer, size_t length, int32_t flag)
101 {
102 const char* ptr = static_cast<const char*>(buffer);
103 size_t totalSent = 0;
104 while (totalSent < length) {
105 ssize_t sent = send(sockfd, ptr + totalSent, length - totalSent, flag);
106 if (sent < 0) {
107 if (errno == EINTR) {
108 continue;
109 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
110 usleep(MS_1);
111 continue;
112 } else {
113 return -1;
114 }
115 } else if (sent == 0) {
116 break;
117 }
118 totalSent += static_cast<size_t>(sent);
119 }
120 return totalSent;
121 }
122
SetFindPacProxyFunction(std::function<std::string (std::string,std::string)> pac)123 void ProxyServer::SetFindPacProxyFunction(std::function<std::string(std::string, std::string)> pac)
124 {
125 pacFunction_ = pac;
126 }
127
Start()128 bool ProxyServer::Start()
129 {
130 if (running_) {
131 return false;
132 }
133 serverSocket_ = socket(AF_INET, SOCK_STREAM, 0);
134 if (serverSocket_ < 0) {
135 NETMGR_LOG_E("create socket fail");
136 return false;
137 }
138 int opt = 1;
139 if (setsockopt(serverSocket_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
140 NETMGR_LOG_E("set socket SO_REUSEADDR fail");
141 close(serverSocket_);
142 serverSocket_ = -1;
143 return false;
144 }
145 int flags = fcntl(serverSocket_, F_GETFL, 0);
146 if (flags < 0 || fcntl(serverSocket_, F_SETFL, static_cast<unsigned short>(flags) | O_NONBLOCK) < 0) {
147 NETMGR_LOG_E("set socket O_NONBLOCK fail");
148 close(serverSocket_);
149 serverSocket_ = -1;
150 return false;
151 }
152 sockaddr_in serverAddr;
153 serverAddr.sin_family = AF_INET;
154 inet_pton(AF_INET, DEFAULT_URL, &(serverAddr.sin_addr));
155 serverAddr.sin_port = htons(port_);
156 if (bind(serverSocket_, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
157 close(serverSocket_);
158 serverSocket_ = -1;
159 return false;
160 }
161 if (listen(serverSocket_, BACKLOG) < 0) {
162 close(serverSocket_);
163 serverSocket_ = -1;
164 return false;
165 }
166 running_ = true;
167 for (int i = 0; i < numThreads_; i++) {
168 workers_.push_back(std::thread(&ProxyServer::WorkerThread, this));
169 }
170 acceptThread_ = std::thread(&ProxyServer::AcceptLoop, this);
171 return true;
172 }
173
Stop()174 void ProxyServer::Stop()
175 {
176 if (!running_) {
177 return;
178 }
179 running_ = false;
180 queueCondition_.notify_all();
181 if (acceptThread_.joinable()) {
182 acceptThread_.join();
183 }
184 for (auto &worker : workers_) {
185 if (worker.joinable()) {
186 worker.join();
187 }
188 }
189 workers_.clear();
190 {
191 std::lock_guard<std::mutex> lock(queueMutex_);
192 while (!taskQueue_.empty()) {
193 close(taskQueue_.front().clientSocket_);
194 taskQueue_.pop();
195 }
196 }
197 if (serverSocket_ >= 0) {
198 close(serverSocket_);
199 serverSocket_ = -1;
200 }
201 }
202
IsRunning() const203 bool ProxyServer::IsRunning() const
204 {
205 return running_;
206 }
207
GetRequestMethod(const std::string & header)208 std::string ProxyServer::GetRequestMethod(const std::string &header)
209 {
210 size_t spacePos = header.find(SPACE_CHAR);
211 if (spacePos == std::string::npos)
212 return EMPTY_STR;
213 return header.substr(0, spacePos);
214 }
215
ParseConnectRequest(const std::string & header,std::string & host,int & port)216 bool ProxyServer::ParseConnectRequest(const std::string &header, std::string &host, int &port)
217 {
218 size_t methodEnd = header.find(SPACE_CHAR);
219 if (methodEnd == std::string::npos)
220 return false;
221 size_t hostStart = methodEnd + 1;
222 size_t hostEnd = header.find(SPACE_CHAR, hostStart);
223 if (hostEnd == std::string::npos)
224 return false;
225 std::string hostPort = header.substr(hostStart, hostEnd - hostStart);
226 size_t colonPos = hostPort.find(COLON_CHAR);
227 if (colonPos != std::string::npos) {
228 host = hostPort.substr(0, colonPos);
229 port = CommonUtils::StrToInt(hostPort.substr(colonPos + 1));
230 } else {
231 host = hostPort;
232 port = HTTPS_PORT;
233 }
234 return true;
235 }
236
ParseHttpRequest(const std::string & header,std::string & host,int & port)237 bool ProxyServer::ParseHttpRequest(const std::string &header, std::string &host, int &port)
238 {
239 size_t hostPos = header.find(HOST_STR);
240 if (hostPos == std::string::npos)
241 return false;
242 size_t hostEnd = header.find(CRLF, hostPos);
243 if (hostEnd == std::string::npos)
244 return false;
245 std::string hostLine = header.substr(hostPos + 6, hostEnd - hostPos - 6);
246 size_t colonPos = hostLine.find(COLON_CHAR);
247 if (colonPos != std::string::npos) {
248 host = hostLine.substr(0, colonPos);
249 port = CommonUtils::StrToInt(hostLine.substr(colonPos + 1));
250 } else {
251 host = hostLine;
252 port = HTTP_PORT;
253 }
254 return true;
255 }
256
TunnelData(int client,int server)257 void ProxyServer::TunnelData(int client, int server)
258 {
259 struct pollfd fds[2];
260 fds[0].fd = client;
261 fds[0].events = POLLIN;
262 fds[1].fd = server;
263 fds[1].events = POLLIN;
264 char buffer[BUFFER_SIZE];
265 bool clientClosed = false;
266 bool serverClosed = false;
267 while (!clientClosed && !serverClosed && running_) {
268 int ret = poll(fds, 2, 1000);
269 if (ret < 0) {
270 if (errno == EINTR)
271 continue;
272 NETMGR_LOG_E("socket poll fail");
273 break;
274 }
275 if (ret == 0)
276 continue;
277 if ((static_cast<unsigned short>(fds[0].revents) & (POLLHUP | POLLERR)) ||
278 (static_cast<unsigned short>(fds[1].revents) & (POLLHUP | POLLERR)))
279 break;
280 if (fds[0].revents & POLLIN) {
281 int n = recv(client, buffer, BUFFER_SIZE, 0);
282 if (n <= 0) {
283 clientClosed = true;
284 continue;
285 }
286 if (SendAll(server, buffer, n, 0) <= 0) {
287 serverClosed = true;
288 continue;
289 }
290 }
291 if (static_cast<unsigned short>(fds[1].revents) & POLLIN) {
292 int n = recv(server, buffer, BUFFER_SIZE, 0);
293 if (n <= 0) {
294 serverClosed = true;
295 continue;
296 }
297 if (SendAll(client, buffer, n, 0) <= 0) {
298 clientClosed = true;
299 continue;
300 }
301 }
302 }
303 }
304
ReceiveResponseHeader(int socket)305 std::string ProxyServer::ReceiveResponseHeader(int socket)
306 {
307 std::string header;
308 char buffer[BUFFER_SIZE];
309 int bytesRead;
310 bool headerComplete = false;
311 while (!headerComplete && header.size() < MAX_HEADER_SIZE) {
312 bytesRead = recv(socket, buffer, sizeof(buffer) - 1, 0);
313 if (bytesRead > 0) {
314 buffer[bytesRead] = '\0';
315 header.append(buffer, bytesRead);
316 if (header.find(CRLF2) != std::string::npos) {
317 headerComplete = true;
318 }
319 } else if (bytesRead == 0) {
320 NETMGR_LOG_W("Connection closed while receiving header, got %{private}zu bytes", header.size());
321 break;
322 } else {
323 if (errno == EINTR) {
324 continue;
325 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
326 NETMGR_LOG_W("Socket timeout while receiving header");
327 break;
328 } else {
329 NETMGR_LOG_E("recv error while receiving header: %{private}s", strerror(errno));
330 break;
331 }
332 }
333 }
334 if (header.size() >= MAX_HEADER_SIZE && !headerComplete) {
335 NETMGR_LOG_W("Header size limit reached without finding complete header");
336 }
337 return header;
338 }
339
ConnectToServer(const std::string & host,int port)340 int ProxyServer::ConnectToServer(const std::string &host, int port)
341 {
342 struct addrinfo hints;
343 struct addrinfo *result;
344 struct addrinfo *rp;
345 int serverSocket = -1;
346 memset_s(&hints, sizeof(struct addrinfo), 0, sizeof(hints));
347 hints.ai_family = AF_UNSPEC;
348 hints.ai_socktype = SOCK_STREAM;
349 hints.ai_protocol = IPPROTO_TCP;
350 std::string portStr = std::to_string(port);
351 int status = getaddrinfo(host.c_str(), portStr.c_str(), &hints, &result);
352 if (status != 0) {
353 NETMGR_LOG_E("getaddrinfo fail: %s", gai_strerror(status));
354 return -1;
355 }
356 for (rp = result; rp != nullptr; rp = rp->ai_next) {
357 serverSocket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
358 if (serverSocket < 0) {
359 continue;
360 }
361 struct timeval timeout;
362 timeout.tv_sec = TIME_OUT_S;
363 timeout.tv_usec = 0;
364 if (setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0 ||
365 setsockopt(serverSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
366 NETMGR_LOG_E("set socket timeout fail: %s", strerror(errno));
367 close(serverSocket);
368 serverSocket = -1;
369 continue;
370 }
371 if (connect(serverSocket, rp->ai_addr, rp->ai_addrlen) == 0) {
372 break;
373 }
374 close(serverSocket);
375 serverSocket = -1;
376 }
377 freeaddrinfo(result);
378 if (serverSocket < 0) {
379 NETMGR_LOG_E("connect to %s:%d fail", host.c_str(), port);
380 return -1;
381 }
382 return serverSocket;
383 }
384
ConnectViaUpstreamProxy(const std::string & targetHost,int targetPort,const std::string & originalRequest,std::string proxyHost,int proxyPort)385 int ProxyServer::ConnectViaUpstreamProxy(const std::string &targetHost, int targetPort,
386 const std::string &originalRequest, std::string proxyHost, int proxyPort)
387 {
388 int proxySocket = ConnectToServer(proxyHost, proxyPort);
389 if (proxySocket < 0) {
390 NETMGR_LOG_E("connect upstream proxy fail %{private}s:%{private}d", proxyHost.c_str(), proxyPort);
391 return -1;
392 }
393 if (SendAll(proxySocket, originalRequest.c_str(), originalRequest.length(), 0) < 0) {
394 close(proxySocket);
395 return -1;
396 }
397 return proxySocket;
398 }
399
ConnectViaUpstreamProxyHttps(const std::string & targetHost,int targetPort,std::string proxyHost,int proxyPort)400 int ProxyServer::ConnectViaUpstreamProxyHttps(const std::string &targetHost, int targetPort, std::string proxyHost,
401 int proxyPort)
402 {
403 int proxySocket = ConnectToServer(proxyHost, proxyPort);
404 if (proxySocket < 0) {
405 NETMGR_LOG_E("connect upproxy fail %{private}s:%{private}d fail", proxyHost.c_str(), proxyPort);
406 return -1;
407 }
408 std::ostringstream connectRequest;
409 connectRequest << CONNECT_STR << SPACE_STR << targetHost << COLON_STR << targetPort << HTTP_1_1
410 << HOST_STR << targetHost << COLON_STR << targetPort << CRLF << PROXY_CONNECTION;
411 std::string requestStr = connectRequest.str();
412 if (SendAll(proxySocket, requestStr.c_str(), requestStr.length(), 0) < 0) {
413 NETMGR_LOG_E("send CONNECT to upstream proxy fail ");
414 close(proxySocket);
415 return -1;
416 }
417 std::string response = ReceiveResponseHeader(proxySocket);
418 if (response.empty() || response.find(HTTP_1_1_200) == std::string::npos) {
419 close(proxySocket);
420 return -1;
421 }
422 return proxySocket;
423 }
424
GetRequestUrl(const std::string & header)425 std::string ProxyServer::GetRequestUrl(const std::string &header)
426 {
427 std::string method = GetRequestMethod(header);
428 std::string url;
429 if (method == CONNECT_STR) {
430 size_t methodEnd = header.find(SPACE_CHAR);
431 if (methodEnd == std::string::npos)
432 return EMPTY_STR;
433 size_t hostStart = methodEnd + 1;
434 size_t hostEnd = header.find(SPACE_CHAR, hostStart);
435 if (hostEnd == std::string::npos)
436 return EMPTY_STR;
437 std::string hostPort = header.substr(hostStart, hostEnd - hostStart);
438 url = HTTPS_PREFIX + hostPort;
439 } else {
440 size_t methodEnd = header.find(SPACE_CHAR);
441 if (methodEnd == std::string::npos)
442 return EMPTY_STR;
443 size_t pathStart = methodEnd + 1;
444 size_t pathEnd = header.find(SPACE_CHAR, pathStart);
445 if (pathEnd == std::string::npos)
446 return EMPTY_STR;
447 std::string path = header.substr(pathStart, pathEnd - pathStart);
448 if (path.find(PROTOCOL_SEPARATOR) != std::string::npos) {
449 return path;
450 }
451 std::string host;
452 int port = HTTP_PORT;
453 if (!ParseHttpRequest(header, host, port)) {
454 return path;
455 }
456 url = HTTP_PREFIX;
457 url += host;
458 if (port != HTTP_PORT) {
459 url += COLON_STR + std::to_string(port);
460 }
461 if (!path.empty() && path[0] != PATH_CHAR) {
462 url += PATH_STR;
463 }
464 url += path;
465 }
466 return url;
467 }
468
GetProxyList(std::string url,std::string host,std::vector<ProxyConfig> & proxyList)469 void ProxyServer::GetProxyList(std::string url, std::string host, std::vector<ProxyConfig> &proxyList)
470 {
471 std::string pacScript;
472 if (pacFunction_) {
473 pacScript = pacFunction_(url, host);
474 }
475 if (pacScript.empty()) {
476 return;
477 }
478 ParsePacResult(pacScript, proxyList);
479 }
480
ParsePacResult(const std::string & pacResult,std::vector<ProxyConfig> & proxyList)481 void ProxyServer::ParsePacResult(const std::string &pacResult, std::vector<ProxyConfig> &proxyList)
482 {
483 proxyList.clear();
484 if (pacResult.empty()) {
485 return;
486 }
487 std::istringstream stream(pacResult);
488 std::string rule;
489 while (std::getline(stream, rule, SEMICOLON_CHAR)) {
490 rule.erase(0, rule.find_first_not_of(WHITESPACE_STR));
491 rule.erase(rule.find_last_not_of(WHITESPACE_STR) + 1);
492 if (rule.empty()) {
493 continue;
494 }
495 ProxyConfig config;
496 size_t spacePos = rule.find(SPACE_CHAR);
497 if (spacePos == std::string::npos) {
498 config.type = rule;
499 if (config.type == DIRECT_STR) {
500 config.host = EMPTY_STR;
501 config.port = 0;
502 proxyList.push_back(config);
503 }
504 continue;
505 }
506 config.type = rule.substr(0, spacePos);
507 if (config.type == DIRECT_STR) {
508 config.host = EMPTY_STR;
509 config.port = 0;
510 proxyList.push_back(config);
511 continue;
512 }
513 size_t hostStart = rule.find_first_not_of(WHITESPACE_STR, spacePos);
514 if (hostStart == std::string::npos) {
515 continue;
516 }
517 std::string hostPort = rule.substr(hostStart);
518 size_t colonPos = hostPort.find(COLON_CHAR);
519 if (colonPos == std::string::npos) {
520 config.host = hostPort;
521 } else {
522 config.host = hostPort.substr(0, colonPos);
523 config.port = CommonUtils::StrToInt(hostPort.substr(colonPos + 1));
524 if (config.port == -1) {
525 config.port = 0;
526 NETMGR_LOG_E("pac config port paser fail");
527 }
528 }
529 proxyList.push_back(config);
530 }
531 }
532
ReadRequestHeader(int clientSocket,std::string & requestHeader)533 bool ProxyServer::ReadRequestHeader(int clientSocket, std::string &requestHeader)
534 {
535 char buffer[BUFFER_SIZE];
536 struct timeval timeout;
537 timeout.tv_sec = TIME_OUT;
538 timeout.tv_usec = 0;
539 if (setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
540 return false;
541 }
542 int bytesReceived = 0;
543 while ((bytesReceived = recv(clientSocket, buffer, BUFFER_SIZE - 1, 0)) > 0) {
544 buffer[bytesReceived] = NULL_CHAR;
545 requestHeader += buffer;
546 if (requestHeader.find(CRLF2) != std::string::npos) {
547 return true;
548 }
549 if (requestHeader.size() >= MAX_HEADER_SIZE) {
550 return false;
551 }
552 }
553 return bytesReceived > 0;
554 }
555
TryConnectWithProxyList(const std::string & targetHost,int targetPort,const std::vector<ProxyConfig> & proxyList,bool isHttps,const std::string & requestHeader)556 int ProxyServer::TryConnectWithProxyList(const std::string &targetHost, int targetPort,
557 const std::vector<ProxyConfig> &proxyList, bool isHttps,
558 const std::string &requestHeader)
559 {
560 int serverSocket = -1;
561 for (const auto &[proxyType, proxyHost, proxyPort] : proxyList) {
562 if (proxyType == SOCKS_STR || proxyType == SOCK5_STR || proxyType == SOCK4_STR) {
563 NETMGR_LOG_D("SOCKS proxy not implemented yet: %{private}s:%{private}d", proxyHost.c_str(), proxyPort);
564 continue;
565 }
566 if (proxyType == DIRECT_STR) {
567 serverSocket = HandleDirectConnection(targetHost, targetPort, isHttps, requestHeader);
568 } else if (proxyType == PROXY_STR || proxyType == HTTP_STR) {
569 serverSocket = HandleProxyConnection(targetHost, targetPort, proxyHost, proxyPort, isHttps, requestHeader);
570 }
571 if (serverSocket >= 0) {
572 LogSuccessfulConnection(proxyType, targetHost, targetPort, proxyHost, proxyPort);
573 break;
574 } else {
575 LogFailedConnection(proxyType, targetHost, targetPort, proxyHost, proxyPort);
576 }
577 }
578 return serverSocket;
579 }
580
HandleDirectConnection(const std::string & targetHost,int targetPort,bool isHttps,const std::string & requestHeader)581 int ProxyServer::HandleDirectConnection(const std::string &targetHost, int targetPort, bool isHttps,
582 const std::string &requestHeader)
583 {
584 NETMGR_LOG_D("Trying DIRECT connection to %{private}s:%{private}d", targetHost.c_str(), targetPort);
585 int serverSocket = ConnectToServer(targetHost, targetPort);
586 if (serverSocket >= 0 && !isHttps && !requestHeader.empty()) {
587 if (SendAll(serverSocket, requestHeader.c_str(), requestHeader.length(), 0) < 0) {
588 close(serverSocket);
589 serverSocket = -1;
590 }
591 }
592 return serverSocket;
593 }
594
HandleProxyConnection(const std::string & targetHost,int targetPort,const std::string & proxyHost,int proxyPort,bool isHttps,const std::string & requestHeader)595 int ProxyServer::HandleProxyConnection(const std::string &targetHost, int targetPort, const std::string &proxyHost,
596 int proxyPort, bool isHttps, const std::string &requestHeader)
597 {
598 NETMGR_LOG_D("Trying HTTP proxy %{private}s:%{private}d for %{private}s:%{private}d",
599 proxyHost.c_str(), proxyPort, targetHost.c_str(), targetPort);
600 if (isHttps) {
601 return ConnectViaUpstreamProxyHttps(targetHost, targetPort, proxyHost, proxyPort);
602 } else {
603 return ConnectViaUpstreamProxy(targetHost, targetPort, requestHeader, proxyHost, proxyPort);
604 }
605 }
606
LogSuccessfulConnection(const std::string & proxyType,const std::string & targetHost,int targetPort,const std::string & proxyHost,int proxyPort)607 void ProxyServer::LogSuccessfulConnection(const std::string &proxyType, const std::string &targetHost, int targetPort,
608 const std::string &proxyHost, int proxyPort)
609 {
610 NETMGR_LOG_D("Successfully connected via %{private}s %{private}s:%{private}d", proxyType.c_str(),
611 proxyType == DIRECT_STR ? targetHost.c_str() : proxyHost.c_str(),
612 proxyType == DIRECT_STR ? targetPort : proxyPort);
613 }
614
LogFailedConnection(const std::string & proxyType,const std::string & targetHost,int targetPort,const std::string & proxyHost,int proxyPort)615 void ProxyServer::LogFailedConnection(const std::string &proxyType, const std::string &targetHost, int targetPort,
616 const std::string &proxyHost, int proxyPort)
617 {
618 NETMGR_LOG_D("Failed to connect via %{private}s %{private}s:%{private}d", proxyType.c_str(),
619 proxyType == DIRECT_STR ? targetHost.c_str() : proxyHost.c_str(),
620 proxyType == DIRECT_STR ? targetPort : proxyPort);
621 }
622
SendErrorResponse(int clientSocket,const char * response)623 void ProxyServer::SendErrorResponse(int clientSocket, const char *response)
624 {
625 SendAll(clientSocket, response, strlen(response), 0);
626 }
627
HandleConnectRequest(int clientSocket,const std::string & requestHeader,const std::string & url)628 void ProxyServer::HandleConnectRequest(int clientSocket, const std::string &requestHeader, const std::string &url)
629 {
630 std::string host;
631 int port;
632 if (!ParseConnectRequest(requestHeader, host, port)) {
633 SendErrorResponse(clientSocket, HTTP_1_1_400);
634 return;
635 }
636
637 std::vector<ProxyConfig> proxyList;
638 GetProxyList(url, host, proxyList);
639 int serverSocket = TryConnectWithProxyList(host, port, proxyList, true);
640 if (serverSocket < 0) {
641 SendErrorResponse(clientSocket, HTTP_1_1_502);
642 return;
643 }
644 if (SendAll(clientSocket, HTTP_1_1_200_CONNECTED, strlen(HTTP_1_1_200_CONNECTED), 0) < 0) {
645 NETMGR_LOG_E("send CONNECT Response fail");
646 close(serverSocket);
647 return;
648 }
649 TunnelData(clientSocket, serverSocket);
650 close(serverSocket);
651 }
652
ForwardData(int fromSocket,int toSocket)653 void ProxyServer::ForwardData(int fromSocket, int toSocket)
654 {
655 char buffer[BUFFER_SIZE];
656 int bytesReceived;
657 while ((bytesReceived = recv(fromSocket, buffer, BUFFER_SIZE, 0)) > 0) {
658 if (SendAll(toSocket, buffer, bytesReceived, 0) < 0) {
659 break;
660 }
661 }
662 }
663
HandleHttpRequest(int clientSocket,const std::string & requestHeader,const std::string & url)664 void ProxyServer::HandleHttpRequest(int clientSocket, const std::string &requestHeader, const std::string &url)
665 {
666 std::string host;
667 int port;
668 if (!ParseHttpRequest(requestHeader, host, port)) {
669 NETMGR_LOG_E("Parse Http Header Fail");
670 SendErrorResponse(clientSocket, HTTP_1_1_400);
671 return;
672 }
673 NETMGR_LOG_D("HTTP request - local port:%{private}d url:%{private}s host:%{private}s",
674 port_, url.c_str(), host.c_str());
675 std::vector<ProxyConfig> proxyList;
676 GetProxyList(url, host, proxyList);
677 int serverSocket = TryConnectWithProxyList(host, port, proxyList, false, requestHeader);
678 if (serverSocket < 0) {
679 SendErrorResponse(clientSocket, HTTP_1_1_502);
680 return;
681 }
682 ForwardData(serverSocket, clientSocket);
683 close(serverSocket);
684 }
685
HandleClient(int clientSocket)686 void ProxyServer::HandleClient(int clientSocket)
687 {
688 std::string requestHeader;
689 if (!ReadRequestHeader(clientSocket, requestHeader)) {
690 close(clientSocket);
691 return;
692 }
693 std::string method = GetRequestMethod(requestHeader);
694 std::string url = GetRequestUrl(requestHeader);
695 if (method == CONNECT_STR) {
696 HandleConnectRequest(clientSocket, requestHeader, url);
697 } else {
698 HandleHttpRequest(clientSocket, requestHeader, url);
699 }
700 close(clientSocket);
701 }
702
AddTask(const ClientTask & task)703 void ProxyServer::AddTask(const ClientTask &task)
704 {
705 {
706 std::lock_guard<std::mutex> lock(queueMutex_);
707 taskQueue_.push(task);
708 }
709 queueCondition_.notify_one();
710 }
711
WorkerThread()712 void ProxyServer::WorkerThread()
713 {
714 while (running_) {
715 ClientTask task = {-1, {}};
716 {
717 std::unique_lock<std::mutex> lock(queueMutex_);
718 queueCondition_.wait(lock, [this] { return !taskQueue_.empty() || !running_; });
719 if (!running_ && taskQueue_.empty()) {
720 break;
721 }
722 if (!taskQueue_.empty()) {
723 task = taskQueue_.front();
724 taskQueue_.pop();
725 }
726 }
727 if (task.clientSocket_ >= 0) {
728 HandleClient(task.clientSocket_);
729 }
730 }
731 }
732
AcceptLoop()733 void ProxyServer::AcceptLoop()
734 {
735 while (running_) {
736 struct pollfd fd;
737 fd.fd = serverSocket_;
738 fd.events = POLLIN;
739 int ret = poll(&fd, 1, 1000);
740 if (ret < 0) {
741 if (errno == EINTR)
742 continue;
743 NETMGR_LOG_E("socket poll fail");
744 break;
745 }
746 if (ret == 0) {
747 continue;
748 }
749 if (!(static_cast<unsigned short>(fd.revents) & POLLIN)) {
750 continue;
751 }
752 struct sockaddr_in clientAddr;
753 socklen_t clientAddrLen = sizeof(clientAddr);
754 int clientSocket = accept(serverSocket_, (struct sockaddr *)&clientAddr, &clientAddrLen);
755 if (clientSocket < 0) {
756 if (errno == EAGAIN || errno == EWOULDBLOCK) {
757 continue;
758 }
759 continue;
760 }
761 AddTask(ClientTask(clientSocket, clientAddr));
762 }
763 }
764
IsPortAvailable(int port)765 bool ProxyServer::IsPortAvailable(int port)
766 {
767 int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
768 if (sockfd < 0) {
769 return false;
770 }
771 int optval = 1;
772 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&optval), sizeof(optval)) < 0) {
773 close(sockfd);
774 return false;
775 }
776 sockaddr_in serverAddr;
777 serverAddr.sin_family = AF_INET;
778 serverAddr.sin_port = htons(static_cast<uint16_t>(port));
779 if (!inet_pton(AF_INET, DEFAULT_URL, &(serverAddr.sin_addr))) {
780 return false;
781 }
782 int bindResult = bind(sockfd, reinterpret_cast<struct sockaddr *>(&serverAddr), sizeof(serverAddr));
783 if (bindResult < 0) {
784 const char *errmsg = strerror(errno);
785 NETMGR_LOG_E("bind error %{private}s", errmsg);
786 }
787 close(sockfd);
788 return (bindResult == 0);
789 }
790
FindAvailablePort(int startPort,int endPort)791 int ProxyServer::FindAvailablePort(int startPort, int endPort)
792 {
793 std::vector<int> portsToTry;
794 for (int port = startPort; port <= endPort; ++port) {
795 portsToTry.push_back(port);
796 }
797 auto seed = std::chrono::system_clock::now().time_since_epoch().count();
798 std::shuffle(portsToTry.begin(), portsToTry.end(), std::default_random_engine(seed));
799 for (int port : portsToTry) {
800 if (IsPortAvailable(port)) {
801 return port;
802 }
803 }
804 return -1;
805 }
806 } // namespace NetManagerStandard
807 } // namespace OHOS
808