Skip to content

Prevent hostname being replaced with IP during handshake#5038

Merged
obiltschnig merged 1 commit intopocoproject:mainfrom
slabko:keep-peer-host-name
Oct 2, 2025
Merged

Prevent hostname being replaced with IP during handshake#5038
obiltschnig merged 1 commit intopocoproject:mainfrom
slabko:keep-peer-host-name

Conversation

@slabko
Copy link
Copy Markdown
Contributor

@slabko slabko commented Oct 1, 2025

Before the handshake is performed, SecureSocketImpl::stateClientConnected overrides the peer hostname with its IP address, making it impossible to send SNI during the handshake in SecureSocketImpl::stateClientHandshakeStart.

This behavior essentially breaks SNI and prevents the library from being used with load balancers that rely on SNI to determine the destination host.

Everywhere else, the peer hostname is replaced by the IP address only when the peer hostname is empty. That makes total sense; however, it seems like this check was forgotten in SecureSocketImpl::stateClientConnected.

status.github.com requires SNI, so this example demonstrates the problem:

#include <iostream>
#include <Poco/Net/HTTPSClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/StreamCopier.h>
#include <Poco/Net/SSLManager.h>

int main()
{
    Poco::Net::Context::Ptr context
        = new Poco::Net::Context(Poco::Net::Context::TLS_CLIENT_USE, "");

    Poco::Net::initializeSSL();
    Poco::Net::SSLManager::instance().initializeClient(nullptr, nullptr, context);

    try {
        static const std::string host = "status.github.com";
        Poco::Net::HTTPSClientSession session(host, 443);
        Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_GET, "/");
        session.sendRequest(req);
        Poco::Net::HTTPResponse res;
        std::istream& rs = session.receiveResponse(res);
        std::cout << res.getStatus() << " " << res.getReason() << "\n";
        Poco::StreamCopier::copyStream(rs, std::cout);
    }
    catch (const Poco::Exception& ex)
    {
        std::cerr << ex.displayText() << "\n";
    }

    return EXIT_SUCCESS;
}

The output will be

Invalid certficate: Host name verification failed

Looking at Wireshark we can see that Client Hello does not contain SNI.
image

With the fix in the PR everything works and we can see SNI in the Client Hello message:
image

Before the handshake is performed, SecureSocketImpl::stateClientConnected
overrides the peer hostname with its IP address, making it impossible to send
SNI during the handshake in SecureSocketImpl::stateClientHandshakeStart.

This behavior essentially breaks SNI and prevents the library from being used
with load balancers that rely on SNI to determine the destination host.

Everywhere else, the peer hostname is replaced by the IP address only when the
peer hostname is empty. That makes total sense; however, it seems like this
check was forgotten in SecureSocketImpl::stateClientConnected.
@obiltschnig obiltschnig merged commit 44cb762 into pocoproject:main Oct 2, 2025
36 checks passed
@matejk matejk added this to the Release 1.15.0 milestone Oct 2, 2025
@matejk matejk added the bug label Oct 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants