Skip to content

dns: reach nameservers over IPv6 - #3

Open
david-yu wants to merge 1 commit into
ipv6/01-test-require-ipv6from
ipv6/02-dns-ipv6-nameservers
Open

david-yu wants to merge 1 commit into
ipv6/01-test-require-ipv6from
ipv6/02-dns-ipv6-nameservers

Conversation

@david-yu

@david-yu david-yu commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Part 2 of 10 of the IPv6 series, split out of #1 and rebased on current scylladb/seastar master. Based on #2, so the diff here is only this PR's commit.

Why

The resolver has returned AAAA records since the initial IPv6 support (2f3573178, 2019), but its c-ares socket glue is still what it was when the resolver was added (fea5d80d2, 2016: "Like seastar, only handles ipv4 atm"). It opens AF_INET sockets and throws "No ipv6 yet" for an AF_INET6 nameserver, so a host whose only nameserver is IPv6 (an IPv6-only Kubernetes pod, an IPv6-only VM) cannot resolve anything: c-ares reports ARES_ECONNREFUSED for every server.

What

  • dns: reach nameservers over IPv6 (83b0ae335) — datagram channels follow the family c-ares asks for, sock_addr accepts AF_INET6, do_recvfrom copies the source by its real length, and servers reach c-ares through ares_set_servers_csv (ARES_OPT_SERVERS carries in_addr only). sock_addr now copies the address out with memcpy instead of reading it through a reinterpret_cast, which fixes scylladb/seastar#2288.

Relation to recent resolver work

  • 705ead2b6 (scylladb/seastar#3456) set ARES_AI_NOSORT because c-ares' RFC 6724 probe could not run through Seastar's socket hooks: IPv4-only socket creation, a throwing IPv6 connect, no getsockname hook. This PR removes the first two. getsockname is still missing, so NOSORT stays, and callers should still try each resolved address in turn, as that commit says.
  • 725128d8f (a TCP nameserver closing the connection) is untouched; its test runs next to the new one.

Testing

test_resolve_udp_ipv6_nameserver answers an A query from a mock nameserver bound to [::1]; on master it fails with std::invalid_argument: Servers must be ipv4 addresses. IPv4 nameservers take the same AF_INET branches as before.

On the core-aws VM (Ubuntu 24.04, GCC 14, C++23, RelWithDebInfo, GnuTLS and OpenSSL in one tree), this PR's head builds and passes dns, ipv6, socket, rpc, httpd, httpd_openssl, tls, tls_openssl, network_interface, websocket and unix_domain with SEASTAR_TEST_REQUIRE_IPV6=1, so none of their IPv6 cases skipped.

Stack

  1. tests, ci: fail instead of skip when IPv6 is expected #2 tests, ci: fail instead of skip when IPv6 is expected
  2. dns: reach nameservers over IPv6 #3 dns: reach nameservers over IPv6 ← this PR
  3. dns: literals for any family, c-ares error text, link-local nameservers #4 dns: literals for any family, c-ares error text, link-local nameservers
  4. net, http, rpc: dual-stack listeners (IPV6_V6ONLY, IPv4-mapped peers) #5 net, http, rpc: dual-stack listeners (IPV6_V6ONLY, IPv4-mapped peers)
  5. net: IPv6 zones and strict literal parsing #6 net: IPv6 zones and strict literal parsing
  6. tls: do not send IP literals in the SNI extension #7 tls: do not send IP literals in the SNI extension
  7. tls: verify server_name on OpenSSL, opt-in #8 tls: verify server_name on OpenSSL, opt-in
  8. net: ipv6_addr equality and hash, ipv4_addr(socket_address) throws instead of terminating #9 net: ipv6_addr equality and hash, ipv4_addr(socket_address) throws instead of terminating
  9. net: listen on an unspecified address binds any family #10 net: listen on an unspecified address binds any family
  10. http: build the Host header from an address in authority form #11 http: build the Host header from an address in authority form

The resolver has returned AAAA records since the initial IPv6 support
(2f35731), but its c-ares socket glue still dates from the IPv4-only
days (fea5d80): it created every UDP socket as AF_INET and rejected any
AF_INET6 sockaddr with "No ipv6 yet". A host whose resolv.conf lists an
IPv6 nameserver could not resolve anything: c-ares reported
ARES_ECONNREFUSED for every server. That is what an IPv6-only Kubernetes
pod looks like (CoreDNS over IPv6), and what an IPv6-only VM with a
link-local or ULA resolver looks like.

- do_socket creates the datagram channel with the family c-ares asked
  for instead of hardcoding AF_INET.
- sock_addr accepts AF_INET6, checks the sockaddr length, and copies the
  address out instead of reading it through a reinterpret_cast.
- do_recvfrom copies the source address by its real length; sockaddr is
  only wide enough for AF_INET, so an IPv6 source was being truncated
  and its length misreported.
- options.servers is installed with ares_set_servers_csv after channel
  creation; ARES_OPT_SERVERS carries in_addr only.

IPv4 nameservers take the same AF_INET branches as before.

Adds a unit test that answers a query from a mock nameserver bound to
[::1].

Fixes scylladb#2288
@david-yu
david-yu force-pushed the ipv6/02-dns-ipv6-nameservers branch from 23ecbcb to 83b0ae3 Compare September 25, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant