反向代理服务器 SOCK4 与 asio c++ (用于 foxyproxy chrome browseR)

reverse proxy server SOCK4 with asio c++ (for foxyproxy chrome browseR)

提问人:Mojo Baggins 提问时间:10/31/2023 更新时间:10/31/2023 访问量:29

问:

“首先,我知道它是同步的,它只意味着一次只能处理一个页面。它不应该是健壮的或任何东西。

我正在尝试编写一个 c++ asio 反向代理服务器,它可以与 foxyproxy chrome 浏览器客户端一起使用,我从互联网上挑选了一些东西,并准备好了这段代码。我的问题如下:

  • 建立 SOCK4 连接后的 http 响应为 null(自从我添加了 SSL 支持以来发生)
  • 如果没有SSL支持,它就会卡住将数据写回客户端,除其他外,它仅适用于自定义SSL客户端,FoxyProxy客户端与https(端口443)通信,所以我想我应该匹配它(我有一个同步的HTTP套接字)。

代码:

#pragma once

#define BOOST_NETWORK_ENABLE_HTTPS 1#include <asio/ssl.hpp>

#include <asio.hpp>

#include <filesystem>

#include <iostream>

#include <regex>

// https://social.msdn.microsoft.com/Forums/en-US/bd8e498b-32f8-4384-94bb-fcbcb0ff98e8/cant-link-with-crypt32lib?forum=windowssdk
#pragma comment(lib, "crypt32.lib")#include <wincrypt.h>

void add_windows_root_certs(asio::ssl::context & ctx) {
    HCERTSTORE hStore = CertOpenSystemStore(0, L "ROOT");
    if (hStore == NULL) {
        return;
    }

    X509_STORE * store = X509_STORE_new();
    PCCERT_CONTEXT pContext = NULL;
    while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != NULL) {
        X509 * x509 = d2i_X509(NULL,
            (const unsigned char ** ) & pContext -> pbCertEncoded,
            pContext -> cbCertEncoded);
        if (x509 != NULL) {
            X509_STORE_add_cert(store, x509);
            X509_free(x509);
        }
    }

    CertFreeCertificateContext(pContext);
    CertCloseStore(hStore, 0);

    SSL_CTX_set_cert_store(ctx.native_handle(), store);
}

using namespace std::literals::chrono_literals;

int main() {

    asio::io_context incoming_proxy_io, outcoming_proxy_io;
    asio::ip::tcp::acceptor incoming_proxy_acceptor_ {
        incoming_proxy_io,
        asio::ip::tcp::endpoint(asio::ip::tcp::v4(), 40000)
    };

    std::filesystem::path cert_path = std::filesystem::current_path() / "Debug\\server.crt";
    std::filesystem::path key_path = std::filesystem::current_path() / "Debug\\server.key";
    std::filesystem::path dh_2048 = std::filesystem::current_path() / "Debug\\dh_pem2048.pem";

    // tls
    asio::ssl::context context_(asio::ssl::context::tlsv12_client);

    context_.set_options(asio::ssl::context::default_workarounds |
        asio::ssl::context::no_sslv2 |
        asio::ssl::context::no_sslv3 |
        asio::ssl::context::tlsv12_client);
    add_windows_root_certs(context_);

    asio::ssl::stream < asio::ip::tcp::socket > m_socket {
        incoming_proxy_io,
        context_
    };

    try {
        std::string username = "";
        std::string user;
        user.resize(username.size());

        unsigned char version, command, port_high_byte, port_low_byte, null_byte;
        asio::ip::address_v4::bytes_type bytes_address;

        std::error_code ec;
        incoming_proxy_acceptor_.accept(m_socket.lowest_layer(), ec);

        if (ec) {
            std::cout << "error accepting client.." << std::endl;
            return -1;
        }

        std::array < asio::mutable_buffer, 7 > bufsRead = {
            {
                asio::buffer( & version, 1),
                    asio::buffer( & command, 1),
                    asio::buffer( & port_high_byte, 1),
                    asio::buffer( & port_low_byte, 1),
                    asio::buffer(bytes_address),
                    asio::buffer( & user[0], user.size()),
                    asio::buffer( & null_byte, 1)
            }
        };

        ec = std::error_code();
        asio::read(m_socket, bufsRead, ec);

        if (ec || null_byte != 0 || version != 0x04 || command != 0x01) {
            std::cout << "problem reading data.. error: " << ec.message() << std::endl;
            return -1;
        }

        unsigned short received_port = port_high_byte;
        received_port = (received_port << 8) | port_low_byte;

        if (received_port != 443) {
            std::cout << "port is bad?" << std::endl;
            return -1;
        }

        // address
        asio::ip::address_v4 true_address(bytes_address);
        assert(true_address.to_string() != m_socket.lowest_layer().local_endpoint().address().to_string());

        unsigned char status = 0x5a;
        std::array < asio::const_buffer, 5 > bufsWrite = {
            {
                asio::buffer( & null_byte, 1),
                    asio::buffer( & status, 1),
                    asio::buffer( & port_high_byte, 1),
                    asio::buffer( & port_low_byte, 1),
                    asio::buffer(bytes_address)
            }
        };

        ec = std::error_code();
        asio::write(m_socket, bufsWrite, ec);
        if (ec) {
            std::cout << ec.message() << "error writing" << std::endl;
        }

        // Continue reading data from the client and forward to the destination (web server)
        while (true) {
            ec = std::error_code();
            asio::streambuf request;
            asio::read(m_socket, request, ec);
            if (ec) {
                std::cout << "failed from scoket.." << std::endl;
                continue;
            }

            std::cout << "Reading from socket was succesful..." << std::endl;

            std::string endp;

            std::istream request_stream( & request);
            std::string request_line;
            std::vector < std::string > request_line_temp;
            while (std::getline(request_stream, request_line)) {
                request_line_temp.push_back(request_line);
            }

            request_line = request_line_temp[1];

            size_t start = 0, end;

            std::string delimeter("\r");

            if ((end = request_line.find(delimeter, start)) != std::string::npos) {
                endp = request_line.substr(start + 6, end - start);
            }

            if (ec) {
                std::cout << "Error reading data from the client: " << ec.message() << std::endl;
                continue;
            }

            if (endp.empty()) {
                std::cout << "No host.." << std::endl;
                continue;
            }

            auto query = asio::ip::tcp::resolver::query(endp, "http");

            asio::error_code ec;
            asio::ip::tcp::resolver resolver {
                outcoming_proxy_io
            };
            asio::ip::tcp::resolver::results_type results = resolver.resolve(query, ec);

            asio::ssl::context context_(asio::ssl::context::tlsv12_client);
            context_.set_options(
                asio::ssl::context::default_workarounds |
                asio::ssl::context::no_sslv2 |
                asio::ssl::context::single_dh_use);
            context_.set_password_callback([ & ](auto, auto) -> std::string {
                return "Dani!eelordrarequiver195709059Dad";
            });
            context_.use_certificate_chain_file(cert_path.string());
            context_.use_private_key_file(key_path.string(), asio::ssl::context::pem);
            context_.use_tmp_dh_file(dh_2048.string());
            asio::ssl::stream < asio::ip::tcp::socket > out {
                outcoming_proxy_io,
                context_
            };

            std::cout << "connecting to.. " << endp << std::endl;

            asio::connect(out.lowest_layer(), results, ec);

            if (ec || !out.lowest_layer().is_open()) {
                std::cout << "Error connecting to client error: " << ec.message() << std::endl;
                continue;
            }

            std::this_thread::sleep_for(0 s);

            std::cout << "writing to.. " << endp << std::endl;

            // Send the HTTP request to the destination server.
            size_t i = asio::write(out, asio::buffer(request.data(), request.size()), ec);
            if (ec || i <= 0) {
                std::cout << "failed to write.." << std::endl;
            }

            std::this_thread::sleep_for(0 s);

            std::cout << "reading from.. " << endp << std::endl;

            // Read the response from the destination server and send it back to the client.
            std::vector < char > response_from_server;
            size_t bytes_transferred = asio::read(out, asio::buffer(response_from_server), ec);
            if (!ec && bytes_transferred >= 0) {
                std::cout << "writing back to.. " << endp << std::endl;

                // Send the response back to the client.
                bytes_transferred = asio::write(m_socket, asio::buffer(response_from_server, bytes_transferred), ec);
                if (ec || bytes_transferred <= 0) {
                    std::cout << "failed to write back.." << std::endl;
                }
            }

            std::cout << "data succesfully red from the server.." << std::endl;

            outcoming_proxy_io.post([ & ]() {
                out.lowest_layer().close();
                // As long as outstanding completion handlers do not
                // invoke operations on socket_, then socket_ can be 
                // destroyed.
                //out.release();
            });
        }

        std::thread t_([ & ]() {
            incoming_proxy_io.run();
        });
        if (t_.joinable()) {
            t_.join();
        }
        std::thread t_2([ & ]() {
            outcoming_proxy_io.run();
        });
        if (t_2.joinable()) {
            t_2.join();
        }
    } catch (asio::system_error & ec) {
        std::cout << "exception caught when accepting a new incoming_proxy" << ec.what() << std::endl;
    }

    return 0;
}
C++ 反向代理 袜子 ASIO FoxyProxy

评论


答: 暂无答案