{"id":1193,"library":"pycares","title":"Pycares: Asynchronous DNS Resolver","description":"Pycares is a Python module that provides an asynchronous interface to c-ares, a C library for performing DNS requests and name resolutions. It enables non-blocking DNS lookups, making it suitable for high-performance network applications. The library is actively maintained, currently at version 5.0.1, with regular releases addressing bug fixes and introducing new features.","status":"active","version":"5.0.1","language":"python","source_language":"en","source_url":"https://github.com/saghul/pycares","tags":["dns","async","networking","c-ares","resolver","low-level"],"install":[{"cmd":"pip install pycares","lang":"bash","label":"Install Pycares"},{"cmd":"pip install pycares[idna]","lang":"bash","label":"Install with IDNA 2008 support"}],"dependencies":[{"reason":"Required for the Python C interface; version 1.5.0 or higher is needed for Python < 3.14, and 2.0.0b1 or higher for Python >= 3.14.","package":"cffi","optional":false},{"reason":"Provides IDNA 2008 encoding support; otherwise, the built-in IDNA 2003 codec is used.","package":"idna","optional":true},{"reason":"The underlying C library for asynchronous DNS resolution. pycares bundles c-ares by default, but a system-wide c-ares can be used by setting PYCARES_USE_SYSTEM_LIB=1 during build.","package":"c-ares","optional":false},{"reason":"Required (version >= 3.5) to build pycares from source, as it's used to compile the bundled c-ares library.","package":"cmake","optional":false}],"imports":[{"symbol":"pycares","correct":"import pycares"}],"quickstart":{"code":"import pycares\nimport socket\n\ndef callback(result, error):\n    if error:\n        print(f\"Error: {error}\")\n        return\n    if result:\n        for record in result.answer:\n            if record.type == pycares.QUERY_TYPE_A:\n                print(f\"A record for {record.name}: {record.data.addr}\")\n            elif record.type == pycares.QUERY_TYPE_AAAA:\n                print(f\"AAAA record for {record.name}: {record.data.addr}\")\n            elif record.type == pycares.QUERY_TYPE_MX:\n                print(f\"MX record for {record.name}: priority={record.data.priority}, exchange={record.data.exchange}\")\n            # Add other record types as needed\n    else:\n        print(\"No records found.\")\n\n\n# Using a simple select-based event loop\nchannel = pycares.Channel(timeout=5.0)\n\n# Query for A records\nchannel.query(\"google.com\", pycares.QUERY_TYPE_A, callback=callback)\n\n# Query for MX records\nchannel.query(\"example.com\", pycares.QUERY_TYPE_MX, callback=callback)\n\n# Basic event loop processing\nwhile True:\n    read_fds, write_fds = channel.getsockname()\n    if not read_fds and not write_fds:\n        break\n    \n    # In a real application, use an actual event loop (e.g., asyncio, Tornado, Gevent)\n    # For this simple example, we block briefly\n    try:\n        rlist, wlist, xlist = socket.select(read_fds, write_fds, [], 1.0)\n    except socket.error as e:\n        print(f\"Socket error in select: {e}\")\n        break\n\n    channel.process_fd(rlist, wlist)\n","lang":"python","description":"This quickstart demonstrates how to perform asynchronous DNS queries for A and MX records using `pycares`. It sets up a `Channel` and makes two queries with a shared callback function. A basic `select`-based loop is used to process file descriptors and handle the asynchronous responses. In a production environment, `pycares` is typically integrated with a more robust event loop like `asyncio` (via `aiodns`), `Tornado`, or `Gevent`."},"warnings":[{"fix":"Update your result parsing logic to expect `DNSResult` objects with `answer`, `authority`, and `additional` sections, and access record data via `record.data.addr`, `record.data.exchange`, etc. Refer to the v5.0.0 migration guide for details.","message":"The DNS query results API was completely rewritten in v5.0.0. Results are now returned as structured dataclasses (`DNSResult`, `DNSRecord`, and specific `RecordData` types like `ARecordData`, `MXRecordData`, etc.) instead of a list of record-specific objects. Existing code accessing results will break.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Pass all `Channel` constructor arguments (e.g., `timeout`, `flags`, `lookups`) and the `callback` argument to query methods as keyword arguments. Remove any explicit `event_thread` arguments.","message":"In v5.0.0, the `Channel` constructor arguments and the `callback` parameter for query methods are now strictly keyword-only. The `event_thread` parameter has also been removed, as event thread mode is now implicit.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Ensure your application decodes TXT record data (e.g., `record.data.data.decode('utf-8')`) if string representation is required.","message":"As of v5.0.0, TXT record data is returned as bytes instead of strings. This change affects how TXT record content should be handled.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Install CMake (version 3.5+) on your system before attempting to build `pycares` from source (e.g., `apt-get install cmake` on Debian/Ubuntu, `brew install cmake` on macOS).","message":"Pycares v5.0.0 switched its build system for the bundled c-ares library to CMake. Building from source now requires CMake version 3.5 or higher to be installed on the system.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Ensure `Channel` objects are explicitly kept alive and properly managed for the entire duration of any pending DNS queries. Implement robust lifecycle management, especially in long-running or highly concurrent applications. Avoid creating `Channel` objects per-request that might be prematurely destroyed.","message":"Improper management of `pycares.Channel` objects, particularly allowing them to be garbage collected while DNS queries are still pending, can lead to a use-after-free vulnerability, causing a fatal Python interpreter crash.","severity":"gotcha","affected_versions":"<=5.0.1 (general concern, specific fixes likely in 5.x)"},{"fix":"When developing or testing, ensure a stable network connection and a properly configured DNS resolver. Account for network-related errors in your application's error handling for DNS lookups.","message":"DNS queries made by `pycares` are real network operations. Consequently, tests and examples often require active internet access and can be sensitive to network conditions or DNS server configurations, potentially leading to environment-specific failures.","severity":"gotcha","affected_versions":"All"},{"fix":"Remove calls to `Channel.getsockname()`. For integrating `pycares` with custom event loops, refer to the v5.0.0 migration guide for updated methods, typically involving `channel.poll()`, `channel.fd`, or `asyncio` integration.","message":"The `Channel.getsockname()` method has been removed in v5.0.0. Code relying on this method for manual polling of file descriptors will encounter an AttributeError.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"The `getsockname` method on `Channel` objects has been removed. Instead of manually polling file descriptors via `select.select` and `getsockname`, integrate `pycares` with an event loop using `channel.loop()` or by registering `channel.fileno()` with your event loop and calling `channel.handle_event(fd, flag)` when events are ready. Refer to the v5.0.0 migration guide or updated examples for detailed event loop integration.","message":"The `getsockname` method has been removed from the `pycares.Channel` object. This impacts custom event loop integrations that previously relied on `getsockname` to obtain file descriptors for polling.","severity":"breaking","affected_versions":">=5.0.0"}],"env_vars":null,"search_vec":"'5.0.1':53 'activ':48 'address':57 'applic':44 'are':18,69 'async':65 'asynchron':2,13 'block':33 'bug':58 'c':17,20,68 'c-are':16,67 'current':50 'dns':3,24,34,64 'enabl':30 'featur':63 'fix':59 'high':41 'high-perform':40 'interfac':14 'introduc':61 'level':73 'librari':21,46 'lookup':35 'low':72 'low-level':71 'maintain':49 'make':36 'modul':9 'name':27 'network':43,66 'new':62 'non':32 'non-block':31 'perform':23,42 'provid':11 'pycar':1,5 'python':8 'regular':55 'releas':56 'request':25 'resolut':28 'resolv':4,70 'suitabl':38 'version':52","created_at":"2026-04-05T14:32:07.266173+00:00","updated_at":"2026-04-16T18:21:20.868332+00:00","problems":[{"fix":"Ensure that your system has the necessary build tools and Python development headers. For Debian/Ubuntu, run: `sudo apt-get update && sudo apt-get install build-essential python3-dev`. For Fedora/RHEL: `sudo dnf groupinstall \"Development Tools\" && sudo dnf install python3-devel`. For macOS, install Xcode Command Line Tools: `xcode-select --install`. Then, try `pip install pycares` again.","cause":"This error typically occurs during installation when required C compilation tools (like `gcc` or `clang`) or Python development headers are missing on the system, preventing the `pycares` C extension from being built.","error":"ERROR: Failed building wheel for pycares"},{"fix":"Reinstall `pycares`, potentially forcing a source build to ensure the C extension is properly compiled: `pip install --upgrade --force-reinstall --no-binary pycares pycares`. Ensure all build dependencies mentioned in the previous fix are also installed.","cause":"This error indicates that the `pycares` C extension module, `_cares`, was not correctly built or cannot be found by Python, often due to a failed or incomplete installation, or issues within a virtual environment.","error":"ModuleNotFoundError: No module named 'pycares._cares'"},{"fix":"Upgrade your `pycares` installation to the latest version or a version compatible with the dependent library's requirements: `pip install --upgrade pycares`.","cause":"This `AttributeError` arises when a dependent library (such as `aiodns`) attempts to use a function or constant (like `ares_query_a_result` or `QUERY_TYPE_CAA`) that exists in a newer version of `pycares`, but an older, incompatible version of `pycares` is currently installed.","error":"AttributeError: module 'pycares' has no attribute 'ares_query_a_result'"},{"fix":"Upgrade `pycares` to version 4.9.0 or newer, which includes a fix for this vulnerability: `pip install --upgrade pycares`. It is also recommended to explicitly close `pycares.Channel` objects when done or use them as context managers (e.g., `with pycares.Channel() as channel:`).","cause":"This fatal error is a result of a use-after-free vulnerability in `pycares` versions prior to 4.9.0, where a `Channel` object could be garbage collected while active DNS queries were still pending, causing a crash when c-ares attempted to access freed memory for callbacks.","error":"Fatal Python error: b_from_handle: ffi.from_handle() detected that the address passed points to garbage"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"5.0.1","cli_name":"","cli_version":null,"type":"library","homepage":null,"github":"http://github.com/saghul/pycares","docs":null,"changelog":null,"pypi":"https://pypi.org/project/pycares/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["http-networking"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-28","last_verified":"2026-08-27","next_check":"2026-07-28","install_tag":"verified"}}