From d2f815b69a8d140f6164fc6a439e27cfa20ca079 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 29 Mar 2024 15:22:59 -1000 Subject: [PATCH] Fix AsyncResolver to match ThreadedResolver behavior AsyncResolver was disabled by default because it did not implement all of functionality of ThreadedResolver because aiodns did not support getaddrinfo until https://github.com/saghul/aiodns/pull/118 see https://github.com/aio-libs/aiohttp/issues/559 --- aiohttp/resolver.py | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/aiohttp/resolver.py b/aiohttp/resolver.py index 6c17b1e7e89..2701a3c119f 100644 --- a/aiohttp/resolver.py +++ b/aiohttp/resolver.py @@ -1,6 +1,6 @@ import asyncio import socket -from typing import Any, Dict, List, Optional, Type, Union +from typing import Any, Dict, List, Optional, Tuple, Type, Union from .abc import AbstractResolver from .helpers import get_running_loop @@ -95,19 +95,49 @@ def __init__( self.resolve = self._resolve_with_query # type: ignore async def resolve( - self, host: str, port: int = 0, family: int = socket.AF_INET + self, hostname: str, port: int = 0, family: int = socket.AF_INET ) -> List[Dict[str, Any]]: try: - resp = await self._resolver.gethostbyname(host, family) + resp = await self._resolver.getaddrinfo( + hostname, + port=port, + type=socket.SOCK_STREAM, + family=family, + flags=socket.AI_ADDRCONFIG, + ) except aiodns.error.DNSError as exc: msg = exc.args[1] if len(exc.args) >= 1 else "DNS lookup failed" raise OSError(msg) from exc hosts = [] - for address in resp.addresses: + for node in resp.nodes: + address: Union[Tuple[bytes, int], Tuple[bytes, int, int, int]] = node.addr + family = node.family + if family == socket.AF_INET6: + if len(address) < 3: + # IPv6 is not supported by Python build, + # or IPv6 is not enabled in the host + continue + if address[3]: + # This is essential for link-local IPv6 addresses. + # LL IPv6 is a VERY rare case. Strictly speaking, we should use + # getnameinfo() unconditionally, but performance makes sense. + host, _port = await self._loop.getnameinfo( + address[0].decode("ascii"), + *address[1:], + socket.NI_NUMERICHOST | socket.NI_NUMERICSERV + ) + port = int(_port) + else: + host = address[0].decode("ascii") + port = address[1] + else: # IPv4 + assert family == socket.AF_INET + host = address[0].decode("ascii") + port = address[1] hosts.append( { - "hostname": host, - "host": address, + "hostname": hostname, + "host": host, "port": port, "family": family, "proto": 0,