2

I have a weird issue; for a single connect request to a server that has a single AAAA record my device runs two A queries instead and fails to connect.

My setup is as follows:

  • LAN (a regular router) without IPv6 connectivity
  • Android 10 with only WiFi connectivity, having one fe80: and two fd14: addresses
  • Debian box, wired, running dnsmasq, acting as the DNS server for all devices
  • dnsmasq will reply that website foo.com has an IPv6 of the Debian box, and no IPv4

I can:

  • Connect from my phone to the Debian box using literal IPv6 address
  • Connect from other devices to foo.com
  • Connect to foo.com from JuiceSSH
  • Do ping6 foo.com successfully in Termux on the phone

What I can't do, I can't connect from my phone to the Debian box via foo.com using regular apps such as Chrome, or my own app. JuiceSSH is the weird exception. I tried making a new app, adding INTERNET permission and this bit of code only:

thread {
    Socket("foo.com", 9000)
}

This works consistently with the apps such as Chrome in that it doesn't connect and—from what I see in dsmasq logs—performs two A queries (both with NODATA-IPv4 response). It never performs an AAAA query. Inet*Address.getAllByName() behaves in a similar way. I tested with another device running Android 6, same outcome.

What's going on here?

4
  • I'm not an expert in networking, but Android doesn't fully support IPv6, check the status on the related question: Does Android have support for IPv6?
    – Andrew T.
    Commented Apr 9, 2021 at 19:51
  • @AndrewT. Some applications do resolve IPv6 on my device; also my app can connect to IPv6 for other users. So I keep thinking that something is weird about my setup
    – squirrel
    Commented Apr 9, 2021 at 19:55
  • I think that I stumbled upon a similar problem. Mine happens while using a IPv6 VPN, but probably the symptoms and result are all the same. I asked it here: android.stackexchange.com/q/244749/366910 Were you able to fix your problem or improve something on your end? Commented Jan 9, 2022 at 11:11
  • @MariusSiuram I weren't, sorry. I decided to stick with IPv4 in the end, oh well.
    – squirrel
    Commented Jan 9, 2022 at 12:10

1 Answer 1

2

Android's hostname resolver (InetAddress.getAllByName(), etc.) will skip AAAA queries unless the device has an IPv6 routing table entry that covers the magic address 2000::.

As a workaround, we could install radvd on some machine on the network and put something like this into its /etc/radvd.conf:

interface eth0 {
  AdvSendAdvert on;
  AdvDefaultLifetime 0;
  route 2000::/64 {};  # Workaround Android DNS resolver bug
};

According to whois, 2000::/64 is not assigned to anybody at present, and hopefully we'll have real IPv6 service by the time that changes. ;) (I would use 2000::/128, but my device sets /proc/sys/net/ipv6/conf/*/accept_ra_rt_info_max_plen to 64 and hence won't accept route prefixes longer than that.)

As for why Android does this, performing an AAAA query can add latency, especially on networks with old broken resolvers, so Google engineers are keen to skip them when they can. (See Chromium issue 40435291, a similar problem in another Google product.) Android's libc (bionic) apparently makes it difficult to properly determine if IPv6 is in use, hence the magic probe of 2000::. (Relevant source code.)

Note that Android (like most OSes) will still prefer the address that seems "most likely to work" as per the rules in RFC 6724. This is generally pretty good for us, because the rules involve routing table checks for each candidate address and will prefer addresses for which a route exists, but it also means it will prefer IPv4 over fc00::/7 ULA addresses (as per section 2.1).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .