Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get a hostname from connection handle in on_tls_init callback #1049

Open
karlisolte opened this issue Jul 8, 2022 · 4 comments
Open

Comments

@karlisolte
Copy link

Hello! I would like to verify TLS certificate. A convenient way of doing that seems to be ctx->set_verify_callback(asio::ssl::rfc2818_verification("host.name"));, but it needs a hostname passed to it.

Handler for set_tls_init_handler has connection_hdl parameter and I would expect to be able to somehow retrieve hostname from it, but I have not succeeded. In particular:

auto wss_connection = client_endpoint_tls.get_con_from_hdl(hdl);
ws_connection->get_uri(); // returns nullptr
ws_connection->get_request().get_uri(); // returns emtpy string
std::shared_ptr<asio::ssl::context> on_tls_init(websocketpp::connection_hdl hdl)
{
    auto ctx = std::make_shared<asio::ssl::context>(asio::ssl::context::sslv23);
    try {
        ctx->set_options(asio::ssl::context::default_workarounds
            | asio::ssl::context::no_sslv2
            | asio::ssl::context::no_sslv3
            | asio::ssl::context::single_dh_use);

        ctx->set_verify_mode(asio::ssl::verify_peer);
        ctx->set_default_verify_paths();
        ctx->set_verify_callback(asio::ssl::rfc2818_verification("ws.ifelse.io"));
    } catch (std::exception& e) {
        LOG_ERROR("Couldn't initialize ssl context: {}", e.what());
    }
    return ctx;
}
@Jacob-Burckhardt
Copy link

Add a hostname argument as the first arg in your on_tls_init function.

Extract the hostname from the URL that you pass to m_client.get_connection. Pass that hostname here:

m_client.set_tls_init_handler (bind (&on_tls_init, hostname, _1));

@karlisolte
Copy link
Author

I am calling set_tls_init_handler as a step during tls_client_endpoint initialization. Binding hostname to on_tls_init callback requires that hostname is known at the time when set_tls_init_handler is called and also limits endpoint to be able to connect to only this hostname (at least without calling set_tls_init_handler again).

I would much prefer to be able to reuse a single tls client endpoint to be able to connect to different hostnames. Or is it not an intended way to use client endpoint?

@Jacob-Burckhardt
Copy link

In the code excerpt below, create_connection calls on_tls_init which occurs before the set_uri call in the excerpt below which explains why get_uri returned null during the call to on_tls_init. That seems to contradict the documentation which says:

A new WebSocket connection is initiated via a three step process. First, a connection request is created by endpoint::get_connection(uri). Next, the connection request is configured. Lastly, the connection request is submitted back to the endpoint via endpoint::connect() which adds it to the queue of new connections to make.

That quote says get_connection makes a request, but it seems to imply the request is not executed until the call to endpoint::connect, but since on_tls_init is called at the request creation stage that shows that it did connect.

You said "calling set_tls_init_handler again". You seem reluctant to do that, and it seems strange you would need to do that, but I think that might be a way to solve your problem.

    connection_ptr get_connection(uri_ptr location, lib::error_code & ec) {
        if (location->get_secure() && !transport_type::is_secure()) {
            ec = error::make_error_code(error::endpoint_not_secure);
            return connection_ptr();
        }

        connection_ptr con = endpoint_type::create_connection();

        if (!con) {
            ec = error::make_error_code(error::con_creation_failed);
            return con;
        }

        con->set_uri(location);

        ec = lib::error_code();
        return con;
    }

@karlisolte
Copy link
Author

That quote says get_connection makes a request, but it seems to imply the request is not executed until the call to endpoint::connect, but since on_tls_init is called at the request creation stage that shows that it did connect.

Yes, so in other words handlers are normally set on the connection object before connect():

auto con = client_endpoint.get_connection(uri, ec);
con->set_open_handler();
con->set_fail_handler();
con->set_close_handler();
client_endpoint.connect(con);

but in case of set_tls_init_handler() there is no point to call this on connection object after client_endpoint.get_connection(uri, ec) (even though connection object has such method) as handler will already have executed. Instead we should set it on the endpoint object right before client_endpoint.get_connection(uri, ec);.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants