HTTPS proxy never receives data from a client or server

My HTTPS proxy dealing with CONNECT HTTP requests from the client performs the following steps:

  • opens a socket for a remote server;
  • sets the socket mode to non-blocking mode;
  • connect() attempts if ((connect_res == -1) && (errno != EINPROGRESS)) ;
  • using select() check whether the server socket is ready to send or receive data;
  • sets the socket back to blocking mode;
  • sends "HTTP/1.1 200 Connection established\r\n\r\n" client after successful connect() ;
  • calls proxyHTTPS() ;

     // if client sent a CONNECT request... struct sockaddr_in remote_server, local_bind; int conn_res, select_res; memset(&remote_server, 0, sizeof(remote_server)); remote_server.sin_family = AF_INET; remote_server.sin_addr.s_addr = rm.getServerAddr(); remote_server.sin_port = rm.getServerPort(); memset(&local_bind, 0, sizeof(local_bind)); local_bind.sin_family = AF_INET; local_bind.sin_addr.s_addr = htonl(INADDR_ANY); local_bind.sin_port = htons(0); fd_set rdset, wrset; struct timeval tv; sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockfd_server < 0) { perror("socket: "); } // make socket not blocking if(!setNonBlocking(sockfd_server)) perror("fcntl"); debug_green("CONNECT set socket to non-blocking mode\n"); bind(sockfd_server, (struct sockaddr*) &local_bind, sizeof(local_bind)); conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in)); // The socket is nonblocking and the connection cannot be completed immediately // check for EINPROGRESS if ((conn_res == -1) && (errno != EINPROGRESS)) { debug_yellow("CONNECT attempting select()\n"); do { FD_ZERO(&rdset); FD_SET(sockfd_server, &rdset); wrset = rdset; tv.tv_sec = 0; tv.tv_usec = 0; select_res = select(sockfd_server+1, &rdset, &wrset, NULL, &tv); } while ((select_res == -1) && (errno == EINTR)); if ((!FD_ISSET(sockfd_server, &rdset)) && ((!FD_ISSET(sockfd_server, &wrset)))) { debug_red("SELECT sockfd non risponde\n"); close(sockfd_server); sockfd_server = -1; return false; } /* repeat not blocking connect() to check if it gives error saying connection already happened (from my teacher slides) */ conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in)); if (conn_res == -1) { if(errno == EISCONN) printf ("connect(): connection already existing, OK\n"); else { printf("connect(): connection failed\n"); close(sockfd_server); sockfd_server = -1; return false; } } printf("connection OK\n"); } else { debug_green("connected immediately\n"); } if (!setBlocking(sockfd_server)) { perror("FCNTL:"); } debug_green("CONNECT set socket back to blocking mode\n");fflush(stdout); // #define CONNECT_200_OK HTTP/1.1 200 Connection established\r\n\r\n std::string connect_200_to_client(CONNECT_200_OK); int connect_200_to_client_send = send(new_sockfd_client, connect_200_to_client.c_str(), sizeof(connect_200_to_client), 0); if (connect_200_to_client_send <= 0) { perror("CONNECT send() 200 OK to client failed"); close(sockfd_server); sockfd_server = -1; return false; } // finally calling proxyHTTPS hm.proxyHTTPS(new_sockfd_client, sockfd_server); 

Now I have to be ready to send data from client to server and from server to client when data is available from one of the two sides of the connection, but it will never succeed.

Here is the code that should forward data from both sides of the connection:

 void proxyHTTPS(int new_sockfd_client, int sockfd_server) { printf("starting proxyHTTPS\n"); fd_set fdset; int maxp1 = sockfd_server > new_sockfd_client ? sockfd_server+1 : new_sockfd_client+1; int r; int read_from_client = 0; int read_from_server = 0; int send_to_client = 0; int send_to_server = 0; struct timeval timeout; char https_buf[4096]; int https_buf_size = sizeof(https_buf); memset(https_buf, 0, https_buf_size); // tried 0, 5, 10, 20, 30, 60 seconds timeout, // still got this problem timeout.tv_sec = 10; timeout.tv_usec = 0; while (true) { FD_ZERO(&fdset); FD_SET(new_sockfd_client, &fdset); FD_SET(sockfd_server, &fdset); timeout.tv_sec = 10; timeout.tv_usec = 0; r = select(maxp1, &fdset, NULL, NULL, &timeout); if (r < 0) { perror("select()"); break; } if (r == 0) { // select timed out debug_yellow("proxyHTTPS: select() request timeout 408\n"); break; } if ((!FD_ISSET(new_sockfd_client, &fdset)) && ((!FD_ISSET(sockfd_server, &fdset)))) { debug_red("proxyHTTPS: SELECT sockfds not responding\n"); break; } else if (FD_ISSET(new_sockfd_client, &fdset)) { debug_green("proxyHTTPS: reading from client and sending to server\n"); read_from_client = recv(new_sockfd_client, https_buf, https_buf_size, 0); if (read_from_client < 0) { debug_red("proxyHTTPS recv() from client " << strerror(errno) << '\n'); break; } else if (read_from_client == 0) { debug_yellow("proxyHTTPS client closed conn\n"); break; } else { // read_from_client > 0 send_to_server = send(sockfd_server, https_buf, read_from_client, 0); if (send_to_server > 0) { debug_green("proxyHTTPS: sent to server " << std::to_string(send_to_server) << " bytes \n"); } else if (send_to_server == 0) { debug_yellow("proxyHTTPS: sent to server 0 bytes...\n"); break; } else { debug_red("proxyHTTPS send() to server " << strerror(errno) << '\n'); break; } } } else if (FD_ISSET(sockfd_server, &fdset)) { debug_green("proxyHTTPS: reading from server and sending to client\n"); read_from_server = recv(sockfd_server, https_buf, https_buf_size, 0); if (read_from_server < 0) { debug_red("proxyHTTPS recv() from server " << strerror(errno) << '\n'); break; } else if (read_from_server == 0) { debug_yellow("proxyHTTPS server closed conn\n"); break; } else { // read_from_server > 0 send_to_client = send(new_sockfd_client, https_buf, read_from_server, 0); if (send_to_client > 0) { debug_green("proxyHTTPS: sent to client " << std::to_string(send_to_client) << " bytes\n"); } else if (send_to_client == 0) { debug_yellow("proxyHTTPS: sent 0 bytes to client, errno: " << errno << '\n'); break; } else { debug_red("proxyHTTPS send() to client " << strerror(errno) << '\n'); break; } } } } debug_yellow("proxyHTTPS: quitting\n"); } 

This, for example, is a CONNECT request that the proxy receives from the client:

 CONNECT www.youtube.com:443 HTTP/1.1 Host: www.youtube.com:443 Proxy-Connection: keep-alive User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36 /r/n 

If the client sends CONNECT www.netflix.com:443 HTTP/1.1 , my proxy server also fails on the terminal outputs:

 setting non block socket connected immediately setting block socket 54.228.227.144:443 OK CONNECT: send to client HTTP/1.1 200 Connection established starting proxyHTTPS proxyHTTPS: reading from server and sending to client proxyHTTPS read from server: Connection refused quitting proxyHTTPS 

If clients send CONNECT www.youtube.com:443 HTTP/1.1 , my proxy fails again and shows:

 setting non block socket connected immediately setting block socket 216.58.201.238:443 OK CONNECT: send to client HTTP/1.1 200 Connection established starting proxyHTTPS select(): Operation now in progress proxyHTTPS: select() request timeout 408 quitting proxyHTTPS 

I think that I took all the steps that I was told to take to establish a tunnel between the client and server, connect() always in order, so the errors should be in my proxyHTTPS . I have no idea!

EDIT 1 : removed perror() when select() returns 0 since errno does not go up; improved error checking in the select() loop, distinguishing return values > or == zero. Despite this, the same problem still arises: one way or another, it cannot read data from the client or server.

EDIT 2 : Updated code for connecting to a remote server.

I'm starting to think that since the select() loop seems to be correct, the problem might be caused by something else ...

The debugging features used above are defined below:

 #define DEFAULTCOLOR "\033[0m" #define RED "\033[22;31m" #define YELLOW "\033[1;33m" #define GREEN "\033[0;0;32m" #define debug_red(...) std::cout << RED << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout); #define debug_yellow(...) std::cout << YELLOW << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout); #define debug_green(...) std::cout << GREEN << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout); 
0
source share

Source: https://habr.com/ru/post/1213306/


All Articles