Search code examples
node.jsnetworkingtcpproxyhttp-tunneling

Node JS TCP Proxy: Set up HTTP Tunnel using Node JS


I'm trying to implement a TCP proxy in Node JS. I only have some experience with Javascript so I met a lot of problems along the way. I've done a lot of searching for this one but had no luck.

I want to implement a two-hop TCP connection for HTTPS proxy. Here is part of my code.

var net = require('net');

var server = net.createServer(function(clientSock) {

    var connected = false;    

    var serverSock;

    clientSock.on('data', function(clientData) {

        if (connected) {

            // Send future messages if is connected
            serverSocet.write(clientData);

        } else {

            var host = // get from data
            var port = // get from data

            if (clientData is a CONNECT request) {

                // Create a new socket to server
                if (!serverSock) {
                    serverSock = new net.Socket();

                    serverSock.connect(port, host, function() {

                        // Send the CONNECT request (Client Hello)
                        serverSock.write(clientData);

                        connected = true;

                        clientSock.write('HTTP/1.1 200 OK\r\n');
                   });

                   serverSock.on('data', function(serverData) {
                        clientSock.write(serverData);
                   });
               }
          }
     });
 });

I used Wireshark to capture the packets sent if I visit https://www.google.com. If I don't use my proxy, the "Client Hello" message is sent in TLS v1.2. But if I use my proxy, it is sent by SSL. The server always reject my CONNECT request and send back a reset request.

I also tried the TLS API in Node JS. The server accepted my CONNECT request but always request me to start a new session after the Key Exchange. The browser will close the socket and create a new socket. But it never loaded the page...

I've spent a whole day on this single problem. I believe I can use TCP socket to implement HTTP Tunnel. Please help... Thanks a lot!!


Solution

  • Problem solved!

    To make TCP socket use TLS v1.2 while dealing with HTTPS, just put this option, {allowHalfOpen: true}, as parameter when creating the sockets.

    New Code would look like this:

    var net = require('net');
    
                                   // option here
    var server = net.createServer({allowHalfOpen: true}, function(clientSock) {
    
    var connected = false;    
    
    var serverSock;
    
    clientSock.on('data', function(clientData) {
    
        if (connected) {
    
            // Send future messages if is connected
            serverSocet.write(clientData);
    
        } else {
    
            var host = // get from data
            var port = // get from data
    
            if (clientData is a CONNECT request) {
    
                // Create a new socket to server
                if (!serverSock) {
    
                                                 // Option here
                    serverSock = new net.Socket({allowHalfOpen: true});
    
                    serverSock.connect(port, host, function() {
    
                        // Don't need to forward hello message from client
                        // Connect method automatically sends it for you
                        //serverSock.write(clientData);
    
                        connected = true;
    
                        clientSock.write('HTTP/1.1 200 OK\r\n');
                   });
    
                   serverSock.on('data', function(serverData) {
                        clientSock.write(serverData);
                   });
               }
          }
     });