CLI tool
c-ares/c-ares avatar
c-ares/c-ares

c-ares: the C DNS resolver library you embed instead of calling getaddrinfo

A C library for asynchronous DNS requests

2,191 stars699 forksCMIT

At a glance

What is it?
c-ares is an MIT-licensed C stub resolver that performs DNS queries asynchronously. It suits C and C++ applications that cannot afford a blocking lookup on the main thread, and it is a poor fit for anyone who just wants a resolver daemon to run.
Who is it for?
Adopt c-ares if you ship a C or C++ program that must resolve names without stalling a thread, and if you are willing to own the event loop integration yourself. Do not adopt it if you want a resolver process to configure and forget, or if your language runtime already exposes a non-blocking resolver.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What c-ares replaces, and why getaddrinfo is the thing it is replacing

The standard way a C program turns a hostname into an address is getaddrinfo. It is synchronous. When the name is not in cache, the calling thread stops until the answer arrives or the resolver gives up, and the timeout is not something the caller controls in any portable way. For a command line tool that is fine. For a server handling many connections, or a UI thread, it is not.

c-ares is a stub resolver library that answers that problem. The README describes it as providing "interfaces for asynchronous queries while trying to abstract the intricacies of the underlying DNS protocol", and says it was "originally intended for applications which need to perform DNS queries without blocking, or need to perform multiple DNS queries in parallel". Those are the two use cases. You hand c-ares a name, it returns immediately, and you get a callback when the answer or the failure arrives.

The intended audience is narrow and specific: people writing C or C++ network software who control their own event loop. The README goes further than that and recommends the library "in all network applications even if the initial goal of asynchronous resolution is not necessary", which is a stronger claim than the design strictly requires. A batch tool that resolves one name at startup gains little from the async machinery and takes on a dependency.

How the async query actually flows through your program

c-ares does not own a thread. It owns a state machine. You create a channel, which holds the resolver configuration and the in-flight queries, and you drive it from your own loop. The library tells you which file descriptors it is waiting on and how long until its next internal timeout, and you feed it back the readable and writable events.

The repository layout reflects this split. The public headers live under include/, the implementation under src/, and the documentation under docs/. The library builds a pkg-config file, libcares.pc.in in the source tree and libcares.pc.cmake in the CMake path, so downstream build systems can locate it the usual way. A CMake package config, c-ares-config.cmake.in, is generated too.

The consequence of the callback model is that every call site has to be restructured. You cannot resolve a name, then use the result on the next line. You resolve, return to the loop, and resume in a callback. That inversion is the whole cost of using c-ares, and it is why the library is a poor drop-in for code that already works synchronously.

Getting c-ares onto your machine and verifying what you downloaded

The README points at INSTALL.md for build information and at the release archives on c-ares.org for signed tarballs. The source tree carries both a CMakeLists.txt and a configure.ac, so either build path exists. The README also states the library "will build with any C89 compiler", which sets a low floor for older toolchains.

The README does not print a build command line. What it does print, in full, is the release verification procedure. Detached signatures ship alongside each tarball, and the project publishes two release keys.

bash
gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 27EDEAF22F3ABCEB50DB9A125CC908FDB71E12C2 # Daniel Stenberg
gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys DA7D64E4C82C6294CB73A20E22E3D13B5411B7CA # Brad House

With the keys in your keychain, the README gives the verify command for a downloaded tarball and its detached signature. The sample output in the README reports a good signature from Daniel Stenberg, followed by a warning that the key is not certified with a trusted signature. That warning is about your keyring, not about the artifact.

bash
% gpg -v --verify c-ares-1.29.0.tar.gz.asc c-ares-1.29.0.tar.gz

The project also generates SLSA provenance. The README shows how to fetch the provenance file and the artifact and check them with slsa-verifier, passing the source URI and the source tag.

bash
$ curl -sO https://github.com/c-ares/c-ares/releases/download/v1.34.3/c-ares-1.34.3.intoto.jsonl
$ curl -sO https://github.com/c-ares/c-ares/releases/download/v1.34.3/c-ares-1.34.3.tar.gz
$ slsa-verifier verify-artifact c-ares-1.34.3.tar.gz \
    --provenance-path c-ares-1.34.3.intoto.jsonl \
    --source-uri github.com/c-ares/c-ares \
    --source-tag v1.34.3

Once the library is built and linked, the first real use is to initialize a channel and start a query. The header is ares.h and the library is libcares. The option names and callback signatures are in the headers under include/ and in docs/; the README does not walk through a minimal program, so read those before writing the loop.

Release integrity, signatures and SLSA provenance

Supply chain checks are documented more thoroughly than the API in the README. Two mechanisms are described. The first is GPG: each c-ares-X.Y.Z.tar.gz has a matching .asc detached signature, and the README lists the fingerprints for Daniel Stenberg and Brad House, noting that some releasers sign with subkeys.

The second is SLSA provenance. The README states that the project generates provenance for its releases and shows a verification example using slsa-verifier against an intoto.jsonl file downloaded from the GitHub release, with the source URI and source tag passed as arguments. The sample output in the README reports a verified signature against a transparency log entry and a verified builder.

For a library that ends up inside other people's binaries, that level of release hygiene matters more than it does for an application. It is also the part of the documentation most likely to age, since the example pins a specific version and a specific verifier tool.

Where c-ares is the wrong tool

The blocking problem c-ares solves is already solved elsewhere in many stacks. If you are writing Go, Rust, Java or Python, your runtime or standard library already offers non-blocking resolution, and adding a C dependency buys you nothing. If you are writing a shell script, a resolver binary is what you want, not a library.

The second limitation is the integration burden. Because c-ares does not run its own thread, it must be wired into whatever loop you already have. If your application is a thread-per-connection C server with no central poll or select, adopting c-ares means either introducing an event loop or running the channel on a dedicated thread, which puts you back where getaddrinfo left you with extra steps.

Third, the README is a landing page, not a manual. It links to FEATURES.md, INSTALL.md and the docs directory, but the API surface is not described in the README itself. Anyone evaluating c-ares from the repository front page alone will not learn the callback signatures or the channel options. That is a documentation gap, not a capability gap, but it affects how long a first integration takes.

c-ares against the system resolver and against a validating resolver

The most direct alternative is the system resolver you already call through getaddrinfo. It requires no dependency, no build step and no loop integration. The difference is control: the system resolver applies the host's configuration, its caching daemon and its timeout policy, and it blocks. c-ares keeps the query inside your process and lets you set the servers, the timeouts and the retry behaviour yourself. The README frames this as an explicit goal, saying one aim is "to be a better DNS resolver than is provided by your system, regardless of which system you use".

A different alternative is a validating resolver such as libunbound, which performs DNSSEC validation itself rather than trusting an upstream recursive server. c-ares is a stub resolver: it asks a recursive server and returns what it gets. The README's RFC list includes record types such as TLSA, SVCB, HTTPS, URI and CAA, but record type support is not the same as validation. If your requirement is to prove an answer is authentic rather than to fetch it quickly, c-ares is the wrong layer.

Licence, maintenance and the cost of staying current

c-ares is MIT licensed, which the README notes makes it "suitable for both free and commercial software". The repository carries a LICENSES/ directory and a .reuse/ directory alongside LICENSE.md, which indicates REUSE-style per-file licence metadata. For static linking into a closed product, MIT imposes no copyleft obligation, though the usual requirement to preserve the copyright notice and permission text still applies. That is a description of the licence text, not legal advice; your own counsel decides how it applies to your distribution.

The last push to the repository was on 2026-07-07, the same day as the v1.34.8 release. The prior release, v1.34.7, was tagged on 2026-07-06, and v1.34.6 on 2025-12-08. Two releases one day apart suggests a fix landing immediately after a tag, which is worth noting if you pin versions: check RELEASE-NOTES.md between the two rather than assuming they are equivalent.

The upgrade cost is the API's history. c-ares has been developed for over twenty years, and the README says it is maintained against the latest DNS RFCs. That means the surface has grown. BACKPORTING.md exists in the tree, which tells you the project has a defined policy for getting fixes onto older branches, useful if you cannot move to the newest release. The practical upgrade path is to track the release notes for deprecations before bumping a pinned version in your build.

Editorial conclusion

Adopt c-ares if you ship a C or C++ program that must resolve names without stalling a thread, and if you are willing to own the event loop integration yourself. Do not adopt it if you want a resolver process to configure and forget, or if your language runtime already exposes a non-blocking resolver. Before committing, read INSTALL.md for the build options your platform needs, and check RELEASE-NOTES.md for the version you plan to pin, since the API has grown across the 1.x line.

Frequently asked questions

What is c-ares?

c-ares is a DNS stub resolver library written in C, MIT licensed, that provides asynchronous query interfaces and abstracts the underlying DNS protocol. The README says it was originally intended for applications that need to query DNS without blocking or need multiple queries in parallel.

Should I use a DNS resolver?

The README recommends c-ares in all network applications, even when asynchronous resolution is not required, on the grounds that it aims to be a better resolver than the one your system provides. The trade-off is that you take on a build dependency and must drive the library from your own event loop.

Is 8.8.8.8 a recursive DNS?

That is a general DNS question rather than a c-ares one, and the README does not discuss specific public resolvers. c-ares is a stub resolver, so it sends its queries to whichever recursive server it is configured with.

What are the three types of DNS queries?

The README does not enumerate query types. It lists the record types the library supports, including AAAA, SRV, NAPTR, TLSA, SVCB, HTTPS, URI and CAA, each with the RFC that defines it.

Is 1.1.1.1 a recursive DNS?

The README does not name any public resolver. What it does say is that c-ares is a stub resolver, which means it delegates recursion to whatever upstream server the application configures it to use.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/c-ares-c-ares.svg)](https://hysenlabs.com/projects/c-ares-c-ares)