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

Fix SNI support with tls_use_host_header #15384

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions datadog_checks_base/datadog_checks/base/utils/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,10 @@ def session(self):
if self._session is None:
self._session = requests.Session()

# Enables HostHeaderSSLAdapter
# Enables HostHeaderSSLSNIAdapter(HostHeaderSSLAdapter)
# https://toolbelt.readthedocs.io/en/latest/adapters.html#hostheaderssladapter
if self.tls_use_host_header:
self._session.mount('https://', host_header_ssl.HostHeaderSSLAdapter())
self._session.mount('https://', HostHeaderSSLSNIAdapter())
# Enable Unix Domain Socket (UDS) support.
# See: https://github.com/msabramo/requests-unixsocket
self._session.mount('{}://'.format(UDS_SCHEME), requests_unixsocket.UnixAdapter())
Expand Down Expand Up @@ -993,3 +993,42 @@ class StandardFields(object):

if not PY2:
StandardFields.__doc__ = '\n'.join('- `{}`'.format(field) for field in STANDARD_FIELDS)

class HostHeaderSSLSNIAdapter(host_header_ssl.HostHeaderSSLAdapter):
"""
# HostHeaderSSLSNIAdapter is a variation of requests_toolbelt.adapters.host_header_ssl
# that includes an SNI related fix: https://github.com/requests/toolbelt/pull/293

# https://toolbelt.readthedocs.io/en/latest/adapters.html#hostheaderssladapter

A HTTPS Adapter for Python Requests that sets the hostname for certificate
verification based on the Host header.

This allows requesting the IP address directly via HTTPS without getting
a "hostname doesn't match" exception.

Example usage:

>>> s.mount('https://', HostHeaderSSLSNIAdapter())
>>> s.get("https://93.184.216.34", headers={"Host": "example.org"})

"""
def send(self, request, **kwargs):
# HTTP headers are case-insensitive (RFC 7230)
host_header = None
for header in request.headers:
if header.lower() == "host":
host_header = request.headers[header]
break

connection_pool_kwargs = self.poolmanager.connection_pool_kw

if host_header:
connection_pool_kwargs["assert_hostname"] = host_header
connection_pool_kwargs["server_hostname"] = host_header
elif "assert_hostname" in connection_pool_kwargs:
# an assert_hostname from a previous request may have been left
connection_pool_kwargs.pop("assert_hostname", None)
connection_pool_kwargs.pop("server_hostname", None)

return super(HostHeaderSSLSNIAdapter, self).send(request, **kwargs)
Loading