HTTP CONNECT processing on the proxy server

Hello!

I write my proxy server in C++. I studied all the man's and standards. I implemented support for absolutely all request methods that the HTTP protocol implies from GET to DELETE, and now I'm faced with the problem of processing the CONNECT method. I absolutely can't understand how to properly process it and forward it between the client and the server. If everything is simple with HTTP requests, a request of this type has arrived:

GET http://examples.ru/i/20140904/source.js HTTP/1.1
Host: examples.ru
Proxy-Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 5.1) Chrome/41.0.2272.118 Safari/537.36
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4

We make the following out of it:

GET /i/20140904/source.js HTTP/1.1
Host: examples.ru
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
User-Agent: Mozilla/5.0 (Windows NT 5.1) Chrome/41.0.2272.118 Safari/537.36
DNT: 1

And we send this case to port 80 and wait for a response. We read the response and close the connection if any of the subscribers specified "Connection: close" or if the server is no longer available. I so opened the connection in general only for processing 1 request and closed it after receiving a response from the server.

But here I am faced with CONNECT, a request of the form comes:

CONNECT www.google.ru:443 HTTP/1.1
Host: www.google.ru
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) Chrome/40.0.2214.111 Safari/537.36

It is clear that I am redoing it as follows:

CONNECT / HTTP/1.1
Host: www.google.ru
Connection: keep-alive

And then I send the code 200 Connection Established to the client. I receive data from the client, which I forward to the server on port 443. In the next moment, a handshake should occur between the client and the server, which apparently happens - in response from the server comes abracadabra, which I send to the client, in response from the client I get the same abracadabra, which when trying to send to the server, an error occurs in the function send() under the number 10053-WSAECONNABORTED. And here I am until the end and can not understand how to properly process all the same CONNECT HTTP method.

Please explain in detail how to process it. Thanks.

Here is the actual code of how I handle CONNECT.

 // Выше принимается запрос и парсится.
 // Создаем внешний сокет с сервером.
 t_error = createSocketClient( ThisClient );
 if ( t_error == -1 ) return -1;

 t_error = sendStatusCodeToClient(ThisClient, 200);
 if ( t_error == -1 ) return -1;

 while ( true ) {
     // Прием запроса от клиента и передача серверу.
     while ( true ) {
         bytes_recv = recv(ThreadInfo[ThisClient].ClientSocket, &buffer[0], SIZE_BLOCK_4096, 0);
         if ( bytes_recv > 0 ) {
             flagData = true;
             bytes_send = send(ThreadInfo[ThisClient].ServerSocket, &buffer[0], bytes_recv, 0);
             if ( bytes_send == SOCKET_ERROR ) { 
                 return -1;
             }
         }
         else if ( bytes_recv == 0 ) break;
         else return -2;
     }

     if ( flagData == true )    {
         // Прием ответа от сервера и передача клиенту.
         while ( true ) {
             bytes_recv = recv(ThreadInfo[ThisClient].ServerSocket, &buffer[0], SIZE_BLOCK_8192, 0);
             if ( bytes_recv > 0 ) {
                 bytes_send = send(ThreadInfo[ThisClient].ClientSocket, &buffer[0], bytes_recv, 0);
                 if ( bytes_send == SOCKET_ERROR ) {
                     return -3;
                 }
             }
             else if ( bytes_recv == 0 )    break;
             else return -4;
         }
     }
 }
Author: Виталий, 2015-08-27

3 answers

One of the reasons may be that the firewall blocks https connections, or any outgoing traffic that it does not understand. Or an error in the logic of the program that closes the socket during the session, output your actions to the logs and see if this is the case.

 1
Author: dsnk, 2015-08-28 06:29:27

And in my opinion, everything is easier, you don't need to send anything to a remote server on connect. It is necessary to establish a tcp connection and, if successful, respond to the client that everything is OK and only to the client. because in this tcp session, the handshake will first take place and only after that the client will send its GET or whatever it wanted to do to the encrypted channel

 0
Author: Mike, 2015-11-09 19:32:47

Yes, Mike described it correctly, with the CONNECT method, headers are exchanged only with the client, and none of the headers are sent to the higher-level proxy or site. Order:

  1. The client sends a request (as in your example)
  2. Your proxy server opens a socket with an endpoint from this request, having previously spelled out the host name from the request to the IP address.
  3. If everything is successful, your proxy should send a 200 Connection Established response to the client.
  4. All exchange after that, the proxy broadcasts all the data between the client and the endpoint.

This scenario is for a client with an explicitly registered proxy server, if you use a 'transparent proxy' using iptables, tproxy, etc., then the order is reduced by point 3, the client is not sent a 200 response, if its request was not the CONNECT method. In the case of 'transparent proxying' technologies, the endpoint address is taken from the socket, and the SOL_IP and SO_ORIGINAL_DST flags must be specified by getsockopt. If use the TPROXY technology, you must use the following construction to remove the address: setsockopt, SOL_IP, IP_TRANSPARENT. example.

If this is something encrypted, then it is not fate to see what is flowing there :) And pay special attention to the dimensions when transmitting both headers and data. Incorrectly specified data length in the HTTP header usually leads to a lot of problems with different browsers. And quite cretically when transmitting encrypted data.

 0
Author: NewView, 2018-05-23 22:53:38