All posts

GeoDNS follows the resolver

How GeoDNS chooses an address from the resolver that sent the query, and from a client prefix when that resolver includes one.

Written by NodeRings

A user in Amsterdam, using 1.1.1.1, looks up www.example.com. You have a VM in that city and a rule that sends Europe there. The answer comes back as Ashburn. The nameserver applied the rule it was able to see. The user was in Amsterdam. The packet we received came from a recursive resolver.

The source address is the resolver

The stub on the machine asks a resolver. The resolver asks the authoritative server, and the source address on that second packet is the resolver's. Steer on the source address and you are steering on where the resolver sits.

A resolver in the house, or at the ISP down the street, is close enough to the person who typed the name. Public resolvers are somewhere else, and they are anycast, so the place "1.1.1.1" occupies is whichever of their sites accepted the query.

Cloudflare's 1.1.1.1 sends that query with no client prefix. Their documentation says the resolver keeps the client address to itself. The exception they publish is a single debug name used between operators, not the lookups your zone receives. From our side that user is a Cloudflare site. People who hit the same site and ask for the same name can share one cached answer.

Cloudflare's 1.1.1.1 FAQ. The answer says 1.1.1.1 does not send the EDNS Client Subnet header, except for the debug name whoami.ds.akahelp.net.
From Cloudflare's 1.1.1.1 FAQ. The resolver does not send a client prefix. The debug name is the only exception they publish.

Google Public DNS attaches a prefix. 8.8.8.8 will carry a slice of the client address, and it refuses a slice tighter than a /24 on IPv4 or a /56 on IPv6. A /24 is 256 addresses. A neighborhood, a branch office, a piece of an ISP. Enough to tell Amsterdam from Ashburn. Coarse on purpose. The authoritative server learns a block of 256 addresses and stops there.

A user in Amsterdam asks 1.1.1.1 with no client prefix, or 8.8.8.8 with a /24. The nameserver locates whichever address arrived.
Same user, two resolvers. 1.1.1.1 arrives as itself. 8.8.8.8 arrives with a client prefix. The /24 in the drawing is a documentation prefix, RFC 5737, standing in for a real client block.

EDNS is extra room on the message

Early DNS messages topped out around 512 bytes and had no spare field for anything invented later. EDNS, RFC 6891, hangs an OPT record on the message, type 41, as metadata. It carries a UDP size, which is how answers got past that ceiling, and a list of options for everything bolted on since.

Client Subnet is option 8 in that list, RFC 7871. The resolver puts in an address family, a masked address, and how many bits of it are real. The answer can come back with a scope length, the width of block allowed to share the cache entry. A scope of 0 means everyone. A wider scope means the answer was picked from something coarser than the /24, a country or the default, and the resolver may reuse it across that whole block.

A prefix on the query is the location we use. Leave the option off and we use the resolver's address. A VPN exit, a mobile carrier's gateway, and a carrier-grade NAT can still file the user in the wrong place, because the prefix is only as good as the address the resolver saw.

Every geo record has a default because of this. A quiet resolver, and a prefix that matches none of the places you listed, still needs an address.

Where the query falls through

More specific wins. An exact state or province beats a region group, the group beats the country, the country beats the continent, and whatever is left gets the default.

Say www is an A record with a 60 second TTL. The addresses here are from the documentation ranges in RFC 5737, so copying them into a lab stays off anyone's real host. Default 203.0.113.10, call that the Ashburn VM. Europe 203.0.113.20. The Netherlands 203.0.113.30. California 198.51.100.10.

A query the table places in California gets 198.51.100.10, even when a US West group also contains California. The exact row wins. The Netherlands gets 203.0.113.30, and the Europe address sits unused for that lookup. Germany, with Europe filled in and Germany left blank, gets Europe. Texas, with no Texas row and no United States row, gets Ashburn. Leave a country off the list and the query falls through to the default.

Match order from California, to a US West group, to the United States, to Europe, to the default address.
Priority, top to bottom. A California query stops on the first row. A German query with no Germany row stops on Europe. Texas, with no US row, reaches the default.

The Geo tab will run this for you before you cut the nameservers over. Pick the record, click a country or a state on the map, and the line under it is the address plus the rule that matched, something like matched region US-CA. That line is where a hole shows up. A continent standing in for a country you meant to add, a group you expected to cover a state that also has its own row, or a state left blank, so the query fell through to Ashburn.

TTL on these records is 30 to 60 seconds. An ordinary A record can live for an hour because the address is the address. A geo answer is a choice about the asker, and resolvers hold it for every similar asker they are allowed to serve from cache. After you edit the row, the previous city can stick until that TTL expires. The short timer is there so a correction spreads in a minute.

The types that take a location map are A, AAAA, CNAME, NAPTR, and SRV. You pick the place from a menu. Continents, countries, states and provinces, and the grouped regions such as US West or Canada East. The matching logic stays on our side. Ordinary records stay on the Records tab. DNS forbids a CNAME at the apex, so an apex alias is a normal ALIAS on that tab, and the geo map goes on www or another name the protocol lets you vary.

The Geo tab with a www A record, Europe, Netherlands, and California answers, and a GeoDNS check result for California.
The Geo tab, drawn from the console, using the documentation addresses above. The check line is what you get after clicking California.

Anycast shortens the question

The nameservers you put at the registrar are ans1.nrings.io and ans2.nrings.io. Use that pair on its own. They are anycast, so the lookup hits a nearby site and the question comes back quickly. The answer is still whatever the ladder returned. A quick round trip that yields 203.0.113.10 is a quick start on a long trip to Ashburn.

Anycast moves the nameserver toward the resolver. GeoDNS changes which origin the resolver is told to use. You want that second hop when the site itself is in more than one place, a VM in Amsterdam and a VM in Ashburn under one hostname. A single origin, with a continent row that returns the address you already published, is an extra rule on the same path.

The map is a map of address blocks. Those maps are wrong in ordinary ways. Roaming phones, corporate proxies, and privacy resolvers that send an empty prefix. 1.1.1.1 is in the last group by policy, so a large share of users on it will share the location of the Cloudflare site that took their query, and your default has to be a place you can serve them from. A system that watches the real path will beat a country row when the table is wrong. Steering in DNS is the decision you can make before the connection starts, using only what the resolver chose to attach.

GeoDNS is part of hosted DNS on NodeRings, same zone as the records and the signatures, on the DNS page. The steps are in the GeoDNS guide.