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