]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Check SAN for IP if using an address URL in https() [#1125].
authorBob Halley <halley@dnspython.org>
Sat, 14 Sep 2024 15:51:39 +0000 (08:51 -0700)
committerBob Halley <halley@dnspython.org>
Sat, 14 Sep 2024 15:51:39 +0000 (08:51 -0700)
Httpx needs us to set the "sni_hostname" extension if the
server in the URL is an IP address, as otherwise it will not
check the certificate.  With this change, it will look for a
SAN with the IP address.

dns/asyncquery.py
dns/query.py

index eac10de3552cd1ce8e25f0d51cb165d1b1a7f22a..ce885a4ced0ee3400668365877ea92896e3e3537 100644 (file)
@@ -39,9 +39,9 @@ import dns.transaction
 from dns._asyncbackend import NullContext
 from dns.query import (
     BadResponse,
+    HTTPVersion,
     NoDOH,
     NoDOQ,
-    HTTPVersion,
     UDPMode,
     _check_status,
     _compute_times,
@@ -560,12 +560,14 @@ async def https(
     else:
         url = where
 
+    extensions = {}
     if bootstrap_address is None:
         parsed = urllib.parse.urlparse(url)
         if parsed.hostname is None:
             raise ValueError("no hostname in URL")
         if dns.inet.is_address(parsed.hostname):
             bootstrap_address = parsed.hostname
+            extensions["sni_hostname"] = parsed.hostname
         if parsed.port is not None:
             port = parsed.port
 
@@ -638,13 +640,25 @@ async def https(
                 }
             )
             response = await backend.wait_for(
-                the_client.post(url, headers=headers, content=wire), timeout
+                the_client.post(
+                    url,
+                    headers=headers,
+                    content=wire,
+                    extensions=extensions,
+                ),
+                timeout,
             )
         else:
             wire = base64.urlsafe_b64encode(wire).rstrip(b"=")
             twire = wire.decode()  # httpx does a repr() if we give it bytes
             response = await backend.wait_for(
-                the_client.get(url, headers=headers, params={"dns": twire}), timeout
+                the_client.get(
+                    url,
+                    headers=headers,
+                    params={"dns": twire},
+                    extensions=extensions,
+                ),
+                timeout,
             )
 
     # see https://tools.ietf.org/html/rfc8484#section-4.2.1 for info about DoH
index 1b0703b2caaadcb6739ee8096201c2690432b5d9..9060012c6625d5741a7f80bda429c00f1e0a9841 100644 (file)
@@ -449,12 +449,14 @@ def https(
     else:
         url = where
 
+    extensions = {}
     if bootstrap_address is None:
         parsed = urllib.parse.urlparse(url)
         if parsed.hostname is None:
             raise ValueError("no hostname in URL")
         if dns.inet.is_address(parsed.hostname):
             bootstrap_address = parsed.hostname
+            extensions["sni_hostname"] = parsed.hostname
         if parsed.port is not None:
             port = parsed.port
 
@@ -525,12 +527,22 @@ def https(
                     "content-length": str(len(wire)),
                 }
             )
-            response = session.post(url, headers=headers, content=wire, timeout=timeout)
+            response = session.post(
+                url,
+                headers=headers,
+                content=wire,
+                timeout=timeout,
+                extensions=extensions,
+            )
         else:
             wire = base64.urlsafe_b64encode(wire).rstrip(b"=")
             twire = wire.decode()  # httpx does a repr() if we give it bytes
             response = session.get(
-                url, headers=headers, timeout=timeout, params={"dns": twire}
+                url,
+                headers=headers,
+                timeout=timeout,
+                params={"dns": twire},
+                extensions=extensions,
             )
 
     # see https://tools.ietf.org/html/rfc8484#section-4.2.1 for info about DoH