ARES_GETADDRINFO(3)

πŸ“¦
version 1.34.9 Β· 5 versions
, in alpine 3.22, alpine 3.23, alpine 3.24, arch rolling, centos-stream 10, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu stonking

πŸ’– ARES_GETADDRINFO β€” a.k.a. the "bestie, who is this host and what service" function πŸ’–

okay so we're in the ares_getaddrinfo(3) manual page, Library Functions Manual edition, and honestly? this one's a whole vibe. sit down, grab a strawberry, let's get into it. πŸ“βœ¨


✨ NAME ✨

ares_getaddrinfo β€” kick off a host query by name and service. that's it, that's the job. πŸ‘‘


πŸ¦‹ SYNOPSIS πŸ¦‹

#include <ares.h>

typedef void (*ares_addrinfo_callback)(void *arg, int status,
                                       int timeouts,
                                       struct ares_addrinfo *result)

void ares_getaddrinfo(ares_channel_t *channel, const char *name,
                      const char* service,
                      const struct ares_addrinfo_hints *hints,
                      ares_addrinfo_callback callback, void *arg)

πŸ’… DESCRIPTION πŸ’…

so ares_getaddrinfo(3) starts a host query by name on the name service channel that channel points at. the name and service params are the hostname and the service, both as NULL-terminated C strings.

here's the tea tho: either name or service may be NULL, but not both. literally not both, bestie. if name is NULL, the addresses you get back are synthesized from service: the wildcard address (0.0.0.0 or ::) comes back when ARES_AI_PASSIVE is set in ai_flags, otherwise you get the loopback address (127.0.0.1 or ::1).

the hints parameter is a ares_addrinfo_hints structure, and she's built like this:

struct ares_addrinfo_hints {
  int ai_flags;
  int ai_family;
  int ai_socktype;
  int ai_protocol;
};

let's go field by field, no skipping, i don't play that 🫢

  • ai_family β€” says which address family you want. AF_UNSPEC means give me both AF_INET and AF_INET6. indecisive queen behavior, love that for us.
  • ai_socktype β€” which socket type you want, like SOCK_STREAM or SOCK_DGRAM. setting it to 0 means any type, we're flexible.
  • ai_protocol β€” setting this to 0 means any protocol. again: flexible.
  • ai_flags β€” extra options, and they're all listed right down below. scroll, babe.

🌸 the flags, one by one, no crumbs left 🌸

  • ARES_AI_NUMERICSERV β€” if this is set, the service field gets treated as a numeric value.
  • ARES_AI_PASSIVE β€” if this is set and name is NULL, the returned addresses will use the wildcard address (0.0.0.0 or ::), which is the move for bind(2)ing a socket that's gonna accept connections. if it's not set and name is NULL, you get the loopback address (127.0.0.1 or ::1) instead.
  • ARES_AI_CANONNAME β€” the ares_addrinfo structure will return a canonical names list. cute, we love a glow-up name.
  • ARES_AI_NOSORT β€” result addresses will not be sorted, and no connections to resolved addresses will be attempted. chaotic? maybe. valid? absolutely.
  • ARES_AI_ENVHOSTS β€” read the hosts file path from the environment variable CARES_HOSTS.

when the query is complete or has failed, the ares library invokes callback. and heads up: completion or failure may happen immediately, or it may happen during a later call to ares_process(3), ares_destroy(3) or ares_cancel(3). so like… don't assume it's instant. πŸ™ˆ

when the associated callback is called, it is called with a channel lock, so care must be taken to make sure any processing is minimal, to prevent DNS channel stalls. keep it short in there, bestie, we're holding the lock. πŸ”’

also: the callback may be triggered from a different thread than the one which called ares_getaddrinfo(3). yes, different thread. not the same one. we don't make the rules. πŸ’€

and for integrators running their own event loops and not using ARES_OPT_EVENT_THREAD: care needs to be taken to ensure any file descriptor lists are updated immediately within the eventloop when notified. like, immediately immediately. no "one sec". ⏰


πŸŽ€ the callback arguments, decoded πŸŽ€

the callback argument arg is copied from the ares_getaddrinfo(3) argument arg. matching set, as it should be. ✨

the callback argument status tells you whether the query succeeded and, if it didn't, how it went wrong. it may have any of these values:

  • ARES_SUCCESS β€” the host lookup completed successfully. slay. πŸ‘‘
  • ARES_ENOTIMP β€” the ares library does not know how to find addresses of that type family.
  • ARES_ENOTFOUND β€” the name was not found. she's not here, girl. 😭
  • ARES_ENOMEM β€” memory was exhausted.
  • ARES_ESERVICE β€” the textual service name provided could not be dereferenced into a port.
  • ARES_ECANCELLED β€” the query was cancelled.
  • ARES_EDESTRUCTION β€” the name service channel channel is being destroyed; the query will not be completed. rip. πŸ’€

🌈 on success: the result 🌈

on successful completion of the query, the callback argument result points to a struct ares_addrinfo, and she contains two linked lists β€” one with resolved addresses, and another with canonical names. also included is the official name of the host (analogous to gethostbyname() h_name). main character energy fr fr.

struct ares_addrinfo {
  struct ares_addrinfo_cname *cnames;
  struct ares_addrinfo_node  *nodes;
  char *name;
};

the ares_addrinfo_node structure is similar to RFC3493 addrinfo, but without canonname and with an extra ttl field. so like, a glow-up, but she's doing her own thing:

struct ares_addrinfo_node {
  int                        ai_ttl;
  int                        ai_flags;
  int                        ai_family;
  int                        ai_socktype;
  int                        ai_protocol;
  ares_socklen_t             ai_addrlen;
  struct sockaddr           *ai_addr;
  struct ares_addrinfo_node *ai_next;
};

the ares_addrinfo_cname structure is a linked list of CNAME records, where ttl is a time to live, alias is a label of the resource record, and name is a value (canonical name) of the resource record. see RFC2181 10.1.1. CNAME terminology. very much iykyk.

struct ares_addrinfo_cname {
  int                         ttl;
  char                       *alias;
  char                       *name;
  struct ares_addrinfo_cname *next;
};
the reserved memory has to be deleted by ares_freeaddrinfo(3). do NOT forget this one, bestie. clean up after yourself, it's giving responsible. 🧚

⭐ the sorting rules ⭐

the result is sorted according to RFC6724 except:

  • Rule 3 (Avoid deprecated addresses)
  • Rule 4 (Prefer home addresses)
  • Rule 7 (Prefer native transport)
please note that the function will attempt a connection on each of the resolved addresses as per RFC6724. she's checking in on every single one of them. thorough queen.

🌸 AVAILABILITY 🌸

this function was added in c-ares 1.16.0, released in March 2020. vintage, but not that vintage. πŸ’œ


πŸ’œ SEE ALSO πŸ’œ


and that's the whole page, bestie!! this one shipped from the Library Functions Manual and was dated 4 November 2018 β€” yeah, 2018, we been knew. mwah, go forth and resolve responsibly. πŸ’–βœ¨πŸŽ€πŸ¦‹