Bug#347358: libc6: getent skips IPv4 entries in /etc/hosts
Package: libc6
Version: 2.3.5-11
Severity: normal
If you add the following line to /etc/hosts:
1.2.3.4 x.y.z
getent will not find it:
$ getent hosts 1.2.3.4
$
This happens in both testing and unstable.
The problem seems to be in nss/getent.c:279
char addr[IN6ADDRSZ];
if (inet_pton (AF_INET6, key[i], &addr) > 0)
host = gethostbyaddr (addr, sizeof (addr), AF_INET6);
else if (inet_pton (AF_INET, key[i], &addr) > 0)
host = gethostbyaddr (addr, sizeof (addr), AF_INET);
else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
host = gethostbyname2 (key[i], AF_INET);
The second call to inet_pton recognizes the queried address as IPv4 but
calls gethostbyaddr with size of 16:
#0 0x400de776 in *__GI_inet_pton (af=2, src=0x804e078 "1.2.3.4",
dst=0x804e060) at inet_pton.c:56
#1 0x401341c7 in internal_getent (result=0x4012fe94,
buffer=0x804e060 "\200\215\"[ÜÑ\004\bná\004\b", buflen=1024,
errnop=0x4012e340, herrnop=0xbffffc88, af=2, flags=8)
at nss_files/files-hosts.c:50
#2 0x401350ea in _nss_files_gethostbyaddr_r (addr=0xbffffcb4, len=16, af=2,
result=0x4012fe94, buffer=0x804e060 "\200\215\"[ÜÑ\004\bná\004\b",
buflen=1024, errnop=0x4012e340, herrnop=0xbffffc88)
at nss_files/files-hosts.c:286
#3 0x400e4cc1 in __gethostbyaddr_r (addr=0xbffffcb4, len=16, type=2,
resbuf=Variable "resbuf" is not available.)
at getXXbyYY_r.c:207
#4 0x400e4a00 in gethostbyaddr (addr=0xbffffcb4, len=16, type=2)
at getXXbyYY.c:116
Notice that type=2 (AF_INET) but len=16.
Finally this breaks in _nss_files_gethostbyaddr_r:
while ((status =
internal_getent (result, buffer, buflen, errnop, herrnop, af,
(len == 16 ? 0x0008 : 0))) ==
NSS_STATUS_SUCCESS)
{
{
if (result->h_length == (int) len
&& !memcmp (addr, result->h_addr_list[0], len))
break;
}
}
The while loop returns IPv4 entries from /etc/hosts but their length is 4
so the 'result->h_length == (int) len' check will fail and they get skipped.
This code is generated by a macro in nss/nss_files/files-hosts.c:286
DB_LOOKUP (hostbyaddr, ,,
{
if (result->h_length == (int) len
&& ! memcmp (addr, result->h_addr_list[0], len))
break;
}, const void *addr, socklen_t len, int af)
Changing the size parameter in the second call to gethostbyaddr
to either 4 or 'sizeof (struct in_addr)' helps:
char addr[IN6ADDRSZ];
if (inet_pton (AF_INET6, key[i], &addr) > 0)
host = gethostbyaddr (addr, sizeof (addr), AF_INET6);
else if (inet_pton (AF_INET, key[i], &addr) > 0)
host = gethostbyaddr (addr, sizeof (in_addr), AF_INET);
else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
host = gethostbyname2 (key[i], AF_INET);
Or perhaps gethostbyaddr should check for mismatched af/size parameters?
-- System Information:
Debian Release: testing/unstable
APT prefers unstable
APT policy: (500, 'unstable'), (500, 'testing')
Architecture: i386 (i686)
Shell: /bin/sh linked to /bin/bash
Kernel: Linux 2.6.8-2-686
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)
-- no debconf information
Reply to: