getaddrinfo returns PTR name in ai_canonname when using DNS

Bug #1057526 reported by Timo Aaltonen on 2012-09-27
14
This bug affects 1 person
Affects Status Importance Assigned to Milestone
eglibc
Fix Released
Medium
eglibc (Debian)
Fix Released
Unknown
eglibc (Fedora)
Fix Released
Undecided
eglibc (Ubuntu)
High
Unassigned
Precise
High
Adam Conrad

Bug Description

Got pinged about this, not fixed in 12.04 yet. From the Redhat bug:

"We have verified that getaddrinfo() does reverse address calls to DNS when AI_CANONNAME is passed in hints.ai_flags and returns the PTR name of the forward resolved ip address as Canonical name.

The canonical name is arguably not what is returned by the PTR record for various reasons. Aside the fact that PTR record are often not under control of the the same people that control the A name, A names can also be roundrobin names and return multiple addresses. Picking one and returnings its PTR as canonical name seem highly questionable.

A CNAME -> A name resolution is welcome as the A name is arguably the Canonical name of a CNAME. But getaddrinfo shouldn't do PTR requests to the DNS.

We found this when testing ssh+GSSAPI auth on laptops that can properly set the A record for their name usin dynamic DNS updates but cannot change the PTR record of whatever network they are currently travelling in.
This breaks kerberos which needs the canonical (A record) name to construct the principal name used to request a ticket when rdns = false is set in krb5.conf and GSSAPITrustDNS is set to no in ssh (the default)."

We have verified that getaddrinfo() does reverse address calls to DNS when AI_CANONNAME is passed in hints.ai_flags and returns the PTR name of the forward resolved ip address as Canonical name.

The canonical name is arguably not what is returned by the PTR record for various reasons. Aside the fact that PTR record are often not under control of the the same people that control the A name, A names can also be roundrobin names and return multiple addresses. Picking one and returnings its PTR as canonical name seem highly questionable.

A CNAME -> A name resolution is welcome as the A name is arguably the Canonical name of a CNAME. But getaddrinfo shouldn't do PTR requests to the DNS.

We found this when testing ssh+GSSAPI auth on laptops that can properly set the A record for their name usin dynamic DNS updates but cannot change the PTR record of whatever network they are currently travelling in.
This breaks kerberos which needs the canonical (A record) name to construct the principal name used to request a ticket when rdns = false is set in krb5.conf and GSSAPITrustDNS is set to no in ssh (the default).

It turned out that setting ai_family triggers this behaviour.

When calling getaddrinfo with ai_flags = AI_CANONNAME, ai_family = AF_UNSPEC then the ai_canonname returned is as expected.

When calling getaddrinfo with ai_flags = AI_CANONNAME, ai_family = AF_INET then the ai_canonname returned contains the PTR name of the forward resolved IP address as described in comment 0.

Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

http://rhn.redhat.com/errata/RHSA-2011-1526.html

Changed in eglibc (Ubuntu):
importance: Undecided → High
Changed in eglibc (Ubuntu Precise):
importance: Undecided → High
Adam Conrad (adconrad) wrote :

The fix to the RedHat bug referenced here was a backport of commits that went into 2.15 and are, thus, included in precise. Is there a reproducer for this bug that shows it still being present in 2.15 on precise, or was it just an assumption that we hadn't fixed it, based on dates or something?

Changed in eglibc (Ubuntu):
status: New → Incomplete
Changed in eglibc (Ubuntu Precise):
status: New → Incomplete
Timo Aaltonen (tjaalton) wrote :

I'll let Marko comment on that :)

Myllynen (myllynen) wrote :

There seems to be two related issues but actually both on 12.10.

Some background information: on RHEL 6 both Firefox and ssh work as expected (i.e., rdns setting in krb5.conf is respected meaning that if DNS reverse mapping has not been set up properly then authentication fails when rdns = true but succeeds with rdns = false). On F18 Firefox works as expected but ssh fails, see https://bugzilla.redhat.com/show_bug.cgi?id=863350.

On Ubuntu 12.04 both Firefox/ssh work as expected. However, on Ubuntu 12.10 both ssh and Firefox fail to authenticate regardless rdns = false in krb5.conf.

I'd suggest you to test and verify with curl and/or Firefox to make sure libc/krb5 are ok and once verified then investigate ssh in more detail which seems to have an issue of its own.

Greg Hudson (ghudson) wrote :

I'm attaching a simple test program which can be used to see the problem, which appears to still be present in 12.10:

$ host ptr-mismatch.kerberos.org
ptr-mismatch.kerberos.org is an alias for www.kerberos.org.
www.kerberos.org has address 18.9.62.44
$ host www.kerberos.org
www.kerberos.org has address 18.9.62.44
$ host 18.9.62.44
44.62.9.18.in-addr.arpa domain name pointer KERBEROS-ORG.MIT.EDU.

$ cc canonname.c
$ ./a.out www.kerberos.org
www.kerberos.org
$ ./a.out -a www.kerberos.org
KERBEROS-ORG.MIT.EDU

$ ./a.out ptr-mismatch.kerberos.org
www.kerberos.org
$ ./a.out -a ptr-mismatch.kerberos.org
KERBEROS-ORG.MIT.EDU

Without AI_ADDRCONFIG, getaddrinfo does the right thing: it follows a CNAME record (like ptr-mismatch.kerberos.org) and returns the name of the A record. With AI_ADDRCONFIG, getaddrinfo performs a PTR lookup. This also happens if ai_family is set in the hint (e.g. to AF_INET); that path isn't exercised in the test program.

Greg Hudson (ghudson) wrote :

My test results were from 12.04, not 12.10. Sorry for the confusion.

Created attachment 6909
Test program demonstrating getaddrinfo issue

With today's master, getaddrinfo with AI_CANONNAME yields the right ai_canonname (the result of CNAME resolution but not PTR lookup) if no other hint fields are given. However, if hint.ai_family is set to INET6, it appears to do a PTR lookup. The attached test program demonstrates the problem (the first and third output lines in particular):

$ ./a.out ptr-mismatch.kerberos.org
AI_CANONNAME alone: www.kerberos.org
AI_ADDRCONFIG also: www.kerberos.org
ai_family AF_INET : KERBEROS-ORG.MIT.EDU
ai_family AF_INET6: Name or service not known

To clarify what's wrong: it was a common historic misunderstanding that "canonical" name meant reverse DNS lookups. This was a cause of bad lookup performance in applications that were using AI_CANNONNAME correctly and not respecting it to perform PTR lookups. For a reference on why the PTR lookup is incorrect, see the following paragraphs in POSIX:

From DESCRIPTION of getaddrinfo:

"If the AI_CANONNAME flag is specified and the nodename argument is not null, the function shall attempt to determine the canonical name corresponding to nodename (for example, if nodename is an alias or shorthand notation for a complete name).

Note:
Since different implementations use different conceptual models, the terms ``canonical name'' and ``alias'' cannot be precisely defined for the general case. However, Domain Name System implementations are expected to interpret them as they are used in RFC 1034.
A numeric host address string is not a ``name'', and thus does not have a ``canonical name'' form; no address to host name translation is performed. See below for handling of the case where a canonical name cannot be obtained."

And from APPLICATION USAGE:

"The term ``canonical name'' is misleading; it is taken from the Domain Name System (RFC 2181). It should be noted that the canonical name is a result of alias processing, and not necessarily a unique attribute of a host, address, or set of addresses. See RFC 2181 for more discussion of this in the Domain Name System context."

Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html

Created attachment 6912
Candidate fix

I stepped through the code and found that:

* In the good case (hint.ai_family == 0), line 569 of gaih_inet does not trigger and we continue on to the loop at line 832, using gethostbyname4_r functions. When the DNS function succeeds, we set canon from the result at line 892. This value of canon is later used for ai_canonname.

* In the bad case (hint.ai_family == AF_INET), line 569 of gaih_inet triggers and we use __gethostbyname2_r for the lookup. This branch of the code does not set canon, so later on at line 1119, canon is still NULL. The conditional there kicks in and sets canon using __gethostbyaddr_r on the first address.

I think the code which uses __gethostbyname2_r ought to be able to set canon using th.h_name. If I use the attached patch, my test program gives the correct answer with hint.ai_family == AF_INET.

Created attachment 6913
Candidate fix 2

This updated patch is more consistent with how other branches of the function set canon.

I believe h->h_name should still be valid by the time canon is used at the end of the function, because it lives in tmpbuf just like it does in the gethostbyname4_r case.

Another approach can be found at:

http://pkgs.fedoraproject.org/cgit/glibc.git/plain/glibc-fedora-gai-canonical.patch

which completely avoids the gethostbyname2_r path if AI_CANONNAME is requested, and also rips out the code to use gethostbyaddr_r for canonname. Although that change is much more invasive than my candidate fix, it has received more testing.

Greg Hudson (ghudson) wrote :

A corresponding Debian bug:

  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=550428

A recently filed (by me) upstream bug, containing a better test program, some analysis of why this happens, and a candidate fix:

  http://sourceware.org/bugzilla/show_bug.cgi?id=15218

A more invasive, but much better tested, fix which has been in Fedora for a while:

  http://pkgs.fedoraproject.org/cgit/glibc.git/plain/glibc-fedora-gai-canonical.patch

Changed in eglibc (Debian):
status: Unknown → New
Changed in eglibc:
importance: Unknown → Medium
status: Unknown → Confirmed
Changed in eglibc:
status: Confirmed → Fix Released

*** Bug 260998 has been marked as a duplicate of this bug. ***
Seen from the domain http://volichat.com
Page where seen: http://volichat.com/adult-chat-rooms
Marked for reference. Resolved as fixed @bugzilla.

Changed in eglibc (Debian):
status: New → Fix Released
Changed in eglibc (Ubuntu):
status: Incomplete → Fix Released
Adam Conrad (adconrad) on 2015-03-26
Changed in eglibc (Ubuntu Precise):
status: Incomplete → In Progress
assignee: nobody → Adam Conrad (adconrad)

Hello Timo, or anyone else affected,

Accepted eglibc into precise-proposed. The package will build now and be available at https://launchpad.net/ubuntu/+source/eglibc/2.15-0ubuntu10.12 in a few hours, and then in the -proposed repository.

Please help us by testing this new package. See https://wiki.ubuntu.com/Testing/EnableProposed for documentation how to enable and use -proposed. Your feedback will aid us getting this update out to other Ubuntu users.

If this package fixes the bug for you, please add a comment to this bug, mentioning the version of the package you tested, and change the tag from verification-needed to verification-done. If it does not fix the bug for you, please add a comment stating that, and change the tag to verification-failed. In either case, details of your testing will help us make a better decision.

Further information regarding the verification process can be found at https://wiki.ubuntu.com/QATeam/PerformingSRUVerification . Thank you in advance!

Changed in eglibc (Ubuntu Precise):
status: In Progress → Fix Committed
tags: added: verification-needed
Adam Conrad (adconrad) wrote :

Verified by mangling my local DNS a bit that the old eglibc exhibits the behaviour mentioned in the bug, and the eglibc in proposed fixes it.

tags: added: verification-done
removed: verification-needed
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package eglibc - 2.15-0ubuntu10.12

---------------
eglibc (2.15-0ubuntu10.12) precise; urgency=medium

  * cvs-vfprintf-multibyte.diff: Fix "memory exhausted" bug in who, by no
    longer parsing %s format arguments as multibyte strings (LP: #1109327)
  * cvs-__SSE_MATH__-feraiseexcept.diff: Check for __SSE_MATH__ in x86_64
    feraiseexcept to fix backported -m32 builds of GCC 4.8 (LP: #1165387)
  * cvs-canonical-name.diff: Don't incorrectly do a PTR lookup when asked
    to do a canonical lookup for a host using AI_CANONNAME (LP: #1057526)
  * cvs-atomic-fastbins.diff: Fix race in free() of fastbin (LP: #1020210)
 -- Adam Conrad <email address hidden> Wed, 25 Mar 2015 13:28:41 -0600

Changed in eglibc (Ubuntu Precise):
status: Fix Committed → Fix Released

The verification of the Stable Release Update for eglibc has completed successfully and the package has now been released to -updates. Subsequently, the Ubuntu Stable Release Updates Team is being unsubscribed and will not receive messages about this bug report. In the event that you encounter a regression using the package from -updates please report a new bug using ubuntu-bug and tag the bug report regression-update so we can easily find any regressions.

Changed in eglibc (Fedora):
importance: Unknown → Undecided
status: Unknown → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.