<aside> 🧭

Module 06 · The Resolver Side of a Linux Host

Every module so far used dig. Your applications do not use dig, and they do not take the same path. This module is about the layer that has silently shaped every result in this track — and about the single most confusing sentence in DNS support: "dig gives the right answer but the app connects somewhere else."

🧠 concept → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (answers hidden)

Prerequisite: Modules 01–04. You need /etc/resolv.conf and the stub resolver (01 B2), the trailing dot and FQDNs (01 A3), TTLs and caching (03), and the 5-second timeout mentioned in 01 B2.

</aside>


Part A · The path an application actually takes

A1 · getaddrinfo, not dig

<aside> 🚕

The analogy. Think of you and a taxi driver given the same destination.

You look it up on your phone and read off the coordinates. The driver has his own route, his own shortcuts, and a note on the dashboard about a road closure you know nothing about.

You will both talk confidently about "the way there" and mean different things. That is dig and your application — and when their answers disagree, neither is lying.

</aside>

<aside> 📖

Official docs: getaddrinfo(3) · nsswitch.conf(5) · resolv.conf(5)

</aside>

When curl, a browser or a Java process needs an address, it does not speak DNS. It calls a C library functiongetaddrinfo() — and hands over a name. Everything after that is the library's business.

flowchart TD
    APP["curl / python / java<br>calls getaddrinfo"] --> NSS["/etc/nsswitch.conf<br>which sources, in which order?"]
    NSS -->|"files"| HOSTS["/etc/hosts<br>NO DNS INVOLVED"]
    NSS -->|"dns"| STUB["stub resolver"]
    STUB --> RC["/etc/resolv.conf<br>nameserver · search · ndots"]
    RC --> QUERY["one or MORE queries<br>search list expansion"]
    QUERY --> SERVER["the configured resolver"]
    DIG["dig"] -.->|"skips nsswitch<br>skips /etc/hosts<br>skips the search list"| SERVER
    style HOSTS fill:#ef4444,color:#fff
    style DIG fill:#f59e0b,color:#fff
    style NSS fill:#8b5cf6,color:#fff

<aside> 🔑

dig is a DNS tool. getaddrinfo is a name resolution tool, and DNS is only one of the things it consults. That is the entire source of the confusion, and it is not a bug in either.

Three differences matter, and each one is a real production incident:

  1. dig never reads /etc/hosts. An entry there overrides DNS for the application and is invisible to dig
  2. dig does not use the search list unless you pass +search, so it may send a completely different name than your application does
  3. dig does not sort or filter the results, while getaddrinfo applies address-selection rules — including preferring IPv6

So "dig works but the app doesn't" is not a contradiction. It is a clue, and it points at this module.

</aside>


A2 · nsswitch.conf — the switchboard

<aside> 🎛️

The analogy. Think of the order in which you look for someone's phone number.

First the note stuck to your desk. Then the company directory. Then you ask around.

Whichever answers first wins, and you stop looking — so the note on your desk quietly outranks the official directory, forever, and nobody maintaining that directory can see it.

</aside>

<aside> 📖

Official docs: nsswitch.conf(5) · hosts(5)

</aside>

One line decides everything:

grep '^hosts' /etc/nsswitch.conf
hosts:          files dns
Source What it means
files /etc/hosts. Consulted first, and a match ends the search
dns The stub resolver, i.e. /etc/resolv.conf
myhostname systemd module: resolves the local hostname and localhost without any file
resolve Talks to systemd-resolved over its own socket, bypassing /etc/resolv.conf entirely
mdns4_minimal Multicast DNS for .local. Note [NOTFOUND=return] after it — it stops the search

<aside> ⚠️

Order is policy, and the order is left to right. files dns means a /etc/hosts entry always beats DNS — which is how you pin a hostname during a migration, and also how a forgotten line from a debugging session sends production traffic to a decommissioned server for six months.

The line to look for on modern Ubuntu and Fedora is resolve:

hosts: files resolve [!UNAVAIL=return] dns

That says: try /etc/hosts, then talk to systemd-resolved directly over its socket, and only fall back to the classic dns path if resolved is unavailable. On such a host, /etc/resolv.conf may not be consulted at all — which is why editing it has no effect and why C1 exists.

</aside>