Bug 524 - Incorrect address ordering by getaddrinfo
Summary: Incorrect address ordering by getaddrinfo
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.3.3
: P2 normal
Target Milestone: ---
Assignee: GOTO Masanori
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-11-08 15:09 UTC by Fredrik Tolf
Modified: 2005-09-26 16:11 UTC (History)
1 user (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Last reconfirmed:


Attachments
Patch to fix this bug (274 bytes, patch)
2005-01-03 03:50 UTC, Fredrik Tolf
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Fredrik Tolf 2004-11-08 15:09:37 UTC
I call getaddrinfo on a host on my network, which has these two addresses:
192.168.0.7
2002:52b6:8514:100::3

The host I'm calling it on has these addresses:
192.168.1.254
2002:52b6:8514:200:76ff:fe3b:a3f4

The problem is that in the returned set of addresses, the IPv4 address is sorted
before the IPv6 address, even though it should be the opposite according to Rule
6, Section 6 in RFC 3484, which specifies that the address of higher precedence
should be sorted first. According to the default precedence table in RFC 3484,
IPv6 addresses have higher precedence than IPv4 addresses.
Comment 1 Fredrik Tolf 2004-11-08 15:16:50 UTC
It seems that there is an error in sysdeps/posix/getaddrinfo.c that causes this.
In the match_prefix function, there is this code snippet:

  for (idx = 0; ; ++idx)
    {
      unsigned int bits = list[idx].bits;
      uint8_t *mask = list[idx].prefix.s6_addr;
      uint8_t *val = in6->sin6_addr.s6_addr;

      while (bits > 8)
        {
          if (*mask != *val)
            break;

          ++mask;
          ++val;
          bits -= 8;
        }

      if (bits < 8)
        {
          if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits)))
            /* Match!  */
            break;
        }
    }

  return list[idx].val;

As you can see, there's no matchine case when there is exactly 8 bits left to
match, which causes the loop to go on with the next prefix in the list, as if it
didn't match, so as long as all prefixes have lengths that are divisible by 8,
the last value (with a 0 bit prefix) will always be returned.

I suggest changing the first case to while(bits >= 8) to resolve this.

Also, I have to say that I'm unsure about the match_prefix function and the
prefixlist struct in general. I'm haven't examined this in detail, but won't it
malfunction on LSB architectures if the bit number isn't divisible by 16, since
the bytes are stored in opposite order of what they are typed into the
prefixlists? It seems to me that the prefixlist arrays should be initialized
with the 8-bit entries in in6_u. Maybe that's just my imagination, though -- I
haven't actually tried debugging it.
Comment 2 Fredrik Tolf 2005-01-03 03:50:43 UTC
Created attachment 333 [details]
Patch to fix this bug

This patch fixes the bug described in the bug report.
Comment 3 Fredrik Tolf 2005-01-03 03:52:41 UTC
I added a patch (against CVS) that fixes this bug. I'd really like to see this
fixed.
Comment 4 Ulrich Drepper 2005-09-26 16:11:39 UTC
The patch seems correct, applied to the CVS trunk.