Subject: lib/7899: getaddrinfo() / resolver weirdness with cnames and ipv6
To: None <gnats-bugs@gnats.netbsd.org>
From: Luke Mewburn <lukem@karybdis.cs.rmit.edu.au>
List: netbsd-bugs
Date: 07/03/1999 06:22:47
>Number: 7899
>Category: lib
>Synopsis: getaddrinfo() / resolver weirdness with cnames and ipv6
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: lib-bug-people (Library Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat Jul 3 06:05:00 1999
>Last-Modified:
>Originator: Luke Mewburn
>Organization:
ftp hackers r us
>Release: Sat Jul 3 22:34:47 EST 1999
>Environment:
System: NetBSD karybdis.cs.rmit.edu.au 1.4D NetBSD 1.4D (LUKEM) #143: Sat Jul 3 14:31:44 EST 1999 lukem@karybdis.cs.rmit.edu.au:/echidna/netbsd/src/sys/arch/i386/compile/LUKEM i386
>Description:
whilst working on some fixes to ftp I started getting errors like:
ftp: non-recoverable failure in name resolution: Undefined error: 0
for certain hosts.
further investigation reveals that getaddrinfo() fails for CNAME
lookups if the family is AF_UNSPEC, because AF_INET6 CNAME lookups
appear to be tried before AF_INET CNAME lookups in that function.
I wrote a little test program which basically does
res = gethostbyname2(argv[1], AF_INET)
printf("got inet %s", res ? res->h_name : hstrerror(h_errno));
res = gethostbyname2(argv[1], AF_INET6)
printf("got inet6 %s", res ? res->h_name : hstrerror(h_errno));
~/test> ./a.out emu
inet emu: returned emu.cs.rmit.edu.au
inet6 emu: failed with (4) No address associated with name
~/test> ./a.out emu
inet proxywww: returned emu.cs.rmit.edu.au
inet6 proxywww: failed with (3) Unknown server error
notice that:
* the first inet6 lookup fails with (4), because there isn't an
AAAA record for emu
* the second inet6 lookups fails with (3), because the CNAME
for proxywww points to an A record not an AAAA record.
for the second case, i whipped out gdb and did a break in
gethnamaddr.c::getanswer() and used __p_reply(answer) when the
breakpoint kicked in.
the first lookup (AF_INET CNAME) returned:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36896
;; flags: qr aa rd ra; Ques: 1, Ans: 2, Auth: 3, Addit: 3
;; QUESTIONS:
;; proxywww.cs.rmit.edu.au, type = A, class = IN
;; ANSWERS:
proxywww.cs.rmit.edu.au. 43200 IN CNAME emu.cs.rmit.edu.au.
emu.cs.rmit.edu.au. 43200 IN A 131.170.24.43
the second lookup (AF_INET6 CNAME) returned:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36897
;; flags: qr aa rd ra; Ques: 1, Ans: 1, Auth: 1, Addit: 0
;; QUESTIONS:
;; proxywww.cs.rmit.edu.au, type = AAAA, class = IN
;; ANSWERS:
proxywww.cs.rmit.edu.au. 43200 IN CNAME emu.cs.rmit.edu.au.
whilst this is probably correct from the resolver's point of view,
gethostbyname2() or getaddrinfo() should be able to cope with this.
>How-To-Repeat:
run a program which uses getaddrinfo (e.g, ftp) and try to lookup a
hostname that is a CNAME. my nameserver isn't ipv6 aware (it's a
netbsd 1.3.3 machine), and I don't have `options inet6' in
resolv.conf.
>Fix:
there's a couple of possible solutions, but I'd rather someone with
more in depth knowledge of the resolver (hi vixie! :-) and/or ipv6
(hi itojun! :-) to comment and/or provide a better solution:
* hack the appropriate bits of gethostbyname2 so that
when a cname lookup is requested by there's no data
returned, if qtype == AAAA or A then return NO_DATA
instead of NO_RECOVERY. this may break other stuff
though.
* instead hack _dns_gethtbyname() in a similar fashion.
* something else?
>Audit-Trail:
>Unformatted: