# Dæmon

## Hvad det er

En dæmon er en langlivet proces, som intet menneske starter i hånden:
styresystemet eller en servicemanager sætter den i gang, den har ingen terminal,
og den bliver kørende for at besvare forespørgsler eller holde øje med en del af
maskinen. På engelsk staves ordet daemon, og mange dæmoner bærer det i navnet
som et afsluttende d: `sshd` tager imod SSH-forbindelser, `crond` kører
planlagte job, og `systemd-journald` samler logge. Windows kalder den samme
slags program en tjeneste, og det gør systemd også, som i dag passer de fleste
dæmoner på Linux.

Den klassiske Unix-opskrift, som Linux-manualen `daemon(7)` stadig gennemgår i
femten nummererede trin, lader programmet rive sig løs selv. Det lukker de
fildeskriptorer, det har arvet, nulstiller sine signalhåndteringer, forker,
kalder `setsid()` for at forlade terminalens session og forker en gang til, så
det ikke kan få en terminal igen. Det første barn afslutter, så PID 1 adopterer
den overlevende proces, som sender sine standardstrømme til `/dev/null`, skifter
til `/`, skriver en PID-fil og opgiver sine privilegier. C-bibliotekets kald
`daemon()` klarer en del af arbejdet, og manualen fraråder det netop, fordi det
kun gennemfører en delmængde af trinene.

Den nye stil, som samme manual kalder new-style daemons, og som både systemd og
Apples launchd forventer, vender opskriften på hovedet. Programmet bliver i
forgrunden, for servicemanageren har allerede startet det løsrevet, med et rent
miljø, den rigtige bruger og den rigtige arbejdsmappe. Det skriver sine
loglinjer til standard error, hvor servicemanageren samler dem op, melder, når
det er klar til at tage imod arbejde, lukker pænt ned på SIGTERM og genindlæser
sin konfiguration på SIGHUP. Apples vejledning til launchd-job er kontant om den
gamle vane: et job må ikke gøre sig selv til dæmon, og forker det og afslutter,
konkluderer launchd, at processen er død.

To naboer bliver tit forvekslet med den. Et planlagt job, som cron eller en
systemd-timer kører, starter, gør sit arbejde og afslutter, mens en dæmon
bliver. Og macOS deler ordet i to: en launch daemon betjener hele systemet og
indlæses ved opstart, mens en launch agent tilhører én bruger og kun kører, så
længe brugeren er logget ind. Linux trækker samme skel med de instanser af
systemd, der kører for hver enkelt bruger.

## Hvorfor det betyder noget

Hver dæmon på en server er en løbende forpligtelse. Den optager hukommelse,
uanset om nogen bruger den, og nogen skal patche den, hver gang leverandøren
udsender en rettelse. Lytter den på en netværksport, hører den til angrebsfladen
i hver time, den kører. Det nyttige spørgsmål er derfor sjældent, hvilken dæmon
man skal installere, men om arbejdet overhovedet kræver en proces, der altid
kører.

Tre former dækker det meste. Noget, der sker efter en tidsplan, som en backup,
en rapport eller fornyelsen af et certifikat, behøver ingen fast proces: en
timer starter det, det kører til ende, og mellem kørslerne koster det intet.
Noget, der besvarer lejlighedsvise forespørgsler, kan socket-aktiveres:
servicemanageren ejer den lyttende socket og starter dæmonen ved første
forbindelse, og da socketen forbliver bundet under en genstart, venter nye
forespørgsler i kø i stedet for at blive afvist. Kun arbejde, der skal reagere
hele tiden, som en webserver, en database eller en mailserver, fortjener en
proces, der altid er oppe. På en lille maskine afgør det valg, om det hele kan
være i hukommelsen.

Den anden beslutning kommer, hver gang en dæmon skrevet af andre skal i
produktion, og fire spørgsmål afgør den. Bliver den i forgrunden, når man beder
den om det? Logger den til standard error, eller insisterer den på sine egne
logfiler? Kan den fortælle servicemanageren, at den er klar, og ikke blot at den
er startet? Og kræver den root, eller kan servicemanageren række den det ene
privilegerede, den har brug for, for eksempel en socket på port 443? En dæmon,
der svarer godt på alle fire, er billig at drive i årevis. En, der dumper på dem
alle, ankommer med et wrapper-script, sin egen logrotation og en undtagelse i
den næste sikkerhedsgennemgang.

## Sådan ser det ud i praksis

Virksomhedens egen platform viser de valg i tre konkrete stykker arbejde.

Da
[sitet blev spejlet til Gemini og Gopher](/da/portfolio/mirrored-the-site-to-gemini-and-gopher-137/),
kom 777 Gemini-dokumenter og 777 Gopher-menuer ud af det samme build som
HTML'en, og to små dæmoner på den samme vært leverer dem. To ekstra protokoller
kostede to faste processer og ingen ny indholdspipeline, og HTML'en ændrede sig
med nul bytes.

Onion-spejlet på Tor viser netværkssiden af samme valg: dæmonen bygger udgående
kredsløb, så ingen ringer ind, og firewallen får ingen ny åben port.
[Rollen, der sætter onion-spejlet op](/da/portfolio/published-the-site-as-a-tor-onion-mirror-on-a-readable-168/),
installerer dæmonen fra distributionens egen pakke, skriver en konfiguration med
den udgående proxyport slået fra og afviser at overskrive en identitet, den ikke
selv har genereret. Ét trin gav en lære, der gælder dæmoner i al almindelighed:
nøglen landede korrekt, kørslen meldte ingen ændring, og den nye adresse blev
aldrig offentliggjort, fordi intet i konfigurationen på det tidspunkt pegede på
den nye mappe. Nu stopper rollen med en fejl, når en identitet ligger på disken,
uden at nogen tjeneste nævner den.

Rapporteringen viser, hvad en stille dæmon kan skjule.
[Seks indsamlere, der kun læser og gengiver værten som Markdown](/da/portfolio/made-six-collectors-state-what-they-never-read-167/),
blev bygget om, da det stod klart, at en blind indsamling og en sund vært gav
den samme side: et spejl, hvis dæmon havde skiftet logformat, viste det samme
nul som et spejl, ingen havde besøgt. Indsamlerne melder nu blandt andet, hvor
mange journallinjer de har læst, over for hvor mange de har genkendt, så en
dæmon, der ændrer det, den skriver, dukker op som et hul og ikke som ro.

## Hvor det går galt

**Tjenesten starter og stopper igen et sekund senere.** En dæmon i gammel stil
forker og lader forælderprocessen afslutte, sådan som opskriften foreskriver.
Under standardindstillingen `Type=simple` er den proces, systemd startede,
hovedprocessen, så når den afslutter, regnes tjenesten for stoppet, og med
standarden `KillMode=control-group` bliver barnet, der skulle fortsætte, dræbt
sammen med resten af enhedens kontrolgruppe. Kør programmet med dets
forgrundsflag. Til de få, der ikke kan ændres, erklærer man `Type=forking`
sammen med `PIDFile=`, en type manualen fraråder til ny kode.

**Klienter forbinder for tidligt og bliver afvist.** Med `Type=simple` regner
systemd tjenesten for startet, så snart processen er forket, så enheder, der er
ordnet efter den, starter, mens dæmonen stadig læser sin konfiguration. Ifølge
servicemanualen melder `systemctl start` oven i købet succes under den type,
selv når programfilen mangler, eller den konfigurerede bruger ikke findes. Vælg
`Type=exec`, der venter, til programmet faktisk er eksekveret, og lad dæmonen
selv melde sig klar med `Type=notify`, når andre afhænger af den:

```c
#include <systemd/sd-daemon.h>

int main(void) {
    load_config();
    open_listeners();
    sd_notify(0, "READY=1"); /* enheder ordnet efter denne starter nu */
    return serve_forever();
}
```

**Et stopscript dræber en fremmed proces.** En forkende dæmon skriver sit
proces-id i en fil, så scripts kan sende den signaler senere. Efter et nedbrud
bliver filen liggende, kernen giver det samme nummer til en helt anden proces,
og det næste stop sender SIGTERM til det forkerte program. Servicemanualen
anbefaler helt at undgå PID-filer i nye projekter. En servicemanager, der selv
har startet processen, følger den gennem dens kontrolgruppe og har ingen fil,
der kan blive forældet.

**En dæmon dør ved opstart og efterlader intet spor.** Den gamle opskrift sender
standard output og standard error til `/dev/null`, så en fejlmeddelelse, der
kommer, før dæmonen har åbnet sin egen logfil, forsvinder sporløst. Under en
servicemanager skal begge strømme blive, hvor de er: alt, hvad dæmonen skriver
til standard error, lander i journalen, hvor `journalctl -u` læser det enhed for
enhed.

**Én udnyttet fejl giver adgang til hele maskinen.** En dæmon, der kører som
root, fordi den skulle bruge port 80 ved opstart, beholder root for hver eneste
forespørgsel bagefter. Lad servicemanageren binde den privilegerede socket og
række den videre, og overlad det at opgive privilegier til servicemanageren, som
`daemon(7)` anbefaler; indstillinger som `NoNewPrivileges=` og `ProtectSystem=`
begrænser, hvad en kompromitteret proces kan røre ved.

## Læs mere

- [daemon(7)](https://man7.org/linux/man-pages/man7/daemon.7.html) — de femten
  trin i den klassiske opskrift, og hvad en dæmon i ny stil gør i stedet.
- [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)
  — C-bibliotekets genvej og den fejl med sessionslederen, som dens egen manual
  beskriver.
- [sd_notify(3)](https://man7.org/linux/man-pages/man3/sd_notify.3.html) — sådan
  fortæller en dæmon systemd, at den er klar, genindlæser eller stopper.
- [systemd.socket(5)](https://man7.org/linux/man-pages/man5/systemd.socket.5.html)
  — socket-aktivering, hvor servicemanageren holder porten og starter dæmonen
  efter behov.
- [setsid](https://pubs.opengroup.org/onlinepubs/9799919799/functions/setsid.html)
  — POSIX-definitionen af kaldet, der løsriver en proces fra sin terminal.
- [Creating Launch Daemons and Agents](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html)
  — Apples regler for launchd-job, blandt andet hvorfor et job aldrig må forke
  og afslutte.

<https://engineer.company/da/glossary/daemon/>
