Er draait op dit moment een DNS-resolver op je machine. Je hebt hem niet geïnstalleerd, je hebt hem waarschijnlijk nooit geconfigureerd, en hij beantwoordt elke naamlookup die de bak doet. Op Fedora, Ubuntu en de meeste desktop-Linux is dat systemd-resolved, en hij zit daar stilletjes sinds de dag dat het systeem werd geïnstalleerd.
Hij kan drie dingen die het waard zijn om te hebben. Hij cachet, zodat dezelfde lookup niet twee keer het netwerk over hoeft. Hij valideert DNSSEC, zodat een vervalst antwoord wordt afgewezen in plaats van geloofd. En hij spreekt DNS over TLS, zodat het lokale netwerk niet elke naam kan meelezen die je opvraagt.
Standaard doet hij precies één daarvan. De andere twee staan uit, en op sommige distributies staan ze al op compileertijd uit, wat betekent dat de instelling die jij zou veranderen niet eens de instelling is die het besliste. Een validator die nooit valideert heeft geen enkel nut.
Dit is wat het ding werkelijk doet, gemeten op een draaiende Fedora 44-bak met systemd 259, en wat er verandert als je de andere twee aanzet. Inclusief wat je distributie op compileertijd voor je besloot, en hoeveel daarvan je gewoon kunt overrulen.
Wat je lookups eigenlijk beantwoordt
Begin met het eerlijke plaatje, want “het gebruikt /etc/resolv.conf” is op deze systemen al jaren niet meer waar.
systemd-resolved biedt zichzelf op vier verschillende manieren aan, en welke een programma gebruikt bepaalt wat het terugkrijgt.1 Het glibc-pad is nss-resolve, ingehaakt via /etc/nsswitch.conf. De native paden zijn D-Bus en Varlink, die het DNSSEC-oordeel en de interface-scope meedragen die getaddrinfo op geen enkele manier kan uitdrukken. En dan de stub-listener, een echte DNS-server op de loopback voor alles wat rauwe DNS spreekt en van niets hierboven weet.
Vier deuren, één daemon.
Op deze machine ziet die bedrading er zo uit:
$ ls -l /etc/resolv.conf
lrwxrwxrwx. 1 root root 39 May 30 13:56 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
$ cat /etc/resolv.conf
nameserver 127.0.0.53
options edns0 trust-ad
search damiendye.uk
$ grep ^hosts: /etc/nsswitch.conf
hosts: files myhostname mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns
resolve in die regel is nss-resolve. dns erachter is de traditionele nss-dns, die daar als terugval zit en alleen afgaat als resolved helemaal niet draait.
Er zijn twee stub-listeners, niet één
Iedereen kent 127.0.0.53. Minder mensen weten dat er een tweede is.
$ ss -lntup | grep ':53 '
udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:*
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.54:53 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
Het zijn niet twee adressen voor hetzelfde ding. De tweede doet met opzet minder:2
127.0.0.53 | 127.0.0.54 | |
|---|---|---|
| Rol | De volledige lokale resolver | Alleen proxymodus |
| Cache | Ja | Nee |
| DNSSEC-validatie | Ja, als het aanstaat | Nooit |
| LLMNR en Multicast DNS | Ja | Nee |
Synthetische namen (localhost, _gateway) | Ja | Nee |
| Upgradet naar DNS over TLS | Ja | Ja |
| Synthetische naam ervoor | _localdnsstub | _localdnsproxy |
| Je krijgt terug | Wat resolved besloot | Wat de upstream zei |
De documentatie is bot over de tweede kolom. Hij zal “pass most DNS messages relatively unmodified to the current upstream DNS servers and back, but not try to process the messages locally, and hence does not validate DNSSEC, or offer up LLMNR/MulticastDNS”.2
Dat maakt 127.0.0.54 het juiste doel voor een programma dat zijn eigen validatie wil doen, of dat het rauwe upstream-antwoord nodig heeft in plaats van resolveds interpretatie ervan.
Beide adressen hebben synthetische namen, _localdnsstub en _localdnsproxy, die zonder enige configuratie resolven.
Vier modi voor /etc/resolv.conf, niet drie
De modus wordt automatisch afgeleid uit wat het bestand is, en er zijn er vier.1
/etc/resolv.conf is | Wat het betekent | Clients die NSS omzeilen |
|---|---|---|
symlink naar run/systemd/resolve/stub-resolv.conf | De aanbevolen modus. Noemt 127.0.0.53 en de actuele zoekdomeinen | Gaan via resolved |
symlink naar /usr/lib/systemd/resolv.conf | Statisch, noemt 127.0.0.53, draagt geen zoekdomeinen | Gaan via resolved |
symlink naar run/systemd/resolve/resolv.conf | Noemt de echte upstreamservers, wordt actueel gehouden | Omzeilen resolved volledig |
| een echt bestand dat iets anders beheert | resolved leest het als afnemer, niet als leverancier | Omzeilen resolved volledig |
Die derde rij zet mensen op het verkeerde been. Het lijkt de nette optie, het wordt bijgehouden, en het betekent stilletjes dat elk programma dat resolv.conf rechtstreeks leest met de resolver van je ISP praat zonder cache, zonder validatie en zonder versleuteling, wat je ook in resolved.conf hebt ingesteld.
De optie trust-ad in het bestand hierboven doet er ook toe. Zonder die optie haalt glibc de AD-bit van het antwoord af voordat jouw programma het ziet, op de redelijke grond dat de bewering van een willekeurige resolver dat hij iets gevalideerd heeft niets waard is. Met 127.0.0.53 als naamserver komt die bewering van je eigen machine, dus trust-ad klopt hier en resolved schrijft hem voor je erin.
Over de systemd-complottheorieën
Vóór alle details, want dit is het onderwerp waar het altijd opduikt.
Als je bezwaar tegen wat volgt een theorie is over Lennart Poettering persoonlijk, of over de motieven van Red Hat, of over systemd als complot om je iets af te pakken, dan kun je ophoepelen, want ik heb geen zin om naar je verzinsels te luisteren.
Alles in dit bericht kwam van een draaiende machine: de broncode, de buildvlaggen, de geleverde binary, de manpages en het gemeten gedrag. Bij elke bewering staat een commando dat je zelf kunt draaien om het na te kijken. De buildvlaggen zijn openbaar. De broncode is openbaar. De ene standaardwaarde die ik werkelijk verkeerd vind, is gekozen door mensen die hun redenering hebben opgeschreven waar iedereen hem kan lezen en er ruzie over kan maken, wat precies is wat ik verderop doe.
Dat is een stuk meer transparantie dan je krijgt van de meeste software die je zonder een woord van klacht draait.
Kom met bewijs of hou op.
De cache is het deel dat gewoon werkt
Dit is de ene functie die overal standaard aanstaat, en het is degene die zonder enige configuratie zijn brood verdient.
De meting, op deze bak, over 32 domeinen. Leeg de cache, vraag de hele lijst op, vraag ze nog eens op, en lees de querytijd die dig meldt in plaats van het proces te klokken:
$ resolvectl flush-caches
$ for n in $NAMES; do dig +tries=1 @127.0.0.53 "$n" A | grep 'Query time'; done
| mediaan | gemiddelde | p90 | max | totaal voor 32 namen | |
|---|---|---|---|---|---|
| koude cache | 103,5 ms | 106,7 ms | 184 ms | 238 ms | 3.414 ms |
| warme cache | 0,0 ms | 0,5 ms | 1 ms | 3 ms | 16 ms |
3.414 milliseconden tegen 16. Dat is het hele argument voor een lokale cache, en het is waarom dit de standaard is.
Wel eerlijk zijn over wat dat getal is, overigens. Het is de besparing op een reeks van tweeëndertig namen die nog nooit waren opgezocht, tegen dezelfde reeks nog eens gedraaid, en geen enkele echte werklast lijkt op een van beide. Het nuttige getal is de staart en niet de mediaan: de slechtste lookup in die set kostte koud 238 ms en warm 3 ms. Een pagina die acht hostnamen binnenhaalt geeft niets om je mediaan, hij wacht op je traagste.
De knoppen
[Resolve]
Cache=yes # yes | no-negative | no
CacheFromLocalhost=no # default: do not cache answers from 127.0.0.1
StaleRetentionSec=0 # serve expired records when upstream is down
| Instelling | Standaard | Wat het doet |
|---|---|---|
Cache=yes | aan | Cache positieve en negatieve antwoorden |
Cache=no-negative | Alleen positieve antwoorden, voor als je het zat bent een negatieve TTL uit te zitten | |
CacheFromLocalhost=no | aan | Helemaal niet cachen als de upstream op 127.0.0.1 zit |
StaleRetentionSec=0 | uit | Verlopen records blijven serveren als de upstream niet meer antwoordt |
DNSCacheSize=4096 | 4096 | Records per scope. Alleen systemd 261 en later |
Die derde rij is degene die bijt. Is je upstream een dnsmasq of een unbound op de loopback, dan cachet resolved zijn antwoorden helemaal niet, op de grond dat het ding waarmee hij praat zelf al een cache is. Richt resolved op een filterende resolver op een andere host en je krijgt twee lagen caching. Richt hem op een op de loopback en je krijgt er één.
StaleRetentionSec= is de interessante, en die staat standaard uit. Zet hem aan, en als de upstream niet meer antwoordt blijft resolved records serveren voorbij hun TTL in plaats van te falen.2 Hij probeert altijd eerst de upstream. Het geldt niet voor NXDOMAIN, want een naam die niet bestaat is een volstrekt geldig antwoord en daar is niets ouds aan. Voor een laptop die in en uit dekking rijdt, of een machine die door een DNS-storing heen moet blijven werken, is dit het waard:
[Resolve]
StaleRetentionSec=1d
systemd 261 voegde daar cachegroottes per protocol aan toe, met DNSCacheSize=, MulticastDNSCacheSize= en LLMNRCacheSize=, elk standaard 4096 records en afgetopt op 2^24.3 Niet op deze bak, die 259 draait, en op geen enkele huidige stabiele distributierelease. Het is het waard te weten dat het eraan komt, want tot nu toe was de cachegrootte helemaal niet instelbaar.
De daemon gooit ook alles weg bij geheugendruk, wat verstandig is en af en toe verrassend als je probeert uit te vogelen waarom een cachehitratio er slecht uitziet.
Split DNS is de reden om hem te houden
Neem je één ding mee uit dit bericht, neem dan deze sectie, want dit is de functie die werkelijk iets doet wat de oude stub-resolver niet kon.
De traditionele resolv.conf heeft één lijst met naamservers voor de hele machine. Eén lijst. Breng een VPN op en iets moet hem overschrijven, wat betekent dat ofwel je interne namen werken en de rest van DNS via de bedrijfsresolver gaat, ofwel andersom. Er is geen derde optie. Het bestand kan er geen uitdrukken.
resolved routeert per query, per interface.1 Elke link heeft zijn eigen servers en zijn eigen domeinen, en een lookup gaat naar de link waarvan het domein het best bij de naam past, op labelaantal.
| Configuratie | Geschreven als | Effect |
|---|---|---|
| Zoekdomein | damiendye.uk | Achtervoegsel voor namen van één label, en routeert passende queries naar deze link |
| Alleen-routeren-domein | ~internal.example | Routeert passende queries naar deze link, wordt nooit als achtervoegsel gebruikt |
| Vangnetroute | ~. | Stuur alles wat nergens anders past naar deze link |
| Standaardroute | DNSDefaultRoute=yes | Neemt queries zonder match, zonder ~. te claimen |
Dus een laptop met een werk-VPN op krijgt dit:
resolvectl domain tun0 '~corp.example' '~10.in-addr.arpa'
resolvectl dns tun0 10.0.0.53
Namen onder corp.example en reverse lookups voor 10.0.0.0/8 gaan de tunnel in. Al het andere blijft over de lokale link naar buiten gaan zoals eerst. Niemands resolv.conf is herschreven, en valt de tunnel weg, dan gaan de routes mee.
Eén regel is het waard onomwonden te zeggen, want het is degene waar mensen naar grijpen en die ze verkeerd doen. ~. op een link betekent geef deze link de voorkeur voor alles. Het zorgt er ook impliciet voor dat geen enkele andere link nog standaardroute kan zijn. Wil je dat een link de restjes krijgt zonder de hele naamruimte te claimen? Zet DNSDefaultRoute=yes en laat ~. met rust.
Kijk wat hij besloten heeft in plaats van het aan te nemen:
$ resolvectl status
Link 3 (wlp4s0)
Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
Protocols: +DefaultRoute LLMNR=resolve -mDNS -DNSOverTLS
DNSSEC=no/unsupported
Current DNS Server: 192.0.2.53
DNS Servers: 192.0.2.53 2001:db8:1::53
DNS Domain: damiendye.uk
Default Route: yes
Elk adres in dit bericht komt uit de documentatiereeksen, 192.0.2.0/24 en 2001:db8::/32, dus plak ze niet in een configuratie en verwacht een antwoord.4 5 De cijfers en het gedrag zijn echt, van een draaiende machine. De adressen zijn plaatsvervangers, want een globaal IPv6-adres dat op de gebruikelijke manier is opgebouwd draagt het MAC-adres van de interface in zijn onderste helft, en er een publiceren geeft meteen een stuk hardware-inventaris weg.
Die -DNSOverTLS en die DNSSEC=no zijn de volgende twee secties.
Hij kan DNSSEC valideren
De daemon wordt upstream beschreven als “a caching and validating DNS/DNSSEC stub resolver”.1 De validerende helft is echt, het is geen omhulsel om iets anders heen, en het werkt. Hij staat alleen niet aan.
Hem per link aanzetten heeft geen sudo nodig, want resolvectl gaat via polkit en een actieve lokale sessie mag het:
$ resolvectl dnssec wlp4s0 yes
$ resolvectl status wlp4s0 | grep DNSSEC
DNSSEC=yes/supported
Dat achtervoegsel /supported is resolved die meldt wat hij vond toen hij de upstream aftastte, los van wat jij vroeg. yes/supported betekent dat je om validatie vroeg en dat de server het kan dragen. no/unsupported op een standaardinstallatie betekent dat niemand erom vroeg, dus dat niemand heeft afgetast.
Zodra het aanstaat komt elke lookup terug met een oordeel, en dat zijn er drie.
Hier zijn ze alle drie op deze machine, tegen echte namen:
$ resolvectl query damiendye.uk
-- Data is authenticated: yes; Data was acquired via local or encrypted transport: no
$ resolvectl query systemd.io
-- Data is authenticated: no; Data was acquired via local or encrypted transport: no
$ resolvectl query dnssec-failed.org
dnssec-failed.org: resolve call failed: DNSSEC validation failed: missing-key
(DNSKEY Missing: no SEP matching the DS found for dnssec-failed.org.)
damiendye.uk is ondertekend, dus de keten vanaf de root valideert en de data is geauthenticeerd. systemd.io is niet ondertekend, dus er valt niets te controleren en resolved zegt dat eerlijk in plaats van te doen alsof. Dat is het eigen domein van het systemd-project, en daar kom ik op terug. dnssec-failed.org wordt gepubliceerd met opzettelijk kapotte signaturen. Die faalt hard, met een diagnose die het precieze probleem benoemt.
Hier is het onderscheid dat verloren gaat. Insecure is geen mislukking. Een niet-ondertekende zone geeft data terug en vertelt je dat ze niet geverifieerd kon worden. Alleen een zone die beweert ondertekend te zijn en het dan niet kan bewijzen wordt afgewezen.
De keten zelf is zichtbaar als je hem wilt zien:
$ dig +short @127.0.0.53 uk DS
43876 8 2 A107ED2AC1BD14D924173BC7E827A1...
$ dig +short @127.0.0.53 damiendye.uk DS
2371 13 2 A5B2825C57899A5A15EE9703832C8358E0D19EF29DC72DD83C691ED77C33BD7F
$ dig +short @127.0.0.53 damiendye.uk DNSKEY
256 3 13 oJMRESz5E4gYzS/q6XDrvU1qMPYIjCWz...
257 3 13 mdsswUyr3DPW132mOi8V9xESWE8jTo0d...
De root staat garant voor uk, uk staat garant voor damiendye.uk, en de 257-sleutel ondertekent de 256-sleutel die de records ondertekent. Algoritme 13 daar is ECDSA P-256, wat je op een nieuwe zone wilt in plaats van de RSA die de uk-DS hierboven nog gebruikt.
Via de gewone stub krijgt een programma dat nog nooit van resolved heeft gehoord hetzelfde oordeel, als een AD-vlag:
$ dig @127.0.0.53 ietf.org A | grep flags
;; flags: qr rd ra ad;
$ dig @127.0.0.53 dnssec-failed.org A | grep status
;; ->>HEADER<<- status: SERVFAIL
En de daemon houdt een lopende telling bij, wat de snelste manier is om te zien of validatie iets doet:
$ resolvectl statistics
DNSSEC Verdicts
Secure: 134
Insecure: 62
Bogus: 0
Indeterminate: 2
Wat validatie kost
Hier ga ik je teleurstellen, want ik heb geprobeerd dit fatsoenlijk te meten en dat lukte niet.
Warm is het schoon en is het niets. Dezelfde 32 namen tegen een volle cache kostten 16 ms zonder validatie en 23 ms met. Noem het een afrondingsfout.
Koud is waar de kosten zouden moeten opduiken, en één client kan het niet isoleren. Ik draaide de reeks beide kanten op en kreeg tegenstrijdige antwoorden: in de ene volgorde leek validatie 74% trager, in de andere leek het sneller, wat onmogelijk is en je vertelt wat er werkelijk wordt gemeten. Welke reeks als tweede draait profiteert ervan dat de upstream-resolver alles al had opgehaald waar de eerste om vroeg. De variabele die domineert is niet validatie, het is wiens cache warm was.
Dus ik geef je geen getal waar ik niet achter kan staan. Wat waar is, is het mechanisme, en de documentatie stelt de vorm ervan onomwonden: validatie “requires retrieval of additional DNS data, and thus results in a small DNS lookup time penalty”.2 Een koude gevalideerde lookup loopt de delegatieketen af en haalt op elk niveau DS en DNSKEY op voordat hij kan antwoorden, dus hij kost extra retourtjes op namen waar nog niemand om heeft gevraagd, en helemaal niets op namen waar iemand wel om heeft gevraagd.
Wat ook de reden is dat dezelfde pagina waarschuwt dat de cache uitzetten “comes at a performance penalty, which is particularly high when DNSSEC is used”.2 De twee functies staan niet los van elkaar. Validatie is juist betaalbaar omdat de cache betekent dat je er één keer voor betaalt.
Wil je het echte getal voor je eigen netwerk, meet het daar. Eén client op één verbinding kan het je niet vertellen.
Waarom staat validatie dan uit
Omdat je distributie het uitzette toen ze het pakket bouwde, en dat deed ze om een reden die ze heeft opgeschreven.
Upstream systemd levert validatie aan. De buildoptie zegt het:
option('default-dnssec', type : 'combo',
choices : ['yes', 'allow-downgrade', 'no'],
value : 'allow-downgrade')
en de upstream-handleiding is het ermee eens: DNSSEC= “Defaults to allow-downgrade”.6
Kijk nu wat Fedora aan die build meegeeft:7
-Ddefault-dnssec=no
-Ddefault-dns-over-tls=no
-Ddefault-mdns=no
-Ddefault-llmnr=resolve
En wat Debian en Ubuntu meegeven:8
-Ddefault-dnssec=no
-Ddefault-llmnr=no
-Ddefault-mdns=no
-Ddns-over-tls=openssl
Dus het bestand op /usr/lib/systemd/resolved.conf op een Fedora-bak, degene met de kop “Entries in this file show the compile time defaults”, zegt #DNSSEC=no. Lees dat nog eens, want het doet iets sluws: de regel ziet eruit als de software die je zijn eigen standaard vertelt, en wat hij je werkelijk terugleest is de buildvlag van Fedora, met de echte standaard van upstream nergens op de pagina.
| Instelling | Upstream-standaard | Fedora-build | Debian/Ubuntu-build | Resultaat op deze bak |
|---|---|---|---|---|
DNSSEC= | allow-downgrade | no | no | DNSSEC=no |
DNSOverTLS= | no | no | no (gecompileerd met OpenSSL) | -DNSOverTLS |
MulticastDNS= | yes | no | no | -mDNS |
LLMNR= | yes | resolve | no | LLMNR=resolve |
Elk daarvan komt overeen met wat resolvectl status op deze machine afdrukt. Broncode, buildvlag, draaiend systeem, alle drie zijn het eens.
De redenering van Fedora staat in het wijzigingsvoorstel en is verfrissend bot. De functie “is known to cause compatibility problems with certain network access points”, en Fedora “is not prepared to handle an influx of DNSSEC-related bug reports”, dus hij gaat uit.9
Mag ik vragen waarom het antwoord op een functie die stukgaat op slechte netwerken is om hem voor iedereen uit te zetten, in plaats van allow-downgrade te leveren zoals upstream doet en hem zichzelf te laten uitzetten waar dat moet? Niet wie het besloot. Wat er in het proces daartoe leidde. Want allow-downgrade bestaat juist voor het captive-portalgeval, het is om precies die reden de standaard van upstream, en in plaats daarvan no leveren betekent dat een machine op een volstrekt goed netwerk ook geen validatie krijgt.
Om eerlijk tegenover ze te zijn: allow-downgrade heeft zijn eigen probleem, en dat is een echt probleem. De modus merkt een resolver op die geen DNSSEC kan en stopt stilletjes met valideren. Een aanvaller die jouw DNS-antwoorden kan vormgeven kan die detectie met opzet laten afgaan, en de documentatie zegt het onomwonden: het “makes DNSSEC validation vulnerable to ‘downgrade’ attacks”.2 Een beveiligingsfunctie die elke aanvaller kan uitzetten doet minder dan ze lijkt te doen.
Dus geen van beide standaarden is goed. no geeft je niets. allow-downgrade geeft je iets wat een aanvaller je kan afnemen, en yes geeft je het echte werk plus alles uit de volgende sectie.
Hoeveel van het web is eigenlijk ondertekend
Voordat je veel moeite in validatie steekt is het het waard te weten welk deel van je lookups het überhaupt kan beschermen. Dus vroeg ik resolved om het oordeel over de apex van tweeëndertig domeinen die dit onderwerp werkelijk aangaan: de organen die de standaard schreven, de clubs die de resolver leveren, en de infrastructuur die iedereen opzoekt of hij het nu wil of niet.
Zestien van de tweeëndertig. De helft.
| Ondertekend | Niet ondertekend | |
|---|---|---|
| Standaarden en registries | ietf.org, iana.org, icann.org, rfc-editor.org, ripe.net, isc.org, nlnetlabs.nl, nic.cz, afnic.fr, verisign.com | geen |
| Distributies en leveranciers | debian.org, fedoraproject.org, opensuse.org, almalinux.org | redhat.com, ubuntu.com, canonical.com, suse.com, rockylinux.org, archlinux.org |
| systemd zelf | geen | systemd.io, freedesktop.org |
| Infrastructuur | cloudflare.com, gov.uk | github.com, kernel.org, google.com, wikipedia.org, mozilla.org, apache.org, gnu.org, quad9.net |
Lees de eerste kolom van boven naar beneden. Elk standaardenorgaan en elke registry heeft ondertekend. Tien van de tien, geen uitzonderingen: de mensen die DNSSEC schreven, en de mensen die de registries draaien die de DS-records voor alle anderen publiceren. Ze hebben het werk op hun eigen zones gedaan.
Lees nu de derde rij van links naar rechts. systemd.io heeft geen DS. Het project dat de validerende resolver schreef waar dit hele bericht over gaat, heeft zijn eigen domein niet ondertekend, en freedesktop.org, waar zijn documentatie woont, ook niet. Daaronder is quad9.net ook niet ondertekend, en daar mag je even bij stilstaan: een publieke resolver wiens hele verkoopverhaal is dat hij DNSSEC voor je valideert, op een zone die niemand kan valideren.
En de leveranciers splitsen netjes langs één lijn. De communitydistributies hebben ondertekend. debian.org, fedoraproject.org, opensuse.org, almalinux.org. De bedrijven niet. redhat.com, ubuntu.com, canonical.com, suse.com. Dat zijn de vier organisaties die deze resolver verpakken en leveren aan het grootste deel van het Linux-landschap.
Daar zit geen gat in de technologie. Het protocol is al ruim vijftien jaar uit te rollen, het gereedschap is gratis, en de registries nemen het DS-record aan zonder ervoor te rekenen. Ik zeg het je voor niks: de mensen die de standaard schreven hebben ondertekend, en de meeste mensen die de software leveren niet.
Er is een scherpere versie van hetzelfde punt in gov.uk, dat wel ondertekend is, en dan dit doet:
$ dig +short @127.0.0.53 www.gov.uk CNAME
www-cdn.production.govuk.service.gov.uk.
$ dig +short @127.0.0.53 service.gov.uk DS
(nothing)
uk heeft een DS. gov.uk heeft een DS. service.gov.uk heeft er geen, dus de keten houdt daar dood op, en www.gov.uk resolvet insecure ook al is de apex erboven netjes ondertekend. Iemand heeft het werk op gov.uk gedaan en toen de echte website op een niet-ondertekende delegatie gericht. Half werk.
Dus als je een zone ondertekent, controleer de namen die mensen werkelijk typen. Een ondertekende apex die met een CNAME een niet-ondertekende CDN-zone in wijst levert je niks op.
DNS over TLS werkt, onder voorwaarden
DNS over TLS is geïmplementeerd, het is in elke gangbare build meegecompileerd, en het werkt. Het staat overal standaard uit, ook upstream, waar DNSOverTLS= “Defaults to no”.6
De configuratie is twee regels, en de tweede is degene die mensen missen:
[Resolve]
DNS=9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net
DNSOverTLS=yes
Die #dns.quad9.net is geen versiering. Hij bepaalt de naam die voor SNI en voor het valideren van het certificaat wordt gebruikt. Laat hem weg en het certificaat wordt in plaats daarvan “checked against the server’s IP”.2 Dat werkt bij de grote aanbieders omdat die IP-adressen in de SAN’s van hun certificaat zetten, maar het is de zwakkere controle, het gaat stuk zodra een aanbieder daarmee ophoudt, en het biedt je geen bescherming tegen omgeleid worden naar een ander adres dat toevallig een geldig certificaat voor zichzelf heeft. Fedora’s eigen magazine-artikel hierover laat de hostnaam weg,10 wat jammer is, want de syntaxis staat gewoon in de commentaren van het meegeleverde configuratiebestand.
Strikt en opportunistisch zijn heel verschillende instellingen
| Modus | Op een server die DoT ondersteunt | Op een server die dat niet doet | Authenticeert de server |
|---|---|---|---|
yes | Versleuteld | Alle lookups falen | Ja |
opportunistic | Versleuteld | Stilletjes platte tekst | Nee |
no | Platte tekst | Platte tekst | n.v.t. |
opportunistic leest als het verstandige midden en is dat meestal niet. De documentatie zegt het ronduit: in die modus is “the resolver is not capable of authenticating the server, so it is vulnerable to ‘man-in-the-middle’ attacks”,2 en iedereen die jouw verkeer op poort 853 kan laten vallen kan de downgrade afdwingen. Het beschermt je tegen passief meekijken op een netwerk waar niemand het probeert. Tegen iemand die het wel probeert doet het niks.
yes is de eerlijke instelling. Het betekent ook dat je, als hij geen verbinding kan maken, helemaal geen DNS krijgt, wat het waard is te weten voordat je het op een machine zet waar je niet naartoe kunt lopen.
Ik probeerde strikte DoT naar Quad9 vanaf deze bak en de query bleef hangen. Geen foutmelding, geen timeout, niets in de journal tussen het legen en mijn terugdraaien twee minuten later:
Sep 27 17:12:11 systemd-resolved[40105]: wlp4s0: Bus client set DNS server list to: 9.9.9.9#dns.quad9.net, ...
Sep 27 17:12:14 systemd-resolved[40105]: wlp4s0: Bus client set DNSOverTLS setting: yes
Sep 27 17:12:15 systemd-resolved[40105]: Flushed all caches.
Sep 27 17:14:39 systemd-resolved[40105]: wlp4s0: Bus client set DNS server list to: 192.0.2.53, ...
Ik kan je van hieruit niet vertellen of poort 853 op die verbinding bereikbaar is, want de shell waarvandaan ik de test draaide kon poort 443 ook niet bereiken en werd duidelijk zelf gefilterd. Wat het log wel laat zien is de faalmodus: strikte DoT die geen verbinding kan maken meldt niets nuttigs. Hij wacht. Zet je dit aan en wordt je DNS stil, kijk dan naar ss -tn dport = :853 voordat je naar resolved gaat zoeken.
Het fatsoenlijk testen
# does the transport actually come up
resolvectl flush-caches
resolvectl query ietf.org # expect: acquired via ... encrypted transport: yes
# is anything still going out in the clear
sudo tcpdump -ni any 'port 53 and not host 127.0.0.53'
Het tweede commando is degene die de waarheid vertelt. Met werkende DoT hoort er niets meer op poort 53 de machine te verlaten, en alles wat dat wel doet is een programma dat om de stub heen is gekomen.
DNS over HTTPS bestaat hier niet
Rechttoe rechtaan antwoord op de vraag: systemd-resolved ondersteunt geen DNS over HTTPS. Niet gedeeltelijk, niet achter een vlag, niet met een buildoptie die niemand aanzet. Er zit helemaal geen DoH in.
En dat is niet van de documentatie afgelezen, die simpelweg verouderd zou kunnen zijn. Het is wat de binary bevat:
$ strings /usr/lib/systemd/systemd-resolved | grep -icE 'application/dns-message|dns-query|:443'
0
$ grep -oE 'name="DNSOver[A-Za-z]*"' /usr/share/dbus-1/interfaces/org.freedesktop.resolve1.Manager.xml
name="DNSOverTLS"
Geen DoH-wireformat, geen HTTP/2, één versleutelingseigenschap op de D-Bus-interface en die is TLS. De volledige lijst met resolved.conf-directieven upstream komt op zeventien instellingen en geen daarvan noemt HTTPS.6
Erom is gevraagd. Issue #8639, “Add support for DNS-over-HTTPS to systemd-resolved”, werd geopend op 2 april 2018 en staat nog steeds open, met twee pull requests eraan en niets gemerged.11 Acht jaar en het loopt door.
Is dat de verkeerde keuze? Niet vanzelfsprekend, en het argument voor DoT is behoorlijk. Beide dragen DNS binnen TLS en beide houden dezelfde passieve waarnemer tegen. Het voordeel van DoH is dat het zich op poort 443 verstopt tussen al het andere, dus een netwerk dat versleutelde DNS wil blokkeren moet veel harder werken. Dat is werkelijk nuttig als de netwerkbeheerder de tegenstander is.
Het snijdt ook de andere kant op. Waar jij de beheerder bent, betekent die ononderscheidbaarheid dat je je eigen DNS ook niet kunt auditen, en elke applicatie die haar eigen DoH-client meelevert stopt met de systeemresolver te gebruiken, en zo krijg je een browser die je split DNS, je cache en je interne zones negeert. Op je eigen spul is een resolver die zichtbaar is op een bekende poort een voordeel.
Dus: bereikt DoT je resolver, gebruik het dan en je verliest niets. Is poort 853 geblokkeerd, dan heeft resolved geen antwoord en wil je een DoH-proxy ervoor, dnscrypt-proxy of cloudflared op de loopback met resolved daarop gericht. Caching en validatie blijven het werk van resolved. Alleen het transport verhuist.
Wat je distributie werkelijk levert
Dezelfde daemon gedraagt zich heel verschillend afhankelijk van wie hem verpakte. De dienst aanzetten is de makkelijke helft. De helft die wordt overgeslagen is hem inhaken in de netwerkgereedschappen die de distributie werkelijk gebruikt, en op een van deze vier is hij werkelijk niet ingehaakt tot je het zelf doet.
| Geïnstalleerd | Aangezet | nss-resolve ingehaakt | Configuratie komt via | Ondersteund | |
|---|---|---|---|---|---|
| Fedora (33+) | ja | ja | ja, in systemd-libs | NetworkManager | ja |
| Ubuntu | ja | ja | ja | netplan, dan NM of networkd | ja |
| Debian (12+) | apart pakket | nee | nee, apart pakket | jij kiest en haakt het in | ja |
| RHEL / Rocky / Alma (9, 10) | ja | nee | ja | NetworkManager, als je het zegt | Technology Preview |
Validatie en een volle cache: de instellingen zelf
Dit zijn overal dezelfde vier regels, want resolved.conf is resolved.conf op elke distributie. Wat verschilt is alleen hoe de rest van de configuratie de daemon bereikt, en daar gaan de volgende vier secties over.
# /etc/systemd/resolved.conf.d/60-local.conf
[Resolve]
DNSSEC=allow-downgrade
Cache=yes
CacheFromLocalhost=no
StaleRetentionSec=1d
Gebruik een drop-in in plaats van /etc/systemd/resolved.conf te bewerken, want het hoofdbestand heeft een lagere voorrang dan elke drop-in en een pakketupdate kan er ruzie met je over maken. De nummering is een gedocumenteerde conventie: leveranciers nemen 10 tot 40 onder /usr/, jij neemt 60 tot 90 onder /etc/, dus die van jou wint.6
Op systemd 261 en later is er een vijfde regel die het waard is toe te voegen, want tot dan was de cachegrootte helemaal niet instelbaar:
DNSCacheSize=16384 # systemd 261+; default 4096, max 2^24
Pas het toe en bevestig dat de daemon het met het bestand eens is, in plaats van aan te nemen dat hij het gelezen heeft:
systemd-analyze cat-config systemd/resolved.conf # every fragment, in precedence order
systemctl restart systemd-resolved
resolvectl status | grep -E 'DNSSEC|Protocols'
resolvectl statistics # verdicts should start moving
DNSSEC=allow-downgrade is de instelling die ik zou zetten op een machine die ik niet ga babysitten, om de redenen in de sectie hierboven. DNSSEC=yes is de eerlijke en die faalt dicht. Kies met opzet.
Hem inhaken in de netwerkstack
De dienst aanzetten is één commando. De eigen netwerkgereedschappen van je distributie zover krijgen dat ze hun DNS-configuratie aan hem afgeven is het deel dat verschilt, en het is waar “aangezet” en “werkt goed” uit elkaar lopen.
| Waar de DNS-configuratie vandaan komt | DNSSEC aanzetten | De cache dimensioneren | Extra bedrading nodig | |
|---|---|---|---|---|
| Fedora | NetworkManager, automatisch | drop-in | drop-in | geen |
| Ubuntu | netplan, dan NM of networkd | drop-in, of per link in .network | drop-in | geen |
| Debian | welke stack je ook koos | drop-in, of per link in .network | drop-in | libnss-resolve, plus de stack hieronder |
| RHEL-familie | NetworkManager, als je het zegt | drop-in | drop-in | dns=systemd-resolved |
Fedora
De volledigste integratie van de vier, en de enige waar alles al is ingehaakt.
NetworkManager bezit het netwerk en geeft DNS aan resolved zonder dat het gezegd hoeft te worden. Op deze bak staat nergens in /etc/NetworkManager/ een dns=-regel en het werkt toch, want NetworkManager merkt de draaiende daemon op en gebruikt hem. /etc/resolv.conf is de stub-symlink, en glibc is ingehaakt omdat libnss_resolve.so.2 in systemd-libs zit, wat niet optioneel is:
$ rpm -qf /usr/lib64/libnss_resolve.so.2
systemd-libs-259.9-1.fc44.x86_64
$ grep ^hosts: /etc/nsswitch.conf
hosts: files myhostname mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns
Op Fedora is de drop-in hierboven dus het hele werk. Verder niets aan te sluiten.
Ubuntu
Standaard aangezet, en nss-resolve is op dezelfde manier ingehaakt. Het verschil is dat de configuratie meestal via netplan binnenkomt:
network:
version: 2
ethernets:
enp1s0:
dhcp4: true
nameservers:
addresses: [9.9.9.9, 149.112.112.112]
search: [example.com]
Netplan geeft dat aan zijn renderer, NetworkManager op de desktop of systemd-networkd op de server, en de renderer geeft het aan resolved. Let op wat netplan niet kan uitdrukken. Er is geen netplan-sleutel voor DNSSEC=, en geen voor DNSOverTLS=. Die gaan in de drop-in hierboven, waar ze toch al thuishoren.
Zit je op systemd-networkd, dan zijn de instellingen per link ook native beschikbaar in het .network-bestand, en een instelling per link wint van de globale:
# /etc/systemd/network/10-lan.network
[Network]
DNS=9.9.9.9#dns.quad9.net
DNSSEC=yes
DNSOverTLS=yes
Domains=~.
Debian moet met de hand worden ingehaakt
Dit is degene die werkelijk niet is ingehaakt, en de reden dat de sectie hierboven bestaat.
Sinds Debian 12 is systemd-resolved een apart pakket, en de release notes zijn expliciet over de upgrade: “The new systemd-resolved package will not be installed automatically on upgrades”, en “until it has been installed, DNS resolution might no longer work since the service will not be present on the system.”12 Dezelfde notities beslechten de bredere vraag: “systemd-resolved was not, and still is not, the default DNS resolver in Debian.”
Het installeren kost drie pakketten, niet één, en het tweede is degene die iedereen mist:
apt install systemd-resolved libnss-resolve
systemctl enable --now systemd-resolved
libnss-resolve staat alleen onder Suggests:, het is geen afhankelijkheid,13 en Suggests is de ene relatie waar apt niets mee doet. Dus niemand installeert het.
De reden dat niemand het merkt is interessanter dan de reden dat niemand het installeert. Laat het weg en glibc bereikt resolved nog steeds, want /etc/resolv.conf wijst naar de stub en gewone nss-dns praat ermee. Het grootste deel van de daemon blijft werken:
Zonder libnss-resolve | Met | |
|---|---|---|
| Cache | Ja, via de stub | Ja |
| DNSSEC-validatie | Ja, het gebeurt in de daemon | Ja |
| DNS over TLS | Ja | Ja |
AD-bit bereikt glibc | Ja, resolv.conf draagt trust-ad | Ja |
| Secure tegenover insecure tegenover bogus | Nee, maar één bit | Ja |
| Adressen met een linkscope | Nee | Ja |
/etc/hosts gelezen door de daemon | Nee | Ja |
Niets in de linkerkolom ziet er kapot uit, dus er wordt niets gerepareerd. Wat je kwijt bent is wat het DNS-wireformat niet kan dragen, en het duidelijkste geval is een adres met een scope eraan:
$ getent hosts _gateway # via nss-resolve
fe80::5054:ff:fe12:3456 _gateway
$ dig +short @127.0.0.53 _gateway # via the stub, as nss-dns would
192.0.2.1
Dezelfde naam, dezelfde daemon, twee verschillende antwoorden. Een link-lokaal IPv6-adres is betekenisloos zonder de interface waaraan het gescoopt is, en er is nergens in een DNS-antwoord plek om die te zetten, dus de stub kan alleen het IPv4 teruggeven. De native API heeft er wel plek voor en geeft je het adres dat je werkelijk wilde.
De oordeelrij is hetzelfde probleem. AD is één bit, ondertekend of niet. De native API scheidt secure van insecure van bogus, wat het verschil is tussen “niemand heeft dit ondertekend” en “iemand heeft dit ondertekend en iemand anders heeft eraan gezeten”. Een applicatie die erom geeft kan die twee over de draad niet uit elkaar houden.
Dat is het gat tussen de dienst die draait en de dienst die is ingehaakt, en het blijft onzichtbaar tot je ernaar gaat zoeken.
Kijk of het geland is:
grep ^hosts: /etc/nsswitch.conf # wants 'resolve [!UNAVAIL=return] dns'
Hoe de rest van je netwerk hem bereikt hangt af van op welke van Debians stacks je zit.
Het pakket verklaart Provides: resolvconf en Conflicts: resolvconf, openresolv,13 dus het neemt de resolvconf-interface volledig over. /usr/sbin/resolvconf wordt een symlink naar resolvectl, wat een multi-call binary is: onder die naam aangeroepen spreekt hij het resolvconf(8)-protocol en duwt alles wat hij krijgt rechtstreeks resolved in.14 Alles wat al resolvconf -a aanroept blijft dus ongewijzigd werken, met systemd-resolved als enige ondersteunde backend.
Niet de hele interface overleeft, en de gaten falen luid in plaats van stil:
resolvconf-optie | Onder systemd-resolved |
|---|---|
-a <iface> | Registreert DNS per link, gelezen van stdin. Degene die ertoe doet |
-d <iface> | Meldt af, hetzelfde als resolvectl revert |
-x | Gemapt op een routeringsdomein ~. |
-p | Markeert de link als geen standaardroute (systemd 257+) |
-f | Laat -a en -d zwijgen over een interface die er niet is |
-m | Geaccepteerd en stilletjes genegeerd |
-u, -i, -I, -l, -r, -R, -v, -V | Niet ondersteund. Het commando faalt |
Eén valkuil die het waard is te kennen voordat je hem gaat debuggen: de shim schrijft /etc/resolv.conf alleen als dat bestand een symlink naar /run/systemd/resolve/resolv.conf is, en niet als het een statisch bestand is.14
ifupdown, de standaard op een Debian-serverinstallatie. De stanzadns-nameserversin/etc/network/interfaceswerd altijd geïmplementeerd door de hooks van het oude pakketresolvconf, ensystemd-resolvedconflicteert met dat pakket en levert geen eigen hooks in/etc/network/if-up.d/. Vertrouw voor een statische interface niet op de stanza. Zet de servers expliciet op de link en laat resolved ze bezitten:# /etc/network/interfaces auto enp1s0 iface enp1s0 inet static address 192.0.2.10/24 gateway 192.0.2.1 up /usr/sbin/resolvconf -a $IFACE <<< 'nameserver 192.0.2.53' down /usr/sbin/resolvconf -d $IFACEDHCP op ifupdown is al geregeld.
isc-dhcp-clientlevert hooks die naar de daemon zijn vernoemd,/etc/dhcp/dhclient-enter-hooks.d/resolved-enteren/etc/dhcp/dhclient-exit-hooks.d/resolved,15 dus de DNS-servers van een lease landen op de juiste link zonder dat er iets te configureren valt.systemd-networkdis de schoonste optie en heeft helemaal geen shim nodig, want de twee helften zijn hetzelfde project. DNS, DNSSEC en DoT per link zijn native sleutels in het.network-bestand, precies als in het Ubuntu-voorbeeld hierboven.NetworkManager, op een Debian-desktop, moet het één keer verteld worden:
# /etc/NetworkManager/conf.d/10-resolved.conf [main] dns=systemd-resolved
Kies er een en weet welke je koos. De faalmodus hier is niet een daemon die weigert te starten, het is twee stacks die allebei geloven dat ze /etc/resolv.conf bezitten, wat leest als haperende DNS en een middag kost. resolvectl status zegt op welke link de servers geland zijn. Is het antwoord geen enkele, dan voedt niets de daemon, en dat is de bug.
RHEL, Rocky en Alma
En hier is degene die het waard is twee keer te lezen. Het pakket is er, nss-resolve is beschikbaar, NetworkManager kan het aansturen, en de documentatie van Red Hat zegt dit:
systemd-resolved is an unsupported Technology Preview.16
Die formulering staat sinds 9.0 in de release notes van RHEL 9 en staat er bij 9.8 nog steeds. Technology Preview betekent geen productie-SLA, en Red Hat raadt het uitdrukkelijk niet aan voor productiegebruik.
En hij staat ook niet aan. NetworkManager bezit resolv.conf op deze systemen, dus hem aanzetten is een NetworkManager-instelling en niet alleen de unit aanzetten:
# /etc/NetworkManager/conf.d/10-resolved.conf
[main]
dns=systemd-resolved
systemctl enable --now systemd-resolved
systemctl reload NetworkManager
resolvectl status # confirm NM actually handed the servers over
Daarna geldt de drop-in hierboven ongewijzigd, en validatie en de cache gedragen zich precies zoals op Fedora.
Dus op RHEL heb je een beslissing die op de andere niet bestaat. Wil je een validerende, cachende, split-DNS-vaardige lokale resolver op een ondersteunde RHEL-bak? Dan is het ondersteunde antwoord niet deze. Het is unbound, of dnsmasq via NetworkManagers eigen dns=dnsmasq, waar Red Hat allebei werkelijk achter gaat staan.
Het label is geen oordeel over de code. Het is een oordeel over waar Red Hat een SLA achter zet, en een cachende validerende resolver is iets waar klanten tickets over openen. Prima. Maar koop je RHEL voor de ondersteuning, dan is naamresolutie op een niet-ondersteund onderdeel draaien een beslissing om met opzet te nemen en op te schrijven, niet een om in te rollen omdat het nu eenmaal in de repo zat.
Er is niets werkelijk verminkt, en zo bewijs je dat
Het uitgangspunt is het waard getest te worden, want “mijn distro heeft het uitgezet, ik zal wel moeten herbouwen” is de reflex en hier is die verkeerd.
systemd heeft twee volstrekt verschillende soorten buildoptie, en er wordt over gepraat alsof ze er één waren:17
| Buildoptie | Soort | Upstream | Fedora | Debian en Ubuntu | Tijdens draaien te wijzigen |
|---|---|---|---|---|---|
resolve | mogelijkheid | aan | gebouwd | true | nee, en ze bouwen het allebei |
nss-resolve | mogelijkheid | aangezet | gebouwd, zit in systemd-libs | enabled, komt als libnss-resolve | nee, en ze bouwen het allebei |
dns-over-tls | mogelijkheid | auto | auto, komt uit op OpenSSL | openssl | nee, en ze compileren het allebei mee |
openssl | mogelijkheid | aangezet | enabled | enabled | nee, en ze zetten het allebei aan |
default-dnssec | alleen standaard | allow-downgrade | no | no | ja, in een drop-in |
default-dns-over-tls | alleen standaard | no | no | upstream-standaard | ja, in een drop-in |
default-mdns | alleen standaard | yes | no | no | ja, in een drop-in |
default-llmnr | alleen standaard | yes | resolve | no | ja, in een drop-in |
Lees de laatste kolom. Elke instelling waarover dit bericht heeft geklaagd zit in de onderste helft, en elk ervan is een standaardwaarde, geen mogelijkheid. De code is op allebei meegecompileerd. Niemand heeft iets weggehaald.
Het bewijs staat eerder in dit bericht en had geen compiler nodig. Op het standaard Fedora-pakket, met DNSSEC=no ingebakken, zette één commando validatie aan en werkte het volledig: een ondertekende zone geauthenticeerd, een niet-ondertekende eerlijk gemeld, een kapotte geweigerd met een precieze diagnose. Was het eruit gecompileerd, dan had resolvectl status nooit yes/supported gezegd.
Controleer dus je eigen build voordat je naar een toolchain grijpt:
# is the crypto there at all
systemctl --version | tr ' ' '\n' | grep -E '^[+-](OPENSSL|GNUTLS|GCRYPT)$'
# ask for the feature and read back what the daemon says it can do
resolvectl dnssec <link> yes
resolvectl status <link> | grep DNSSEC # yes/supported means the code is there
Op deze Fedora-bak is dat -GCRYPT +GNUTLS +OPENSSL, wat ruim voldoende is: DNSSEC heeft er een van nodig en DoT is tegen OpenSSL gebouwd.
Wat de distributies werkelijk wél weghalen
Er is één ding dat ze er allebei uit halen, en het staat niet in het lijstje waar iedereen over klaagt.
Upstream compileert een fallbacklijst met DNS-servers in de binary: Cloudflare, Google en Quad9.17 Zowel Fedora als Debian bouwt met -Ddns-servers= op niets gezet, en je kunt het op de geleverde binary bevestigen in plaats van me op mijn woord te geloven:
$ strings /usr/lib/systemd/systemd-resolved | grep -ciE 'quad9|one\.one\.one|dns\.google'
0
Niets. Geen hyperscaler in het uitvoerbare bestand ingebakken.
Dat is de ene plek waar beide distributies het beter hebben gedaan dan upstream, en dat verdient het onomwonden gezegd te worden, gezien hoeveel van dit bericht over standaardwaarden ging die ik verkeerd vind. Een machine die zijn DNS-configuratie kwijtraakt hoort luid te falen en op je te wachten. Hij hoort niet stilletjes elke naam die je opzoekt naar een resolver in een ander rechtsgebied te sturen die jij nooit hebt gekozen. Wil je een fallback? Zet FallbackDNS= en kies wie het is.
Als je werkelijk een herbouw nodig hebt
Er bestaat één echt geval: een minimale of embedded build waar iemand -Ddns-over-tls=false heeft meegegeven en het transport werkelijk ontbreekt. Controleer eerst met de commando’s hierboven, want het is zeldzaam en het ziet er identiek uit aan de instelling die gewoon uitstaat.
Heb je het wel nodig, herbouw dan het pakket, nooit make install:
# Fedora
dnf download --source systemd
rpmbuild --rebuild --define '_with_upstream 1' systemd-*.src.rpm
# Debian and Ubuntu
apt source systemd
cd systemd-*/ && editor debian/rules # change the -Ddefault-* flags
dpkg-buildpackage -us -uc -b
Ik heb geen van beide op deze machine gedraaid, dus behandel ze als de vorm van het werk, niet als een getest recept. Het principe is wat telt. systemd is PID 1, en een met de hand gebouwde make install over de kopie van je distributie heen haalt het uit de pakketbeheerder: geen beveiligingsupdates meer, en de volgende upgrade vecht met je om de bestanden. Het pakket bouwen houdt allebei. Voor bijna iedereen is het eerlijke antwoord dat een drop-in van vier regels hetzelfde werk in twintig seconden doet, en daarom staat deze sectie er vooral om je het uit het hoofd te praten.
Drie configuraties die het waard zijn
Geen menukaart met elke optie. Drie posities, die ik elk werkelijk zou verdedigen.
| Laptop, vijandige netwerken | Server, je eigen netwerk | Strikt | |
|---|---|---|---|
| Waartegen je je verdedigt | Het café en het hotelportaal | Niets lokaals; de upstream valideert al | Een resolverpad dat je niet vertrouwt |
DNSSEC= | allow-downgrade | no | yes |
DNSOverTLS= | opportunistic | no | yes |
StaleRetentionSec= | 1d | 1d | niet gezet |
| Overleeft een captive portal | Ja | n.v.t. | Nee |
Overleeft een gefilterde .arpa | Ja | Ja | Nee |
| Overleeft een geblokkeerde poort 853 | Ja | n.v.t. | Nee |
| Een aanvaller kan het downgraden | Ja, beide instellingen | n.v.t. | Nee |
Een laptop op netwerken die je niet beheert. Versleutel het transport, en neem het downgraderisico in ruil voor een ding dat achter een captive portal blijft werken.
# /etc/systemd/resolved.conf.d/60-local.conf
[Resolve]
DNS=9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net
DNSOverTLS=opportunistic
DNSSEC=allow-downgrade
Cache=yes
StaleRetentionSec=1d
Een server op een netwerk dat je wel draait, met een validerende upstream. Het is al een hop verderop gebeurd. Doe het niet twee keer, en neem geen afhankelijkheid van een publieke resolver.
[Resolve]
DNSSEC=no
DNSOverTLS=no
Cache=yes
CacheFromLocalhost=no
StaleRetentionSec=1d
Een machine waar je het echte werk wilt. Strikt op beide punten, niets voor een aanvaller om te downgraden, en je hebt gecontroleerd dat de upstream het kan dragen.
[Resolve]
DNS=9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net
DNSOverTLS=yes
DNSSEC=yes
Cache=yes
Die derde breekt reverse DNS als iets in je pad .arpa filtert, hij breekt volledig als poort 853 geblokkeerd is, en hij faalt dicht in plaats van stilletjes. Dat zijn de voorwaarden. Ken ze voordat je hem uitrolt, niet erna, want een bak die niks kan resolven is een lange rit als hij niet in de kamer hiernaast staat.
Wat je ook kiest, pas het toe en kijk dan wat de daemon werkelijk besloten heeft in plaats van wat jij schreef:
systemd-analyze cat-config systemd/resolved.conf # every file, in order
systemctl restart systemd-resolved
resolvectl status # the state it is really in
resolvectl status is hier het orakel, op dezelfde manier waarop de build het orakel is voor een Hugo-site. Een instelling in een bestand is een intentie. Wat status afdrukt is wat er gebeurt.
De rest van de werkwoorden is het waard te kennen, want samen beantwoorden ze bijna elke vraag die je over deze daemon zult hebben zonder dat je een log hoeft te lezen:
| Commando | Wat het je vertelt |
|---|---|
resolvectl status | Servers, domeinen en protocollen per link, en de live DNSSEC- en DoT-staat |
resolvectl query NAAM | Het antwoord, het gebruikte protocol, het DNSSEC-oordeel, en of het uit de cache kwam |
resolvectl statistics | Cachehits tegen missers, en de lopende telling secure/insecure/bogus |
resolvectl show-cache | Alles wat nu in de cache zit, per scope |
resolvectl flush-caches | De cache legen zonder de daemon te herstarten |
resolvectl dns LINK ... | Servers op één link zetten tijdens het draaien, zonder configuratiebestand |
resolvectl dnssec LINK yes | Validatie aanzetten voor één link, om te testen voor je het vastlegt |
resolvectl domain LINK ~x | Routerings- en zoekdomeinen op één link zetten |
resolvectl revert LINK | Elke wijziging tijdens het draaien op die link weggooien |
resolvectl show-server-state | Feature-aftasting per server: wat elke upstream bleek te ondersteunen |
resolvectl monitor | Queries en antwoorden live meekijken, wat beter is dan gokken |
Alles in dat middenblok is alleen tijdens het draaien en overleeft niet dat een link opnieuw opkomt, wat het de juiste manier maakt om een instelling te proberen voordat je hem in een drop-in schrijft. Het betekent ook dat nmcli device reapply stilletjes je testwerk ongedaan maakt, dus controleer status erna, niet ervoor.
De standaardwaarden zijn een standpunt, geen ongeluk
Drie functies in de doos. Eén aangezet.
Verleidelijk om dat als luiheid te lezen. Dat is het niet. Over elk van die standaardwaarden is geruzied door mensen die de bugwachtrij aan de andere kant van de beslissing zagen, en Fedora schreef tenminste eerlijk op dat het de ondersteuningslast niet aankon. Dat is een echte beperking en ik zal niet doen alsof dat niet zo is.
Maar een standaardwaarde is een standpunt, en dit standpunt zegt dat een lookup die niemand kan verifiëren een aanvaardbaar ding is om op te bouwen. We hebben de standaard sinds 2005. De registries publiceren de records gratis, de resolver op je machine implementeert het hele ding, en de reden dat hij stilstaat is dat te veel van het internet nooit iets heeft ondertekend, dus hem aanzetten maakt jouw machine degene die er kapot uitziet. Dat is de vorm van elke standaard die niemand afdwingt. Het netjes doen is een kostenpost die je in je eentje draagt, en het voordeel komt pas opdagen als genoeg anderen hem ook hebben gedragen.
En daarom is de telling het deel hiervan waar ik werkelijk iets mee zou doen. Niet de instellingen. De instellingen zijn twintig minuten. De telling zegt dat de organisaties die de richtlijnen publiceren, de resolver leveren en de broncode van de wereld hosten hun eigen zones grotendeels niet hebben ondertekend, en dat gov.uk de apex ondertekende en toen de ene website waar niemand omheen kan op een niet-ondertekende delegatie richtte. Iemand deed het moeilijke deel en keek toen nooit de naam na die mensen typen.
Je kunt alleen je eigen boeltje opknappen. Draai je een zone, onderteken hem, dien de DS in, en ga dan de www-naam opzoeken zoals een bezoeker dat zou doen en bevestig dat de keten tot het eind overleeft. Het is een middag. Doe dat en het argument voor validatie houdt op theoretisch te zijn voor iedereen die jouw naam opzoekt, en dat is het enige deel hiervan dat wij werkelijk kunnen repareren.
systemd-resolved.service(8)— “implements a caching and validating DNS/DNSSEC stub resolver”; de vier clientinterfaces, de twee stub-listeners, synthetische records, de routeringsregels en de vier modi van/etc/resolv.conf. ↩︎ ↩︎ ↩︎ ↩︎resolved.conf(5), zoals geleverd in systemd 259.9 op Fedora 44 —DNSSEC=,DNSOverTLS=,Cache=,CacheFromLocalhost=,StaleRetentionSec=en de beschrijving van de proxystub op127.0.0.54. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎resolved.conf(5)—DNSCacheSize=,MulticastDNSCacheSize=enLLMNRCacheSize=, “Each defaults to 4096”, toegevoegd in systemd 261. ↩︎RFC 5737 — “IPv4 Address Blocks Reserved for Documentation”:
192.0.2.0/24,198.51.100.0/24en203.0.113.0/24. ↩︎RFC 3849 —
2001:DB8::/32gereserveerd voor documentatie, “to reduce the likelihood of conflict and confusion when relating documented examples to deployed systems”. ↩︎resolved.conf(5), upstream latest —DNSSEC=“Defaults toallow-downgrade”,DNSOverTLS=“Defaults tono”, de nummeringsconventie voor drop-ins, en de volledige lijst met directieven zonder optie voor DNS over HTTPS. ↩︎ ↩︎ ↩︎ ↩︎Fedora
systemd.spec, rawhide — de meson-buildvlaggen-Ddefault-dnssec=no,-Ddefault-dns-over-tls=no,-Ddefault-mdns=no,-Ddefault-llmnr=resolve. ↩︎Debian
systemdpackaging,debian/rules—-Ddefault-dnssec=no,-Ddefault-llmnr=no,-Ddefault-mdns=no,-Ddns-over-tls=openssl. De systemd van Ubuntu is van deze packaging afgeleid. ↩︎Fedora Change: systemd-resolved — Fedora 33 maakte het de standaardresolver; verandert de standaard “from the upstream default
DNSSEC=allow-downgradetoDNSSEC=no” omdat de functie “is known to cause compatibility problems with certain network access points” en Fedora “is not prepared to handle an influx of DNSSEC-related bug reports”. ↩︎Fedora Magazine — Use DNS over TLS — de aanbevolen configuratie
DNSOverTLS=yes, gegeven met kale IP-adressen en zonder de SNI-vorm#hostname. ↩︎systemd issue #8639 — “Add support for DNS-over-HTTPS to systemd-resolved”, geopend op 2 april 2018, nog steeds open. ↩︎
Debian 12 release notes, 5.2.3 — “The new
systemd-resolvedpackage will not be installed automatically on upgrades”; “until it has been installed, DNS resolution might no longer work”; “systemd-resolved was not, and still is not, the default DNS resolver in Debian.” ↩︎Debian
systemdpackaging,debian/control— de stanzasystemd-resolved:Provides: resolvconf,Conflicts: resolvconf, openresolv,Replaces: resolvconf, enlibnss-resolvealleen vermeld onderSuggests:. ↩︎ ↩︎resolvconf(1), de resolvectl-compatibiliteitsmodus — resolvectl “is a multi-call binary. When invoked as ‘resolvconf’ … it is run in a limited resolvconf(8) compatibility mode”; systemd-resolved “is the only supported backend”; welke opties worden ondersteund, genegeerd of geweigerd; en de regel dat /etc/resolv.conf alleen wordt geschreven als het een symlink naar /run/systemd/resolve/resolv.conf is. ↩︎ ↩︎Debian
isc-dhcp-clientfile list — levert/etc/dhcp/dhclient-enter-hooks.d/resolved-enteren/etc/dhcp/dhclient-exit-hooks.d/resolved. ↩︎RHEL 9.4 release notes, Technology Previews — “Note that
systemd-resolvedis an unsupported Technology Preview.” Ongewijzigd meegedragen van RHEL 9.0 tot en met 9.8. ↩︎systemd
meson_options.txt— de scheiding tussen opties voor mogelijkheden (resolve,nss-resolve,dns-over-tls,openssl) en opties voor standaardwaarden (default-dnssec,default-dns-over-tls,default-mdns,default-llmnr), en de meegecompileerde fallbacklijstdns-servers. ↩︎ ↩︎