9. Unterstützte Funktionen¶
Die Funktionen auf Protokoll- und Richtlinienebene, die Pepsi unterstützt, jeweils mit dem maßgeblichen RFC: die SMTP- und Authentifizierungsmaschinerie, die Ende-zu-Ende-Kryptographie und die Betriebsoberfläche um beides. Der RFC-Index verweist jeden RFC auf Code und Konfiguration; die programmweisen Kapitel führen auf, welches Programm jede Funktion umsetzt.
9.1. Eingehender SMTP-Empfang¶
pepsi-ingress ist ein standardkonformer SMTP-Server (RFC 5321) mit diesen Erweiterungen:
Transportsicherheit. Klartext, STARTTLS-Upgrade (RFC 3207) und implizites TLS (RFC 8314, z. B. der Submission-Port 465) — je Listener über
MODEausgewählt. Submission-Listener (RFC 6409,SUBMISSION = yes) können gebunden werden — siehe Nachrichteneinlieferung.Übertragung des Nachrichtentexts. Klassisches
DATAund CHUNKING/BDAT (RFC 3030) für große Nachrichten.BINARYMIMEwird nicht angekündigt, und einMAIL FROMmitBODY=BINARYMIMEwird mit501 5.5.4abgelehnt.SIZE-Ankündigung und -Durchsetzung (
MAX_MESSAGE_SIZE; Überschreitung → 552).PIPELINING und ENHANCEDSTATUSCODES.
8BITMIME (RFC 6152) und SMTPUTF8 (RFC 6531) — siehe Internationalisierte und 8-Bit-Inhalte.
DSN (RFC 3461) — siehe Zustellungsstatusbenachrichtigungen.
SMTP AUTH (RFC 4954) für die Submission — siehe Client-Authentifizierung.
Annahmerichtlinie: Mail wird nur für
ACCEPTED_DOMAINSangenommen (andere werden als Relaying mit550abgelehnt); das domainlose Postfach<Postmaster>wird immer angenommen (RFC 5321 §4.5.1); Empfänger, die gültige SRS-Tokens sind, werden rückwärtsdekodiert und weitergeleitet (siehe Sender Rewriting Scheme (SRS)).Dauerhaftigkeit: Dem Client wird
250erst mitgeteilt, nachdem der Datensatz festgeschrieben ist; ist die Datenbank nicht verfügbar, erhält der Client ein vorübergehendes451und wiederholt.
9.2. Trace-Header¶
Ingress stellt jeder Nachricht vor der Authentifizierung einen Received:-Header gemäß RFC 5321 §4.4 voran (sodass die ARC-Versiegelung ihn abdeckt). Die with-Klausel hält den Übertragungstyp fest — SMTP, ESMTP, ESMTPS, ESMTPA oder ESMTPSA — gemäß RFC 3848 (das bloße ESMTPA, authentifiziert, aber nicht über TLS, ist der lokale UNIX-Submission-Socket), und eine for-Klausel benennt bei Einzelempfänger-Transaktionen den Empfänger.
9.3. Client-Authentifizierung¶
Jeder Listener kann den sich verbindenden Client authentifizieren und dessen Mail als lokal erzeugt markieren (was ihr erlaubt, an jede Domain weiterzuleiten, und ESMTPSA in die Received:-Spur stempelt). Eine Sitzung ist authentifiziert, wenn einer von vier listenerspezifischen Mechanismen gelingt:
die Peer-IP ist im
MYNETWORKSdes Listeners (von vornherein vertrauenswürdig);ein SMTP-AUTH-Austausch gelingt (RFC 4954,
PLAIN/LOGIN), verifiziert gegen ein konfiguriertes SASL-Backend (SASL_TYPE/SASL_PATH; heute der Auth-Client-Socket von Dovecot).AUTHwird nur über TLS angeboten und akzeptiert — ein Klartextversuch wird mit504 5.5.4abgelehnt, dem Code, den RFC 4954 §4 für ein Verfahren vorschreibt, das „eine Verschlüsselungsschicht erfordert“ (§1 erklärt das ältere538für veraltet);ein vorgelegtes TLS-Client-Zertifikat passt zu einem konfigurierten Schlüssel/CA-Pin (
TLS_AUTH_CLIENT);die Gegenstelle eines UNIX-Sockets wird über
SO_PEERCREDidentifiziert (AUTH_PEERCRED, der lokale Submission-Socket) und ihr Login ist auf mindestens eine Adresse abgebildet. Dieser Mechanismus trägt einen Benutzernamen, speist also dieselbeUSERNAME_MAP-Durchsetzung, die auch eine SASL-Sitzung erfährt.
Dies ist verschieden von der Grenz-Authentifizierung unten, die die Nachricht verifiziert (SPF/DKIM/DMARC), unabhängig davon, wie — oder ob — sich der Client selbst authentifiziert hat. Siehe pepsi-ingress.
9.4. Nachrichteneinlieferung¶
Ein mit SUBMISSION = yes markierter Listener verhält sich als Message Submission Agent (RFC 6409) statt als MX:
Authentifizierung ist verpflichtend — ein nicht authentifiziertes
MAIL FROMwird mit530 5.7.0abgelehnt (das Flag erfordert also einen der obigen Client-Auth-Mechanismen sowie TLS auf jedem Listener, der kein lokaler UNIX-Domain-Socket ist); undSubmission-Korrekturen werden auf jede angenommene Nachricht angewendet: ein fehlendes
Date:(§8.2) undMessage-ID:(§8.3) werden ergänzt, bevor die Nachricht gespeichert wird; undDurchsetzung der Submission-Identität (§6) über
USERNAME_MAP: das Umschlag-MAIL FROMund derFrom:-Header müssen Adressen sein, die der authentifizierte Benutzer verwenden darf (andernfalls550), und ein erlaubtesFrom:, das von der kanonischen Identität des Benutzers abweicht, erhält einenSender:-Header, der sie benennt (§8.1).
Das Flag hat auf einem MX-Listener keine Wirkung.
9.5. Grenz-Authentifizierung¶
Bevor Ingress eine Nachricht speichert, authentifiziert es sie, damit der schließliche Empfänger weiterhin das Urteil sehen kann, das Pepsi an der Grenze gefällt hat (die Weiterleitung wird die ursprünglichen SPF/DKIM-Signale zerstören):
SPF (RFC 7208) auf der
MAIL FROM-Identität unter Verwendung der Client-IP.DKIM-Signaturverifikation (RFC 6376 / RFC 8463).
DMARC-Auswertung (RFC 7489), mit optionaler Durchsetzung zur SMTP-Zeit (
DMARC_ENFORCE→550bei einem eindeutigen Fehlschlag unter einerquarantine/reject-Richtlinie). Andernfalls ist die Authentifizierung fail-open: Ein DNS- oder Parse-Fehler wird festgehalten und die Mail angenommen.iprev / FCrDNS (RFC 8601) — bestätigt der PTR des Clients vorwärts auf seine IP.
Ein Authentication-Results-Header (RFC 8601), der all das Obige festhält, gestempelt mit dem Ingress-Hostnamen als
authserv-id.
9.6. Authenticated Received Chain (ARC)¶
Die Stage pepsi-stage-arc implementiert ARC (RFC 8617). Sie verifiziert jede eingehende ARC-Kette und versiegelt die Nachricht als unsere ADMD, indem sie ein Set aus ARC-Authentication-Results / ARC-Message-Signature / ARC-Seal voranstellt, signiert mit dem einzigen ARC_ALGORITHM (ARC erlaubt eine Signatur pro Hop). Dies erlaubt einem nachgelagerten Empfänger, dem Grenzurteil zu vertrauen, nachdem die Weiterleitung das SPF/DKIM-Alignment zerstört hat. Die Versiegelung ist fail-open. Weil ARC die Authentifizierung eines vorgelagerten Absenders über den Weiterleitungs-Hop hinweg bewahrt, gilt es nur für Mail, die Pepsi empfängt: lokal erzeugte Einlieferungen (state.local_origin) werden übersprungen — sie werden von der DKIM-Signierungs-Stage als Autor-Domain authentifiziert —, sodass die generierte Pipeline ARC im eingehenden Zweig platziert, nach der state.local_origin-Aufteilung.
9.7. Sender Rewriting Scheme (SRS)¶
Die Stage pepsi-stage-srs schreibt den Umschlagabsender in eine lokale Adresse einer von Pepsi kontrollierten SRS_DOMAIN um, die den ursprünglichen Absender per HMAC kodiert (der gekürzte MAC ist base32-kodiert, RFC 4648), sodass SPF beim nächsten Hop besteht. Der Null-Absender und eine bereits in der SRS-Domain liegende Adresse bleiben unverändert; eine bereits-SRS-Adresse wird in der kompakten SRS1-Form neu signiert. Ingress führt die Gegenrichtung aus: Ein an eine gültige SRS-Adresse zurückgesendeter Bounce wird verifiziert und an den ursprünglichen Absender weitergeleitet, während ein gefälschtes oder abgelaufenes Token abgelehnt wird (550).
9.8. Ende-zu-Ende-Verschlüsselung und -Signierung¶
pepsi-stage-encrypt verschlüsselt eine lokal eingelieferte Nachricht an jeden Empfänger, in OpenPGP (PGP/MIME, RFC 3156) oder S/MIME (CMS, RFC 8551 / 5083), signiert mit dem eigenen Schlüssel des From:-Autors. Die Signatur liegt innerhalb des Chiffrats.
ENABLE_PEP (standardmäßig an) ist eine Voreinstellung von Standardwerten nach dem Vorbild des Projekts pretty Easy privacy: Jeder lokale Absender an einer bedienten Domain erhält automatisch einen OpenPGP-Schlüssel, eine Nachricht wird nur signiert, wenn sie verschlüsselt wird (SIGN = encrypted-only), und Klartext-Mail trägt den Schlüssel des Absenders in einem Autocrypt:-Header, aber keine Signatur. Jede ausdrücklich ausgeschriebene Option hat weiterhin Vorrang; ENABLE_PEP = no macht das Signieren opportunistisch und schaltet die automatische Schlüsselerzeugung ab.
Jeder verschlüsselte Empfänger bekommt sein eigenes Chiffrat auf seinem eigenen Warteschlangendatensatz: Es gibt keine Offenlegung der Empfängerliste, keinen zwischen Empfängern geteilten Inhaltsschlüssel, und ein Bcc-Leck ist strukturell unmöglich. Empfänger, die ein Ergebnis teilen, teilen sich einen Datensatz.
Empfängerschlüssel stammen aus dem Speicher von Schlüsselverwaltung, gefüllt von der Entdeckungsschicht (WKD, VKS, DANE, LDAP, Ernte aus eingehender Mail). Die Stage selbst betreibt keine Netzwerk-E/A: Ein Empfänger, dessen Schlüssel nicht zwischengespeichert ist, pausiert die Nachricht, bis ein Entdeckungsdienst die Anfrage erledigt, und einer mit einem frischen negativen Cache-Eintrag nimmt sofort den Schlüssellos-Pfad.
Was mit einem Empfänger ohne Schlüssel geschieht, ist Richtlinie — ON_NO_KEY ist cleartext, secure-link oder bounce und bezieht seinen Standardwert aus ENCRYPT, statt einen eigenen zu tragen. ENCRYPT = required fällt nie auf Klartext zurück, und kein Klartextergebnis ist je stillschweigend — jedes wird protokolliert und je Empfänger in state.crypto.out festgehalten, samt dem tatsächlich verwendeten Inhaltscontainer und der Angabe, ob es eine Herabstufung war.
Die Stage läuft vor der DKIM-Signierung, sodass DKIM die tatsächlich übertragenen Bytes abdeckt; Konfiguration erklärt, warum diese Reihenfolge nicht optional ist.
9.9. Serverseitige Entschlüsselung und Verifikation¶
pepsi-stage-decrypt ist die eingehende Hälfte. Für eine Nachricht an einen Empfänger, den dieser Host bedient, öffnet es jedes Chiffrat, das die Nachricht trägt, verifiziert jede Signatur, die sie trägt, hält das Urteil fest und entfernt jeden Sicherheitsindikator, den der Absender gefälscht hat. Der Benutzer liest gewöhnliche Mail in seinem üblichen Client, ohne dass ein Plugin beteiligt ist. Die Ausnahme ist Mail, die an einen Schlüssel verschlüsselt ist, den der Benutzer aus seinem eigenen Mail-Client registriert hat (ein Schlüssel in Client-Verwahrung, dessen private Hälfte Pepsi nie besitzt): Sie wird ungeöffnet durchgereicht, damit der Client sie entschlüsselt.
Es läuft nur für Empfänger, die dieser Host bedient, und versucht es bei allem anderen gar nicht erst. Das Entschlüsseln schreibt den Nachrichtentext um, was die DKIM-Signatur des Absenders ungültig macht; das ist bei einer Nachricht, die gleich hier in ein Postfach abgelegt wird, harmlos und bei einer weitergeleiteten nicht. Eine Nachricht mit Empfängern beider Art wird aufgeteilt, sodass die weitergeleitete Kopie diejenige ist, die ankam.
Das Urteilsvokabular ist genau. valid bedeutet, die Signatur ist einwandfrei und der Schlüssel war verankert — eine X.509-Kette zu einer konfigurierten CA oder ein OpenPGP-Schlüssel aus einer eingestuften Entdeckungsquelle. valid-untrusted bedeutet einwandfrei mit einem Schlüssel, der sich an nichts binden ließ, was der Zustand des meisten signierten Mailverkehrs der Welt ist und nie als valid gemeldet wird. invalid, unverifiable und none vervollständigen die Menge, und trägt eine Nachricht mehrere Signaturen über denselben Inhalt, so gewinnt die schlechteste von ihnen. (Eine außerhalb des Chiffrats angebrachte Signatur ist eine eigene Klasse: Sie steht nur dann für die Nachricht ein, wenn nichts den Klartext signiert, und dann nie besser als valid-untrusted — siehe pepsi-stage-decrypt.) Nur valid setzt state.signature_verified, woran pepsi-stage-check-whitelist einen Datensatz der weißen Liste knüpft.
Beide Fehlerpfade stellen standardmäßig zu, im Einklang mit Pepsis fail-open-Haltung bei eingehendem SPF, DKIM und DMARC: Eine Nachricht, die wir nicht öffnen konnten, wird weiterhin verschlüsselt zugestellt (der Benutzer hält den Schlüssel womöglich in seinem eigenen Client), und eine schlechte Signatur ist ein festgehaltenes Urteil und kein Zustellfehler (Mailinglisten, die Nachrichtentexte umschreiben, erzeugen sie an völlig legitimer Mail). Quarantäne- und Bounce-Wege gibt es für Installationen, die sie wünschen.
Das Ergebnis erreicht den Benutzer auf zwei Wegen: über einen X-Pepsi-Crypto-Header mit dokumentierter Grammatik und — standardmäßig — über ein [decrypted][verified], das dem Subject in Schachtelungsreihenfolge vorangestellt wird, was für die meisten Benutzer das einzige Signal ist, das sie je sehen werden. Beides beruht auf derselben Disziplin: Jedes X-Pepsi-*-Feld und jede unserer eigenen Betreffmarkierungen wird aus eingehender Mail entfernt, bevor unsere hinzugefügt wird. Ein privater Header ist definitionsgemäß fälschbar, und diese Entfernung ist die gesamte Grundlage dafür, dass man ihm glauben darf.
Das Schlüsselmaterial, das eine Nachricht mitführt — S/MIME-Signiererzertifikate, application/pgp-keys-Teile, Autocrypt-Header —, wird im Speicher gelesen, um die Signatur eben dieser Nachricht zu prüfen, denn die meiste signierte Mail führt das Zertifikat mit, das sie signiert hat. Tut sie es nicht, pausiert die Nachricht an einer Entdeckungsanfrage, statt an einem Keyserver zu blockieren, sodass selbst die erste Nachricht eines neuen Korrespondenten ein echtes Urteil erhält.
Die Entschlüsselungs-Stage speichert nichts davon. Alles Lernen von Peer-Schlüsseln ist eine eigene Stage, pepsi-stage-autocrypt-learn, platziert nach dem Spam-Urteil — was „Nachrichten ignorieren, die die MUA für Spam hält“ aus Autocrypt Level 1 §5.3 überhaupt erst umsetzbar macht (LEARN_FROM_SPAM, standardmäßig aus). Eine eingehende Pipeline ohne diese Stage verifiziert Signaturen einwandfrei und lernt nie den Schlüssel eines Korrespondenten.
Was die Decrypt-Stage öffnet, wird als Klartext abgelegt — es sei denn, der Empfänger hat seinen eigenen Mail-Client-Schlüssel registriert; dann versiegelt pepsi-stage-reencrypt, unmittelbar vor der lokalen Zustellung platziert, die Nachricht mit diesem Schlüssel, sobald jede lesende Stage fertig ist. Eine Richtlinie pro Empfänger (ON_NO_CLIENT_KEY) kann Mail für einen Benutzer ohne einen solchen Schlüssel abweisen, statt sie lesbar abzulegen.
9.10. Schlüsselverwaltung, -entdeckung und -veröffentlichung¶
Keine der beiden Krypto-Stages betreibt eigene Netzwerk-E/A. Beide schöpfen aus einem Schlüsselspeicher im gemeinsamen Schema, der aus zwei Richtungen gefüllt wird: von pepsi-keydisc — je eine Dienstinstanz pro Entdeckungsmethode, sodass ein langsamer Keyserver niemanden aufhält — und von pepsi-stage-autocrypt-learn aus der eintreffenden Mail. Eine Stage, die einen Schlüssel braucht, den sie nicht hat, committet, was sie behalten darf, pausiert die Nachricht und reiht eine Anfrage ein; der antwortende Dienst gibt im selben Round-Trip jede an dieser Adresse geparkte Nachricht frei.
Entdeckungsquellen, jede eine eigene, nebenläufig ausgeführte Abfrage mit eigenem Rang auf einer Vertrauensleiter: das Web Key Directory (erweiterte und direkte Form), DANE
OPENPGPKEY(RFC 7929) undSMIMEA(RFC 8162) — nur angenommen, wenn das AD-Bit des Resolvers sagt, die Antwort sei DNSSEC-validiert —, das VKS-Protokoll eines verifizierenden Keyservers und LDAP. Unter ihnen allen sitzen auf der Leiter die beiden Sprossen, die keine Entdeckungsdienste sind und keine Instanz haben: aus eingehender Mail geerntetes Material (S/MIME-Signiererzertifikate,application/pgp-keys-Teile undAutocrypt-Header) und — noch eine Sprosse tiefer, ganz unten — der durchAutocrypt-Gossip:eingeführte Schlüssel eines Dritten in einer Nachricht, die verschlüsselt ankam. Beide werden von pepsi-stage-autocrypt-learn unmittelbar geschrieben; eine der beiden inSOURCESzu benennen wird abgelehnt.Veröffentlichung der Schlüssel unserer eigenen Benutzer: die WKD-Endpunkte, die pepsi-httpd bedient, die
OPENPGPKEY/SMIMEA-Einträge, die pepsi-keys und pepsi-setup ausgeben, und — nur auf Anforderung, je Identität — das Hochladen auf einen verifizierenden Schlüsselserver, dessen Bestätigungsmail pepsi-stage-vks-confirm beantwortet.Verwahrung. Privates Material wird verpackt unter einem Schlüsselverschlüsselungsschlüssel gespeichert, der außerhalb der Datenbank liegt, und ist nur von der einen Datenbankrolle erreichbar, unter der die Krypto-Stages laufen.
Ein negativer Cache bedeutet, dass nur die erste Nachricht an oder von einem unbekannten Korrespondenten je wartet.
Schlüsselverwaltung ist das Kapitel über all dies; die Optionsreferenz ist pepsi.conf(5).
9.11. Der Secure-Link-Ausweg¶
Die meisten Korrespondenten veröffentlichen keinen Schlüssel, sodass ENCRYPT = required sonst nur „bounce es“ oder „sende es im Klartext“ ließe. Das Secure-Link-Portal ist die dritte Antwort: pepsi-stage-secure-link legt die Nachricht auf dem Server ab — verschlüsselt unter einer frisch erzeugten PIN — und mailt dem Empfänger einen Link, während die PIN ihn über einen anderen Kanal erreicht (standardmäßig wird sie dem Absender gemailt, der sie weitergibt). Der Empfänger liest die Nachricht in einem Browser, kann ihre Anhänge herunterladen und, wo der Operator es freigibt, antworten.
Der Inhaltsschlüssel ist Argon2id über die PIN, ein Salz je Nachricht und einen Pfeffer, der nur in secrets.d liegt, und gespeichert wird nur das AEAD-Chiffrat — sodass eine gestohlene Datenbank nichts hergibt, ein gestohlener Server nichts hergibt und kein Administrator eine gespeicherte Nachricht lesen kann. Der Betreff reist mit dem Nachrichtentext im Chiffrat; Absender, Empfänger, Zeitstempel und Lebenszykluszähler liegen im Klartext, weil Zustellung, Ablauf und die Frage „ist das angekommen?“ sie brauchen. Eine verlorene PIN ist eine verlorene Nachricht, und der Wiederherstellungsweg ist, dass der Absender erneut sendet.
Nachrichten werden als Text, nie als HTML gerendert, sodass es keinen Bereiniger zu umgehen und keine entfernten Inhalte gibt, die nach Hause telefonieren; eine falsche PIN wird durch eine Sperre je Token und eine Ratenbegrenzung je Quelle begrenzt; und eine Antwort wird ohne state.local_origin injiziert und ausschließlich an den gespeicherten Absender adressiert, sodass das öffentliche Formular kein offenes Relay werden kann. Siehe Das Secure-Link-Ausweichportal für den Ablauf, das Bedrohungsmodell und die Konfiguration.
9.12. Ausgehende DKIM-Signierung¶
Die Stage pepsi-stage-dkim-sign stellt DKIM-Signaturen (RFC 6376) voran — standardmäßig sowohl eine RSA-2048- als auch eine Ed25519-Signatur (RFC 8463), oder unter [pepsi] DKIM_ALGORITHMS nur eine von beiden — unter der SIGNING_DOMAIN oder der From:-Domain der Nachricht. Gmail, Microsoft 365 und Yahoo verifizieren Ed25519 nicht, und Google führt eine solche Signatur in seinen DMARC-Aggregatberichten als fail; DMARC besteht trotzdem über die RSA-Signatur. Die Signatur deckt immer den ganzen Body ab: Das l=-Body-Längen-Tag aus RFC 6376 wird nie ausgegeben, da strenge Verifizierer eine solche Signatur rundweg ablehnen, statt die kürzere Abdeckung hinzunehmen. Das Signieren ist fail-closed: Eine Nachricht, deren Signaturdomain keine Schlüssel hat oder die nicht signiert werden kann, wird als failed markiert, statt unsigniert weitergeschickt zu werden. Da die Header-Auswahl von unten nach oben erfolgt, stört die Signatur bestehende Signaturen nicht.
9.13. Zustellungsstatusbenachrichtigungen¶
Pepsi implementiert DSN durchgängig (RFC 3461 / RFC 3463 / RFC 3464):
Ingress kündigt
DSNan und validiert/speichertRET/ENVID(beiMAIL FROM) undNOTIFY/ORCPT(beiRCPT TO) unterstate.dsn.Die Relay-Stages propagieren diese Parameter an einen nächsten Hop, der ebenfalls
DSNankündigt, und lassen sie andernfalls weg (RFC 3461 §6 — Pepsi wird nicht zum DSN-verantwortlichen Relay).pepsi-stage-bounce gibt den Bericht als RFC-3464-
multipart/reportmit erweiterten RFC-3463-Statuscodes aus:einen Failure-Bericht, wenn
NOTIFYFAILUREanfordert (der Standard bei Abwesenheit) —NOTIFY=NEVERverwirft stillschweigend;einen Success-Bericht (
Action: delivered) nur, wenn das globaleORIGINATE_SUCCESS_DSNgesetzt ist undNOTIFY=SUCCESSangefordert wurde;einen Delay-Bericht (
Action: delayed), wenn dasDELAY_DSN_AFTEReiner Relay-Stage bei einer noch eingereihten Nachricht abläuft, dieNOTIFY=DELAYangefordert hat (höchstens einmal gesendet).
Eine Null-Absender-Nachricht (ein Bounce) wird niemals selbst gebounct (RFC 5321 §6.1).
9.14. Internationalisierte und 8-Bit-Inhalte¶
Ingress kündigt 8BITMIME (RFC 6152) und SMTPUTF8 (RFC 6531) an und hält die BODY=-Deklaration fest. Weil die Fähigkeiten eines nächsten Hops bis nach dem Verbindungsaufbau unbekannt sind, entscheidet der ausgehende SMTP-Client pro Hop:
Unterstützt der Hop die Erweiterung, kündigt Pepsi
BODY=8BITMIME/SMTPUTF8erneut an.Andernfalls stuft es herab: 8-Bit-MIME-Blattteile werden in eine 7-Bit-Transferkodierung umkodiert (RFC 2045 — Quoted-Printable für
text/*, sonst Base64), nach dem Befund der Oktette statt nach der deklarierten Kodierung; UTF-8-Header-Felder werden als RFC-2047-Encoded-Words umgeschrieben, an den drei Stellen, an denen RFC 2047 §5 eines erlaubt (ein unstrukturiertes Feld, eine Display-Name-Phrase, das Innere eines Kommentars); ein Nicht-ASCII-Parameter vonContent-Type/Content-Disposition— der Dateiname eines Anhangs, in einem beliebigen MIME-Teil — erhält die RFC-2231-Form (filename*=UTF-8''caf%C3%A9.txt), und ein Nicht-ASCII-boundary=, für das es keine kodierte Form gibt, wird zusammen mit den Begrenzungszeilen durch ein neues ASCII-Boundary ersetzt.Die herabgestuften Bytes werden dann erneut geprüft: Die Umwandlung geschieht nach bestem Bemühen an einer Nachricht, die niemand validiert hat, und RFC 6152 §3 untersagt es „unter allen Umständen“, einem Hop 8-Bit-Inhalte anzubieten, der
8BITMIMEnicht angekündigt hat; ein Nachrichtentext, der danach immer noch 8-bittig ist, ist daher stattdessen ein dauerhafter Fehler (Bounce).Eine Nicht-ASCII-Adresse (im Umschlag oder innerhalb einer Header-Adresse), die einem Nicht-
SMTPUTF8-Hop gegenüber nicht darstellbar ist, ist ein dauerhafter Fehler (Bounce).
Das Umkodieren des Nachrichtentexts zerstört zwangsläufig eine den Nachrichtentext abdeckende DKIM/ARC-Signatur; dies ist unvermeidbar (Fähigkeiten werden spät gebunden) und selten.
9.15. Ausgehendes Relay¶
Zwei austauschbare Relay-Stages versenden Mail nach außerhalb:
pepsi-stage-relay-to-internet — Direkt-zu-MX-Zustellung (RFC 5321 §5): eigene
MX-Abfrage mit Präferenz-Reihenfolge und Happy-Eyeballs-Adressauswahl (pro Adresse inpepsi.dns_addresszwischengespeichert), impliziter MX über Adress-Einträge (§5.1) und Null-MX-Behandlung (RFC 7505). TLS wird per MTA-STS (RFC 8461) mit Zertifikatsidentitätsprüfungen (RFC 6125) authentifiziert;enforce-Richtlinien verlangen STARTTLS zu einem gelisteten MX.pepsi-stage-relay-to-smarthost — Relay über einen konfigurierten Smarthost, nach Empfängerdomain (oder einem Catch-All) gewählt, mit Transport je MTA (
plain/tls/starttls), Zertifikatsverifikation und der vollständigen SMTP-AUTH-Suite (RFC 4954) —PLAIN/LOGIN,CRAM-MD5,SCRAM-SHA-1/-SHA-256(mit optionalem-PLUS-Channel-Binding),OAUTHBEARER/XOAUTH2, SASLEXTERNAL(TLS-Client-Zertifikat),NTLM,GSSAPI/Kerberos und dem veraltetenDIGEST-MD5— oderauto-Aushandlung. Siehe Client-Authentifizierung und den RFC-Index.
Beide Stages wenden den Schleifenschutz an und zählen die Received:-Header der Nachricht gegen ihre eigene Option MAX_HOP_COUNT — sie ist eine Einstellung der Relay-Stage im Abschnitt [stage-<name>] jeder Stage, keine von Ingress, sodass eine Nachricht gestoppt wird, wenn sie gerade weitergesendet werden soll, und nicht erst, wenn sie ankommt.
Beide Stages authentifizieren das TLS des nächsten Hops mit DANE (RFC 7672, DANE = off|warn|strict) — sie schlagen die TLSA-Einträge des Hops nach und gleichen sie mit der vorgelegten Kette ab, mit Vorrang vor MTA-STS — und halten, wenn [pepsi-tlsrpt] SEND_REPORTS eingeschaltet ist (standardmäßig ist es aus), jede ausgehende TLS-Sitzung für TLS-Reporting (RFC 8460) fest; pepsi-tlsrpt verschickt die täglichen Sammelberichte. Sie teilen sich die Wiederholungssemantik: Ein vorübergehender Fehler pausiert die Nachricht mit exponentiellem Backoff (RETRY_INITIAL/ RETRY_MAX_INTERVAL/RETRY_FACTOR) bis MAX_LIFETIME, nach dem sie gebounct oder als fehlgeschlagen markiert wird; ein dauerhafter Fehler wird zu BOUNCE_STAGE geroutet (oder markiert den Datensatz als failed).
9.16. Lokale Zustellung¶
Für Empfänger in einer lokalen Domain legen drei Stages die Mail auf dem Host ab, statt sie weiterzuleiten (jede reicht die Empfänger, die sie nicht bearbeiten kann, an ihr NEXT_STAGE weiter, sodass sie sich kombinieren lassen):
pepsi-stage-relay-to-maildir — schreibt die Nachricht direkt in das
Maildir/new/jedes lokalen Benutzers. Die Lokalität wird durchLOCAL_DOMAINSundTARGETS(passwd-uid-Bereiche) entschieden; der privilegierte Schreibvorgang wird vom setuid-rootpepsi-helper-maildir-writererledigt, der über das eigenepepsi-maildir-Set-Group-ID-Bit der Stage erreicht wird.pepsi-stage-relay-to-lmtp — übergibt die Nachricht an einen lokalen Mail Delivery Agent (typischerweise Dovecot) über LMTP (RFC 2033), der beim Ablegen der Mail das Sieve-Filter (RFC 5228) jedes Empfängers ausführt. Sie stellt alle Empfänger in einer Transaktion zu und routet jeden, den der MDA ablehnt, anhand seines RFC-3463-Status weiter. Benötigt keinen privilegierten Helper (der MDA gibt Privilegien ab).
pepsi-stage-dot-forward — verarbeitet die
~/.forward-Datei jedes lokalen Benutzers (der klassische sendmail/Postfix-Mechanismus) über den setuid-rootpepsi-helper-dot-forward, der seine Privilegien vor dem Lesen auf den Benutzer absenkt: Weitergeleitete Adressen starten die Pipeline neu,|pipe//file-Direktiven laufen als der Benutzer, und ein Empfänger ohne~/.forwardläuft unverändert durch.
pepsi-stage-aliases ergänzt diese, indem es vor der lokalen Zustellung die Umschlagempfänger über eine Postfix-virtual(5)-artige Map (Volladresse oder @domain-Catch-All, transitiv expandiert) expandiert.
pepsi-stage-vacation beantwortet Mail, die eintrifft, während ein Empfänger abwesend ist, und markiert den Betreff der weitergeleiteten Kopie, sodass er bei seiner Rückkehr sehen kann, welche Mail für ihn beantwortet wurde. Es ist die eine Benutzerfilteraktion, die Pepsi selbst umsetzt, statt sie dem Sieve eines MDA zu überlassen, weil die Antwort eine neue Nachricht ist, die signiert und weitergeleitet werden muss — und weil die Entscheidung, keine zu senden, Pipeline-Wissen ist: RFC 3834 sagt, beantworte nie einen Bounce, Mailinglisten-Mail, irgendetwas bereits als automatisch Markiertes oder eine Dienstadresse, und Pepsi ergänzt sein eigenes „beantworte nie Spam“ und eine Ratenbegrenzung je Korrespondent. Urlaubszeiträume sind gewöhnliche Konfiguration je Adresse, sodass dieselbe Option im globalen Geltungsbereich ein nationaler Feiertag ist und im eigenen pepsi.settings-Datensatz der Urlaub einer einzelnen Person.
pepsi-stage-route ergänzt sie anders: Statt zuzustellen, wählt es je Empfänger einen nächsten Hop anhand der Domain dieses Empfängers und teilt die Nachricht, wenn ihre Empfänger uneins sind. Es ist das, was Pepsi einem bestehenden Mailsystem vorschalten lässt — die Domains hinter dem Gateway gehen zu diesem System, der Rest ins Internet — und es ist die Stelle, an der pepsi-setup nachweist, dass keine von diesem Host bediente Domain in seinen eigenen Ingress zurückgeroutet werden kann. Siehe Microsoft Exchange als Gateway.
9.17. Mailinglisten und Archive¶
Pepsis Mailinglisten-Subsystem ist eine Neuimplementierung von GNU Mailman 3: sein Datenmodell, seine Rule/Chain- und Handler/Pipeline-Architektur, seine REST-API, sein E-Mail-Befehlsvokabular und die Namen seiner Benachrichtigungsvorlagen sind der Entwurf des GNU-Mailman-Projekts, urheberrechtlich geschützt durch die Free Software Foundation, und Dateien, die aus GNU Mailman, Postorius oder HyperKitty übernommen wurden, stehen weiterhin unter der GNU General Public License (vendor/PEPSI-VENDORING.md führt sie auf). Der Abnahmetest lautet: ein unveränderter mailmanclient, Postorius oder HyperKitty steuert es. Siehe Mailinglisten, Archive und Die REST-API von GNU Mailman 3.
Fünf Pipeline-Stages statt eines eigenen Daemons: Routing, Einlieferung, Zustellung pro Mitglied, E-Mail-Befehle und Bounce-Verarbeitung – eine Listennachricht ist damit ein gewöhnlicher Datensatz in der Warteschlange, den ARC, DKIM, SRS, TLS und die Relay-Stages bereits behandeln. Wie das Subsystem aufgebaut ist ist die Übersicht.
Neun Adressen pro Liste und keine Alias-Datei. Mailman schreibt für die neun Adressen jeder Liste Postfix- oder Exim-Maps und lädt den MTA neu; Pepsi routet anhand des Empfängers innerhalb der eigenen Pipeline, es gibt also nichts neu zu erzeugen und nichts, was aus dem Tritt geraten kann.
Moderation mit dem Vokabular von upstream: achtzehn Rules, vier abschließende Chains (
accept,hold,reject,discard) und eine Pipeline aus siebzehn Handlern, mit den Namen, die die REST-API meldet.``List-*``-Header nach RFC 2369 und ``Archived-At`` nach RFC 5064 in jeder Listennachricht.
Ein-Klick-Abmeldung nach RFC 8058 –
List-Unsubscribe-Postplus eine mit einem Schlüssel gesichertehttps:-URI, die ein einzelnesPOSTausführt. Upstream hat das nicht; es ist die eine Stelle, an der Pepsi darüber hinausgeht.Sammelnachrichten in beiden Formaten: die einfache Sammelnachricht nach RFC 1153 und das MIME-
multipart/digest, je Abonnent, mit Band- und Ausgabennummer, einer Größenschwelle und einem periodischen Timer.Bounce-Verarbeitung mit der Bewertungslogik von upstream, VERP-Zuordnung bei jeder Kopie (die siebzehn heuristischen Erkenner sind daher der Rückfall und nicht der Mechanismus), optionalen Probenachrichten, Warnungen und schließlich der Abmeldung.
Ein Archiv – eine Neuimplementierung von HyperKitty, die dessen Message-ID-Hash und URL-Schema beibehält, damit bestehende Archivlinks eine Migration überleben – mit Volltextsuche, optionaler Trigramm-Teilzeichenfolgensuche, mbox-Import und -Export sowie einer
purge-Löschung, die einen Grabstein hinterlässt.Migration von Mailman 2.1 und 3: die
config.pckvon 2.1 wird mit einer eingeschränkten Pickle-Maschine gelesen, die keine Klasse instanziieren kann (ein nicht vertrauenswürdiges Pickle ist damit Daten und kein Code), und ein Mailman-3-Server wird über dessen eigene REST-API gelesen.Kein JavaScript auf irgendeiner Listen- oder Archivseite, und kein
403auf einer öffentlichen Oberfläche: eine Ablehnung ist dasselbe404, das eine nicht vorhandene Liste erhält, denn ein403verrät, dass es sie gibt.
9.18. Unerwünschte Mail¶
Pepsi filtert, nachdem es eine Nachricht angenommen hat; alles Folgende entscheidet also, was mit Mail geschieht, die bereits in der Warteschlange liegt. Drei Mechanismen wirken über ein Urteil, state.spam, und eine Tabelle, pepsi.whitelist, zusammen:
Die Korrespondenz-Whitelist. pepsi-stage-auto-whitelist hält die Empfänger der Mail fest, die Ihre Benutzer senden; pepsi-stage-check-whitelist erkennt deren Antworten (wahlweise nur, wenn DKIM, eine verifizierte Signatur oder ein benannter ARC-Versiegler für sie bürgt) und setzt
state.spam = false. Operator und Benutzer können sie mit pepsi-whitelist von Hand verwalten.Pay-to-Send (pepsi-stage-anti-spam): Mail von allen anderen wird zurückgehalten, bis ihr Absender einen kleinen GNU-Taler-Betrag zahlt.
Confirm-to-Send (pepsi-stage-secretary): Mail von allen anderen wird zurückgehalten, bis ihr Absender einmal auf eine Challenge antwortet. Die Antwort setzt ihn auf die Whitelist, sodass ein Korrespondenzpartner nur ein einziges Mal gefragt wird.
Post-Queue-Milter (SpamAssassin, rspamd, ClamAV, …) und der Sprachfilter können das Urteil ebenfalls setzen oder beeinflussen; siehe pepsi-stage-milter.
9.18.2. Pay-to-Send und Confirm-to-Send im Vergleich¶
Beide halten die Mail unbekannter Absender zurück, und beide senden dem Absender eine automatische Antwort mit Null-Absender, in seiner Sprache. Sie unterscheiden sich darin, was der Absender beweisen muss:
Pay-to-Send |
Confirm-to-Send |
|
|---|---|---|
Der Absender beweist |
dass er für diese Nachricht Geld ausgeben wird |
dass er Mail an der Adresse lesen kann, von der er geschrieben hat |
Stoppt |
Massenmail in jedem Umfang, auch von funktionierenden Postfächern |
Massenmail von Adressen, die nicht empfangen können (den Großteil davon) |
Stoppt nicht |
einen zahlungswilligen Absender |
einen Spammer mit funktionierendem Postfach, der die Antwort automatisieren kann |
Abschreckung |
wirtschaftlich: Jede Nachricht kostet |
nur rechtlich: |
Benötigt |
ein GNU-Taler-Händler-Backend und eine Wallet auf Seiten des Absenders |
nichts außer einer Antwort |
Offen gesagt: Confirm-to-Send ist der schwächere Filter. Er lohnt sich trotzdem, weil er einen legitimen Korrespondenzpartner eine einzige Antwort kostet und einen Mailserver im Betrieb nichts — und beide lassen sich kombinieren. Sind beide aktiviert, läuft der Sekretär zuerst und sein UNCHALLENGEABLE_STAGE zeigt auf die Bezahlschranke, sodass Mail, die man nicht um eine Antwort bitten kann (ein Listenbeitrag, ein nicht authentifizierter oder gefälschter Absender, ein Absender über der täglichen Challenge-Obergrenze), stattdessen zur Zahlung aufgefordert wird, während ein bestätigter Absender die Bezahlschranke mit state.spam = false erreicht und sie unberührt passiert.
Confirm-to-Send geht sorgsam mit Backscatter um, da seine Challenge an den Umschlagsabsender geht und der Umschlagsabsender von Spam meist gefälscht ist: Er fordert nur einen Absender heraus, der SPF oder DMARC bestanden hat (REQUIRE_AUTHENTICATED) und dessen From: dieselbe Adresse ist, höchstens MAX_CHALLENGES_PER_SENDER-mal pro Tag über alle Benutzer hinweg; er antwortet nie auf das, worauf RFC 3834 nicht zu antworten gebietet; und seine Challenge zitiert nichts von der zurückgehaltenen Nachricht außer einem kurzen Hinweis auf ihren Betreff (SUBJECT_HINT_LENGTH, standardmäßig acht Zeichen).
9.18.3. Spamfilter und der Sekretär¶
Standardmäßig bleiben spambewertende Milter (SpamAssassin über spamass-milter, rspamd, MIMEDefang, …) vor der Whitelist-Prüfung, und der Assistent von pepsi-setup erzeugt diese Reihenfolge:
… → milter-spamassassin → check-whitelist → secretary → local
UNCHALLENGEABLE_STAGE = local
Eine Nachricht, die der Filter ablehnt, erreicht den Sekretär nie, sodass offensichtlicher Spam keine Challenge an seinen gefälschten Absender auslöst — so wird Backscatter vermieden. Was den Sekretär doch erreicht, hat den Filter passiert; deshalb setzt der Assistent UNCHALLENGEABLE_STAGE auf das eigene NEXT_STAGE des Sekretärs: Den Filter erneut laufen zu lassen, hieße zweimal zu scannen.
Die Alternative ist, den Filter hinter den Sekretär zu verlegen, sodass er nur Mail scannt, die nicht herausgefordert werden konnte:
… → check-whitelist → secretary → local
└─ UNCHALLENGEABLE_STAGE → milter-spamassassin → local
Die Konfigurationsänderung für einen Filter unter [stage-milter-spamassassin]:
Nehmen Sie den Filter aus der Hauptkette: Setzen Sie das
NEXT_STAGEder Stage, die auf ihn zeigte, auf das eigeneNEXT_STAGEdes Filters (normalerweisecheck-whitelist).Setzen Sie in
[stage-secretary]UNCHALLENGEABLE_STAGE = milter-spamassassin.Setzen Sie in
[stage-milter-spamassassin]NEXT_STAGEauf dasNEXT_STAGEdes Sekretärs (hierlocal).
Führen Sie dann pepsi-setup check (oder run) aus, um den Graphen zu validieren.
Der Kompromiss wirkt in beide Richtungen:
Dafür: Die CPU-Zeit des Filters wird nur für die Mail aufgewendet, die ihn braucht. Mail von der Whitelist und Mail von bestätigten Absendern — der Großteil eines persönlichen Postfachs — wird nie gescannt.
Dagegen: Challenges gehen nun ungescannt hinaus. Spam, den der Filter abgelehnt hätte, löst zuerst eine Challenge aus, was mehr Backscatter an gefälschte Absender bedeutet (begrenzt durch
REQUIRE_AUTHENTICATEDund die tägliche Obergrenze, aber nicht null); und Spam, dessen Absender tatsächlich bestätigt — die eine Art, die Confirm-to-Send nicht stoppen kann —, wird zugestellt, ohne dass der Filter ihn je sieht.
Welches Layout Sie auch wählen, Viren- und Richtlinien-Milter bleiben auf dem Hauptpfad (vor der Whitelist-Prüfung): Ein bestätigter oder auf der Whitelist stehender Korrespondenzpartner kann trotzdem Malware senden, von einem kompromittierten Konto aus oder unwissentlich, und das Urteil eines Richtlinienfilters gilt für alle.
9.19. Betriebsfunktionen¶
Einzeltabellen-Pipeline mit Absturzwiederherstellung: verwaiste
running-Datensätze werden beim Dispatcher-Start zurückgesetzt; in Bearbeitung befindliche Kindprozesse werden beim Herunterfahren zurückgesetzt.Elastische, pipelinende Worker-Pools und Watchdog: Jede Stage betreibt persistente Worker-Prozesse, die bei Bedarf bis zu ihrem
PARALLELISMgestartet und nachWORKER_IDLE_TIMEOUTabgeräumt, nachMAX_MESSAGESerneuert werden; jeder Worker bekommt bis zuQUEUE_LIMITNachrichten auf einmal zugeführt (in Bearbeitung befindliche KapazitätQUEUE_LIMIT × PARALLELISM, ohne zusätzliche Verbindungskosten), und ein Worker, derMAX_RUNTIMEbei seiner vordersten Nachricht überschreitet, wird beendet (timeout) und ersetzt.Warteschlangen-Werkzeuge: pepsi-queue listet, löscht, verschiebt zwischen Stages und löst Nachrichten in großer Zahl los.
Zustandsüberwachung: pepsi-status gibt eine nur lesende Zusammenfassung der Warteschlange, festhängender Nachrichten, kumulativer Zustell-/Fehlerzähler und jüngster ausgehender TLS-Ergebnisse aus (auch als
--json), geeignet zur Ausführung über SSH.Einrichtung und DNS-Überprüfung: pepsi-setup installiert das Schema, erzeugt Schlüssel und gibt DNS aus/validiert es (DKIM, SPF, MTA-STS).
HTTP-Server: pepsi-httpd bedient über einen oder mehrere TLS- (SNI-gewählte) oder Klartext-Listener die MTA-STS-Richtliniendatei (
/.well-known/mta-sts.txt), eine Prometheus-/metrics-Seite (nur auf einem Listener mitADMIN = yes— sie beschreibt die Pipeline), die Web-Key-Directory-Endpunkte, die die eigenen Identitäten dieser Installation veröffentlichen (/.well-known/openpgpkey/…, direkte und erweiterte Form), das Das Secure-Link-Ausweichportal-Portal und das untenstehende Mail-Autokonfigurations-Dokument.Autokonfiguration von Mail-Clients (draft-ietf-mailmaint-autoconfig): Ein Client, dem nichts als
fred@example.orggegeben wurde, holthttps://autoconfig.example.org/mail/config-v1.1.xmlund konfiguriert sich selbst — Submission-Host, Port, Transportsicherheit und Authentifizierung, und dasselbe für den Postfachserver. Die Submission-Hälfte wird vom laufenden Submission-Listener abgeleitet, sodass sie nicht von dem Server abdriften kann, den sie beschreibt; die Postfachhälfte benennt den MDA, mit dem die Installation gepaart ist. Öffentlich und ohne Authentifizierung bedient, wie der Entwurf es verlangt, weil ein Client es lesen muss, bevor er wissen kann, wie er sich authentifiziert.Administrative API und Konsole: Auf einem Listener, der ausdrücklich mit
ADMIN = yesgekennzeichnet ist — und nie auf einem, der sie im Klartext vom Host führen würde —, stellt derselbe Server die Die administrative API unter/api/v1(Warteschlange, Gesundheit, Konfiguration, Schlüsselspeicher, Prüf- und Mailjournale) und die Browser-Die Verwaltungskonsole unter/uibereit, die ein Client genau dieser API ist. Überall sonst antworten diese Pfade mit demselben404wie ein unbekannter Pfad. Die Authentifizierung erfolgt über die Peer-Zugangsdaten des UNIX-Sockets, ein Sitzungs-Cookie oder ein Bearer-Token, und jeder Prinzipal trägt Geltungsbereiche; all das wird im Prüfprotokoll erfasst.Metriken:
pepsi-dispatchzeichnet den Durchsatz pro Stage, Kills/Timeouts, Abstürze und Verarbeitungszeit sowie die globalen Stage-/Nachrichten-Gesamtwerte auf (etwa einmal pro Minute in einer Transaktion in die Datenbank geschrieben), exportiert vonpepsi-httpdneben Live-Anzeigen für aktiv/pausiert, die aus der Warteschlange gelesen werden.Strukturiertes Logging über
tracingauf konfigurierbaren Stufen.
Für Standards, die Pepsi nicht implementiert (darunter BINARYMIME), siehe Anwendbare, noch nicht implementierte RFCs.
9.20. Funktionsstabilität¶
Jede in diesem Kapitel beschriebene Funktion wird in einer einzigen Funktionsstabilität-Tabelle erfasst, die — pro Funktion — ihren maßgeblichen RFC festhält, ob sie einen automatisierten Test hat (und welcher Art: U Unit, I Integration, I/U beides), ob sie von Hand verifiziert wurde und wie weit sie laut anonymer, freiwilliger Nutzungstelemetrie (pepsi-telemetry) verbreitet und genutzt ist.
Diese Tabelle wird generiert: contrib/update-feature-stability.sh führt das von Hand gepflegte Register contrib/feature-registry.tsv (Spalten Name, RFC, Test und manueller Test) mit einem pepsi-telemetry-GET /telemetry/report (den Verbreitungs- und Nutzungszahlen) zusammen. Siehe Die Pipeline erweitern dazu, wie Sie sie aktuell halten, wenn Sie eine Funktion hinzufügen, einen Test schreiben oder die Telemetriezahlen auffrischen.