偷看asio https ssl流而不从输入流中删除 [英] Peek asio https ssl stream without deleting from input stream

查看:101
本文介绍了偷看asio https ssl流而不从输入流中删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用独立的asio和来自Eidheim的HTTPS包装器( Eidheims SimpleHttpsServer )在Windows上使用异步请求处理和线程池设置HTTPS服务器。 HTTPS服务器偶尔会获取原始套接字查询,因为我想替换旧的套接字服务器,并且如果客户端应用程序不是最新的,则它们不会发送HTTP格式的查询。
对于HTTP,这没问题,因为如果传入的查询没有HTTP格式,我可以将Read(从套接字)方法更改为使用旧代码来处理请求。

I am using asio standalone and an HTTPS wrapper from Eidheim (Eidheims SimpleHttpsServer) to set up an HTTPS server on Windows with asynchronous rerquest handling and a thread pool. Occassionally the HTTPS server gets raw socket queries though, because I want to replace an older socket server and if the client app is not up to date, they wont send HTTP(s) formatted queries. For HTTP this was no problem, because I could change the Read (from socket) method to use the legacy code for request handling instead, if the incoming query did not have HTTP format.

现在,在HTTPS ssl套接字流上尝试相同的操作,在发生任何读取之前,服务器首先需要执行ssl握手,因此我需要在该握手之前先读取(窥视)套接字以进行验证如果需要纯套接字回退方法或标准HTTPS方法。

Now, trying the same on HTTPS ssl socket streams, the server first needs to perform an ssl handshake, before any reading takes place, so I need to read (peek) into the socket before that handshake to verify if it needs pure socket fallback methods or standard HTTPS methods.

但是,每当我在握手之前手动读取套接字时,输入流上都会丢失字节,并且无法提供

But whenever I read the socket before that handshake manually, Bytes are missing on the input stream and could not yet provide those missing bytes to the handshake/reading process.

所以我认为将字节保留在输入流上而不是偷看会比较容易,但是我还没有发现窥视asio :: ssl :: stream的方法。 (应该使用async_receive和flag message_peek,但是我找不到它。我找到的唯一文档是关于boost :: beast的)

So I thought it would be easier to leave the bytes on the input stream and instead peek, but I have not yet found a way to peek into asio::ssl::stream. (async_receive and the flag message_peek are supposed to work, but I couldn't find it. The only documentation I found is for boost::beast)

这是一个覆盖的accept函数,如果握手成功,则调用read:

My only angle on this is the overwritten accept function, in which a read is called if the handshake succeeds:

(来自 https://gitlab.com/eidheim/Simple-Web-Server/-//blob/master/server_https.hpp

void accept() override {
    auto connection = create_connection(*io_service, context);

    acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const error_code& ec) {
        auto lock = connection->handler_runner->continue_lock();
        if (!lock)
            return;

        if (ec != error::operation_aborted)
            this->accept();

        auto session = std::make_shared<Session>(config.max_request_streambuf_size, connection);

        if (!ec) {
            asio::ip::tcp::no_delay option(true);
            error_code ec;
            session->connection->socket->lowest_layer().set_option(option, ec);

            session->connection->set_timeout(config.timeout_request);

// ***** I need to read (peek) before this to decide if a handshake is needed *****

            session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code& ec) {
                session->connection->cancel_timeout();
                auto lock = session->connection->handler_runner->continue_lock();
                if (!lock)
                    return;
                if (!ec)
                    this->read(session);
                else if (this->on_error)
                    this->on_error(session->request, ec);
            });
        }
        else if (this->on_error)
            this->on_error(session->request, ec);
    });
}

是否有人有洞察力如何窥视asio ssl流(我只需要实际上是第一个字节)?
还是有人知道这个图书馆,并且对如何解决这个问题有另一个想法?
还有其他我可以研究的混合(asio)服务器(https和原始套接字)示例吗?

Does anyone have some insight how to peek into asio ssl streams (I just need the first Byte actually)? Or does someone know this library and has another idea on how to tackle this? Any other example of mixed (asio) servers (https and raw sockets) which I could look into?

感谢
Natulux

Thanks Natulux

推荐答案

结果是不鼓励偷看套接字,也很难做到,而对于独立于asio的情况更是如此。
我发现的解决方法是这样的:

Turns out peeking into the socket is discouraged and also hard to accomplish, even more so with asio standalone. The workaround I found works like this:

  • Switch from Asio Standalone library to boost::asio, because boost::asio has additional overloads for the asio namespace (at least when comparing the atm newest builds boost 1.72.0 and asio 1.13.0)
  • As described in this article (Is it possible to do async_handshake after reading from socket prior using Boost::asio?) read the whole handshake, if you need any reading from the ssl stream in before and pass the read buffer to the async_handshake overload (see first point) as second parameter

对我来说,像这样:

void accept() override {
    auto connection = create_connection(*io_service, context);

    acceptor->async_accept(connection->socket->lowest_layer(), [this, connection](const error_code &ec) {
    auto lock = connection->handler_runner->continue_lock();
    if(!lock)
        return;

    if(ec != error::operation_aborted)
        this->accept();

    auto session = std::make_shared<Session>(config.max_request_streambuf_size, connection);

    if(!ec) {
        asio::ip::tcp::no_delay option(true);
        error_code ec;
        session->connection->socket->lowest_layer().set_option(option, ec);

        //read some bytes, needed before the handshake
        const unsigned int bytesToRead = 1;
        int size_of_the_data = 100;
        std::vector<unsigned char> _raw_buffer(size_of_the_data);
        asio::mutable_buffers_1 sslBuffer(asio::buffer(_raw_buffer, size_of_the_data));

        //You should make this async!
        asio::read(session->connection->socket->next_layer(), boost::asio::buffer(sslBuffer, bytesToRead), asio::transfer_exactly(bytesToRead));

        //Get the read data from the buffer in a readable form
        unsigned char * firstByte = asio::buffer_cast<unsigned char*>(sslBuffer);

        //Use the data somehow (in my case, use the first Byte to see if I need raw socket handling or ssl handshake + https handling)
        if (SocketQuery::CheckForSocketQuery(firstByte[0])) {
            this->read_socket(session, firstByte[0]);
        }
        else
        {
            //read handshake, 4000 Bytes should be way more than any handshake needs (which is something between 200 and 400 bytes usually)
            //You should make this async!
            std::size_t bytesOfHandshake = session->connection->socket->next_layer().read_some(boost::asio::buffer(sslBuffer + bytesToRead, 4000));
            bytesOfHandshake += bytesToRead;

            session->connection->set_timeout(config.timeout_request);

            //Use overload of async_handshake with buffer as second parameter
            //Note that the async callback lambda is expected to take the buffer and buffer size as you see below
            session->connection->socket->async_handshake(asio::ssl::stream_base::server, asio::buffer(sslBuffer, bytesOfHandshake), [this, sslBuffer, session](const error_code& ecHttps, std::size_t bufferSize) {
            session->connection->cancel_timeout();
            auto lock = session->connection->handler_runner->continue_lock();
            if (!lock)
                return;

            if (!ecHttps)
            {
                this->read(session);
            }
            else if (this->on_error)
            {
                this->on_error(session->request, ecHttps);
                wxLogMessage("server error: " + wxString(ecHttps.message()));
            }
            else
            {
                wxLogMessage("server error: " + wxString(ecHttps.message()));
            }
        });
        }
    }
    else if(this->on_error)
        this->on_error(session->request, ec);

    });
}

这篇关于偷看asio https ssl流而不从输入流中删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆