Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date: Wed, 19 Oct 2022 00:02:36 +0800
From: Tom Shen <sjiagc.dev@...il.com>
To: musl@...ts.openwall.com
Subject: gethostbyname2_r returns invalid IPv6 address if DNS server replies
 IPv4 address

Hi Musl team,

Recently we encountered an issue in requesting name resolution in Alpine
Linux with Musl.

Environment:
* Alpine Linux 3.14.2
* IPv6 module disabled
* musl-libc 1.2.2
* CoreDNS with "rewrite stop type AAAA A" configured

Reproduce steps:
1. getent hosts <any-name-only-has-ipv4-record>
2. Check output

Expected: Get correct IPv4 address, e.g. 10.96.36.74

Actual: Return an invalid IPv6 address, e.g. a60:244a::, which is the
actual IPv4 32-bit address followed by zeros.

Debugging:

1. Alpine Linux's getent (
https://github.com/alpinelinux/aports/blob/3.14-stable/main/musl/getent.c)
tries gethostbyname2 with AF_INET6 first, if no result, then calls with
AF_INET.
2. With requested family AF_INET6, gethostbyname2_r -> __lookup_name
-> name_from_dns_search sends a DNS request with RR_AAAA to CoreDNS.
3. In CoreDNS, we configured "rewrite stop type AAAA A", which results in
the RR_AAAA request type being rewritten to RR_A. So the response from
CoreDNS is: AF_INET (2) and 32-bit IP 10.96.36.74 (0x0a60244a below).

> (gdb) p addrs
> $55 = {{family = 2, scopeid = 0, addr = "\n`$J", '\000' <repeats 11
> times>, sortkey = 0}
> (gdb) x/4xb addrs[0]->addr
> 0x7fffffffe0d8: 0x0a    0x60    0x24    0x4a
>

4. In gethostbyname2_r, the result address family is assigned to the
request's family, regardless of the family in the response.

> h->h_addrtype = af;
> h->h_length = af==AF_INET6 ? 16 : 4;
>
 This results in the IPv4 address replied from CoreDNS is wrongly copied to
the result as IPv6 address which is a60:244a:: .
5. getent gets an IPv4 address, so it won't try AF_INET, rather directly
return the invalid IPv6 address a60:244a:: .

Suggested fix:
In gethostbyname2_r when adding answered addresses into the result, we need
to filter out the addresses with mismatching address family.

> for (i=0; i<cnt; i++) {
>     // if (addrs[i].family != h->h_addrtype) continue; // need to fix the
> index of h->h_addr_list too
>     h->h_addr_list[i] = (void *)buf;
>     buf += h->h_length;
>     memcpy(h->h_addr_list[i], addrs[i].addr, h->h_length);
> }
>

Could you review this issue? Thanks in advance!

Best regards!
Tom Shen

Content of type "text/html" skipped

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.