| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- #!/bin/sh
- # Erzeugt je Domain einen DKIM-Schlüssel, legt den öffentlichen Schlüssel als
- # DNS-TXT-Record an, trägt den Schlüssel in OpenDKIM ein und startet OpenDKIM neu.
- #
- # DRY_RUN=1 (Vorgabe) schickt nichts ins DNS und startet nichts neu. Schlüssel
- # und Konfiguration werden trotzdem lokal geschrieben, damit der Wert zum
- # Prüfen überhaupt erst vorliegt. Erst nach der Prüfung auf 0 setzen.
- set -eu
- DRY_RUN=1
- CLI=./schlundtech-dns
- KEYDIR=/etc/opendkim/keys
- OPENDKIMDIR=/etc/opendkim
- SELECTOR=$(date +%Y%m)
- DOMAINS="klumpp.de klumpp.net netdome.biz oberrhein.de"
- die() { printf '%s\n' "$*" >&2; exit 1; }
- run_cli() {
- if [ "$DRY_RUN" -eq 1 ]; then
- "$CLI" "$@" --dry-run
- else
- "$CLI" "$@"
- fi
- }
- command -v opendkim-genkey >/dev/null 2>&1 || die "opendkim-genkey nicht gefunden"
- [ -x "$CLI" ] || die "$CLI nicht gefunden — vorher 'go build'"
- uid=$(id -u) || die "id -u schlug fehl"
- [ "$uid" -eq 0 ] || die "muss als root laufen, schreibt nach $KEYDIR"
- [ -d "$KEYDIR" ] || die "$KEYDIR fehlt"
- cd "$KEYDIR"
- for domain in $DOMAINS; do
- opendkim-genkey -d "$domain" -b 2048 -r -s "$SELECTOR"
- # Nur die zwei neuen Dateien, nicht alles im Verzeichnis.
- chown opendkim:opendkim "$SELECTOR.txt" "$SELECTOR.private"
- mv "$SELECTOR.txt" "$domain.txt"
- mv "$SELECTOR.private" "$domain.private"
- # Die .txt von opendkim-genkey ist KEIN blosser Record-Wert, sondern ein
- # kompletter Zone-File-Eintrag, vorgeblich in 250-Zeichen-Stuecke geteilt:
- #
- # 202610._domainkey.klumpp.de IN TXT ( "v=DKIM1; k=rsa; "
- # "p=MIIB..." "..."
- # )
- #
- # Die Anfuehrungszeichen trennen die Character-Strings. Nur was zwischen
- # ihnen steht ist der Record-Wert; der Rest ist Zone-File-Syntax und darf
- # nicht mit in DNS. awk mit -F'"' liefert genau diese Zwischenstuecke,
- # die dann aneinandergehaengt werden - genau das, was ein Resolver tut.
- value=$(awk -F'"' '{ for (i = 2; i <= NF; i += 2) printf "%s", $i }' "$domain.txt")
- [ -n "$value" ] || die "kein Wert in $domain.txt gefunden"
- case "$value" in
- *v=DKIM1*) ;;
- *) die "$domain.txt enthaelt keinen DKIM-Record" ;;
- esac
- case "$value" in
- *p=*) ;;
- *) die "$domain.txt enthaelt kein p=" ;;
- esac
- run_cli records set "$domain" \
- --name "$SELECTOR._domainkey" --type TXT --value "$value"
- # Ein 2048-Bit-Schluessel ergibt rund 360 Zeichen und ueberschreitet damit
- # die 255 Bytes je Character-String, die DNS erlaubt. Das ist normal: der
- # Wert wird in mehrere Strings aufgeteilt und vom Gateway als einer
- # gespeichert. Im Portal sieht er deshalb quoted und aufgeteilt aus.
- if [ "${#value}" -gt 255 ]; then
- printf '%s: %d Zeichen, laenger als 255 — das Gateway teilt den Wert in Character-Strings auf, das ist korrekt\n' \
- "$domain" "${#value}" >&2
- fi
- if [ "$DRY_RUN" -eq 0 ]; then
- keyline="key-$domain $domain:$SELECTOR:$KEYDIR/$domain.private"
- grep -qxF "$keyline" "$OPENDKIMDIR/key.table" 2>/dev/null ||
- printf '%s\n' "$keyline" >>"$OPENDKIMDIR/key.table"
- signline="*@$domain key-$domain"
- grep -qxF "$signline" "$OPENDKIMDIR/signing.table" 2>/dev/null ||
- printf '%s\n' "$signline" >>"$OPENDKIMDIR/signing.table"
- fi
- done
- if [ "$DRY_RUN" -eq 1 ]; then
- printf 'nur Vorschau: kein DNS-Record gesetzt, key.table/signing.table unveraendert, kein Neustart — DRY_RUN=0 zum Ausfuehren\n' >&2
- else
- systemctl restart opendkim
- fi
|