偷看asio https ssl流而不从输入流中删除 [英] Peek asio https ssl stream without deleting from input stream
问题描述
我正在使用独立的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:
- 从Asio Standalone库切换到boost :: asio,因为boost :: asio对于asio名称空间还有其他重载(至少在比较atm最新版本boost 1.72.0和asio 1.13.0时)
- 如本文所述(是否可以在之后执行async_handshake如果您之前需要从ssl流中进行任何读取,请先使用Boost :: asio?从套接字读取),然后将读取缓冲区作为第二个参数传递给async_handshake重载(请参见第一点)
- 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屋!