Currently, there's no way for a user of getaddrinfo(3) to easily learn about the results of DNS search path processing. There's the AI_CANONNAME flag, but that additionally takes into account CNAME processing, which is not always desirable.
I noticed the other day that Windows 7 (yes yes, laugh) added an AI_FQDN flag that offers this behavior. It signals to the resolver to set ai_canonname according to the expanded name *without* considering CNAME records. It turns out this is a fairly non-invasive change to getaddrinfo(3), so I went ahead and put together a diff yesterday (at least for the code; man page bits are still necessary). Anyway, I'm interested in knowing what people think of adding this feature. I don't know of any other getaddrinfo(3) implementations that support it, but djm@ mentioned that it would be nice to have in OpenSSH for host key validation. Index: include/netdb.h =================================================================== RCS file: /cvs/src/include/netdb.h,v retrieving revision 1.27 diff -u -p include/netdb.h --- include/netdb.h 2 Jun 2009 16:47:50 -0000 1.27 +++ include/netdb.h 1 Apr 2011 01:48:24 -0000 @@ -155,9 +155,10 @@ struct protoent { #define AI_NUMERICHOST 4 /* don't ever try hostname lookup */ #define AI_EXT 8 /* enable non-portable extensions */ #define AI_NUMERICSERV 16 /* don't ever try servname lookup */ +#define AI_FQDN 32 /* return the FQDN that was resolved */ /* valid flags for addrinfo */ #define AI_MASK \ - (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV) + (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_FQDN) #define NI_NUMERICHOST 1 /* return the host address, not the name */ #define NI_NUMERICSERV 2 /* return the service address, not the name */ Index: lib/libc/net/getaddrinfo.c =================================================================== RCS file: /cvs/src/lib/libc/net/getaddrinfo.c,v retrieving revision 1.71 diff -u -p lib/libc/net/getaddrinfo.c --- lib/libc/net/getaddrinfo.c 18 Nov 2009 07:43:22 -0000 1.71 +++ lib/libc/net/getaddrinfo.c 1 Apr 2011 01:48:24 -0000 @@ -309,7 +309,9 @@ getaddrinfo(const char *hostname, const char *servname if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) ERR(EAI_BADHINTS); /* xxx */ - if (hints->ai_flags & ~AI_MASK) + if ((hints->ai_flags & ~AI_MASK) != 0 || + (hints->ai_flags & (AI_CANONNAME | AI_FQDN)) == + (AI_CANONNAME | AI_FQDN)) ERR(EAI_BADFLAGS); switch (hints->ai_family) { case PF_UNSPEC: @@ -671,14 +673,13 @@ explore_numeric(const struct addrinfo *pai, const char pai->ai_family == PF_UNSPEC /*?*/) { GET_AI(cur->ai_next, afd, pton); GET_PORT(cur->ai_next, servname); - if ((pai->ai_flags & AI_CANONNAME)) { - /* - * Set the numeric address itself as - * the canonical name, based on a - * clarification in rfc2553bis-03. - */ - GET_CANONNAME(cur->ai_next, canonname); - } + /* + * Set the numeric address itself as + * the canonical name, based on a + * clarification in rfc2553bis-03. + */ + GET_CANONNAME(cur->ai_next, canonname); + while (cur && cur->ai_next) cur = cur->ai_next; } else @@ -764,7 +765,7 @@ explore_numeric_scope(const struct addrinfo *pai, cons static int get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) { - if ((pai->ai_flags & AI_CANONNAME) != 0) { + if ((pai->ai_flags & (AI_CANONNAME | AI_FQDN)) != 0) { ai->ai_canonname = strdup(str); if (ai->ai_canonname == NULL) return EAI_MEMORY; @@ -1129,7 +1130,7 @@ getanswer(const querybuf *answer, int anslen, const ch haveanswer++; } if (haveanswer) { - if (!canonname) + if (!canonname || (pai->ai_flags & AI_FQDN) != 0) (void)get_canonname(pai, sentinel.ai_next, qname); else (void)get_canonname(pai, sentinel.ai_next, canonname); @@ -1275,11 +1276,9 @@ found: /* cover it up */ res->ai_flags = pai->ai_flags; - if (pai->ai_flags & AI_CANONNAME) { - if (get_canonname(pai, res, cname) != 0) { - freeaddrinfo(res0); - goto again; - } + if (get_canonname(pai, res, cname) != 0) { + freeaddrinfo(res0); + goto again; } } return res0; @@ -1369,8 +1368,7 @@ nextline: /* cover it up */ res->ai_flags = pai->ai_flags; - if (pai->ai_flags & AI_CANONNAME) - (void)get_canonname(pai, res, canonname); + (void)get_canonname(pai, res, canonname); } } else res0 = NULL;