DDEV claims you have no internet connection, when you clearly do (and fills up your /etc/hosts as a result).

When I run, for example, ddev ssh, I always get the annoying error:

Internet connection not detected, see https://ddev.readthedocs.io/en/stable/users/faq/ for info.

Unfortunately, this isn’t the first time an annoying error of little effect got under my skin. If some error claims something to be true, when I quite clearly know it is not, I find myself constitutionally incapable of ignoring its ignorance.

According to the referenced documentation above, the problem is typically a “slow” DNS resolution for {rand10apha}.ddev.site, and so the fix is simply to increase the DNS timeout using ddev config global --internet-detection-timeout-ms=3000. If that fixes the issue for you, I guess you are done here. Thanks for stopping by (and hopefully your internet connection speed improves)!

Now, there is another potential causes of this issue, and I know I’m not alone in seeing the problem - hence this documentation. If the error nags at you like it does to me, but you don’t care about (or would even prefer) gunking up your local /etc/hosts file with numerous ddev.site entries, just use the following in each project:

ddev config --use-dns-when-possible=false

This can be run after the project is created, or as an argument during the initial config. ddev will no longer attempt it’s DNS request, and will happily modify /etc/hosts instead. No complaints, no false claims.

So…if you’re still reading at this point (curious, aren’t you?) here’s the scoop:

First off, I had not tried to do the actual DNS resolution that DDEV was trying to do. At this point, I had no idea what query ddev was attempting, my thinking being “DNS works fine, what’s ddev’s issue?” So instead, I was curious HOW ddev was doing this. There are numerous methods of retrieving a host name on GNU/Linux systems - gethostbyaddr, calling DNS directly, or using DBus to talk to systemd-resolved. I happened to not have that running, which was another reason this was my initial query.

ddev is written in the Go language. I found where the project was attempting to do the query (and now I would have a sample of the DNS query I still didn’t try it) and find it is using the built-in net library. Helpfully, the net library of Go supports using environment variables to provide some debugging output. There are two libraries that Go can use dependent upon some compiler tag, so I just set that variable (using export GODEBUG=netdns=2) and took a peek into the process to see which it was. A portion of the output while running ddev start:

Running   Command=ip address show dev docker0
go package net: built with netgo build tag; using Go's DNS resolver
go package net: hostLookupOrder(altjalxaln.ddev.site) = files,dns
Internet connection not detected, see https://ddev.readthedocs.io/en/stable/users/faq/ for info.

So, it’s using Go’s pure DNS resolver (rather than cgo). In either case, I it would not be using DBus anyway, and it should just work.

At this point, with a DNS name staring me in the face, I finally tried it: dig altjalxaln.ddev.site. Hmm… no result?!? OK - I guess it doesn’t just work. Getting somewhere, at least, even if I was wrong. How about if I use CloudFlare to resolve the DNS?:

dig @1.1.1.1 altjalxaln.ddev.site

; <<>> DiG 9.16.5 <<>> @1.1.1.1 altjalxaln.ddev.site
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62582
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;altjalxaln.ddev.site.		IN	A

;; ANSWER SECTION:
altjalxaln.ddev.site.	60	IN	A	127.0.0.1

;; Query time: 43 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Sat Aug 15 01:40:54 EDT 2020
;; MSG SIZE  rcvd: 85

Well, at least this whole “use DNS to figure out if we have internet” is making some sense finally. So…what the heck is wrong with MY DNS resolution?

Turns out, this is actually a security feature. My DNS is provided by a local DNSMASQ server. This software has a feature that prevents DNS results like the above, where some external DNS server answers with an IP that is non-routable/private: 127.0.0.1. The feature is described here:

--stop-dns-rebind
    Reject (and log) addresses from upstream nameservers which are in the private ranges. This blocks an attack where a browser behind a firewall is used to probe machines on the local network. For IPv6, the private range covers the IPv4-mapped addresses in private space plus all link-local (LL) and site-local (ULA) addresses. 

If you were that reader that didn’t mind gunking up your local /etc/hosts, I guess you might be onto something. While that’s a pretty specific attack vector, I’ll leave the feature enabled.

Instead, I’ll work around it for this case. If resolution of {something}.ddev.site to anything other than 127.0.0.1 is useful, I’m ignoring that. Instead, I just added an option to DNSMASQ to ask it to answer this query itself with a configuration line: address=/ddev.site/127.0.0.1. Now, I can let ddev use DNS, without it making any more false claims (grr!) NOR modifying my /etc/hosts. In this case, I’m on a desktop system, but if you float around with and see this on your laptop, you might want to still just disable the DNS lookup.