# DMS-CUSTOM-APPEND # =========================================================================== # WICHTIG: Diese Datei wird von user-patches.sh an /etc/rspamd/local.d/settings.conf # ANGEHAENGT und nicht darueber kopiert. DMS legt in dieser Datei selbst eine # Regel fuer authentifizierte User ab (DMS::SED_TAG::1), die erhalten bleiben muss. # =========================================================================== # # Hintergrund # ----------- # Externe Mail erreicht DMS nie direkt: SES -> S3/SQS -> email-worker -> SMTP. # Rspamd sieht als Client-IP daher immer den Worker-Container (172.x) statt des # echten Absender-Servers. Alle verbindungsbezogenen Pruefungen messen damit # unsere eigene Infrastruktur und liefern systematisch Strafpunkte: # # HFILTER_HOSTNAME_UNKNOWN 6.0 (kein PTR fuer 172.x -> exakt die add_header-Schwelle) # R_SPF_FAIL / R_SPF_SOFTFAIL 4.5 / 2.5 # R_DKIM_NA / R_DKIM_PERMFAIL 1.0 / 4.5 # # Diese Gruppen werden fuer Einlieferungen aus dem Docker-Netz deaktiviert. # Inhaltsbezogene Pruefungen (Bayes, Fuzzy, URL-/Surbl-Blocklisten, MIME, # Attachment-Checks) bleiben vollstaendig aktiv - echter Spam wird also weiter # erkannt, nur eben anhand des Inhalts statt anhand einer Transportstrecke, # die rspamd hier gar nicht beurteilen kann. # # SPF/DKIM/DMARC gehen dadurch nicht verloren: SES prueft sie bereits mit der # echten Absender-IP. Das Ergebnis liegt im SQS-Payload (receipt.spamVerdict, # spfVerdict, dkimVerdict, dmarcVerdict). Sobald der Worker diese Verdicts als # Header stempelt, koennen sie hier per multimap wieder bepunktet werden. # --------------------------------------------------------------------------- # 1) Vom Worker SELBST komponierte Mail: Weiterleitungen und OOO-Antworten # # Zusaetzlich zu den Auth-Symbolen aus Regel 2 fallen hier inhaltliche Symbole # an, die auf die Bauform der Weiterleitung reagieren. buildForwardMessage() # in email-worker-nodejs/src/email/rules-processor.ts setzt: # # From: die getroffene lokale Adresse (support@bayarea-cc.com) # To: das Weiterleitungsziel (ebrunks@bayarea-cc.com) # Reply-To: den Originalabsender (andreas.knuth@gmail.com) # # Damit sieht jede Weiterleitung an einen Kollegen in derselben Domain formal # aus wie CEO-Fraud: Absender und Empfaenger intern, Antwort geht nach aussen # an eine Freemail-Adresse. Rspamd bepunktet das - zu Recht, nur ist die # Praemisse hier falsch, weil wir die Mail selbst gebaut haben: # # SPOOF_REPLYTO 6.0 From-Domain == To-Domain != Reply-To-Domain # FREEMAIL_REPLYTO_NEQ_FROM 2.0 Reply-To ist Freemail und != From # # Belegt an F228E320085 (2026-08-15 07:53:38): Score 7.95, also ueber # add_header = 6 - die Weiterleitung landete im Junk, waehrend dieselbe Mail # als Original an support@ mit -1.05 sauber durchlief (EC702320085). # # WARUM EINE EIGENE REGEL statt symbols_disabled in Regel 2: # Regel 2 gilt auch fuer "delivered", also fuer echte eingehende Fremdmail. # Dort ist SPOOF_REPLYTO genau das Signal, das BEC-Angriffe erkennt - das # darf nicht verloren gehen. Diese Regel prueft deshalb den WERT des Headers # und greift nur fuer Mail aus unserer eigenen Komposition. # # Die Auth-Gruppen muessen wiederholt werden: rspamd wertet nach Prioritaet # aus und wendet nur die erste passende Regel an, Regel 2 greift hier also # nicht mehr. # # Falls der Regexp-Vergleich nicht zieht, faellt die Mail auf Regel 2 zurueck # und behaelt ihre 7.95 - der Fehler ist damit sichtbar, nicht still. Pruefen # laesst sich das am Feld "Regel:" in: # docker exec mailserver bash /tmp/docker-mailserver/rspamd_report.sh --detail # Erwartet wird ses_worker_forwarded. # --------------------------------------------------------------------------- ses_worker_forwarded { priority = 20; ip = ["172.16.0.0/12", "127.0.0.0/8"]; header = { "X-SES-Worker-Processed" = "^(forwarded|ooo-reply)$"; } apply { groups_disabled = ["spf", "dkim", "dmarc", "hfilter"]; symbols_disabled = ["RDNS_NONE", "SPOOF_REPLYTO", "FREEMAIL_REPLYTO_NEQ_FROM", "FREEMAIL_REPLYTO"]; } } # --------------------------------------------------------------------------- # 2) Uebrige Einlieferungen des email-workers (externe Mail, "delivered") # # Der Worker setzt X-SES-Worker-Processed auf JEDER Mail, die er einliefert: # delivered = Originalmail an das lokale Postfach -> diese Regel # forwarded = neu komponierte Weiterleitung -> Regel 1 # ooo-reply = Abwesenheitsantwort -> Regel 1 # # Hier werden ausschliesslich die Transportpruefungen abgeschaltet. Alle # inhaltlichen Symbole bleiben aktiv, insbesondere SPOOF_REPLYTO. # # Die IP-Bedingung ist die Absicherung: ohne sie koennte ein externer Absender # den Header selbst setzen und die Auth-Pruefungen abschalten. Beide # Bedingungen werden von rspamd implizit mit UND verknuepft. # --------------------------------------------------------------------------- ses_worker_injected { priority = 10; ip = ["172.16.0.0/12", "127.0.0.0/8"]; header = { "X-SES-Worker-Processed" = true; } apply { groups_disabled = ["spf", "dkim", "dmarc", "hfilter"]; symbols_disabled = ["RDNS_NONE"]; } } # --------------------------------------------------------------------------- # 3) Lokale Re-Injection ohne Worker-Header # # Betrifft: # - Sieve-Redirects fuer INTERNE Mail (accounting@ -> support@ -> Forwards). # Diese Mail laeuft nie ueber SES/Worker, hat also keinen Worker-Header. # - Roundcube, das ohne SASL-Auth aus dem Docker-Netz einliefert # (ROUNDCUBEMAIL_SMTP_USER ist bewusst leer). # # Beides wurde bisher von der DOCKER_WL-Whitelist (-50) aufgefangen. Diese # Regel ersetzt sie - deutlich enger gefasst, weil sie an das Docker-Netz # gebunden ist statt an eine faelschbare Absenderdomain. # # Niedrigste Prioritaet: rspamd wertet Regeln nach Prioritaet aus und nimmt # den ersten Treffer, Worker-Mail landet also immer in Regel 1 oder 2. # # ACHTUNG: Diese Regel setzt voraus, dass Port 25 NICHT oeffentlich erreichbar # ist (docker-compose.yml bindet ihn auf 127.0.0.1). Wird das je geaendert, # muss diese Regel weg - sonst umgeht jeder externe Absender die Pruefung. # --------------------------------------------------------------------------- local_reinjection { priority = 5; ip = ["172.16.0.0/12", "127.0.0.0/8"]; apply { groups_enabled = ["dkim"]; } }