Fix: ARC-Ketten-Validierung und doppelter X-ARC-Header behoben
- Einrückungsfehler (IndentationError) im Milter-Skript gefixt - Logik erweitert: Startet als Instanz 1, wenn eingehende Mails kein ARC besitzen (CV=none) - Schutz vor duplizierten X-ARC Headern implementiert - Selector-Handling im Generator flexibler gestaltet (CLI-Parameter hinzugefügt) - Feste Shebangs auf die virtuelle Umgebung (/usr/share/pyarc-venv) umgestellt
This commit is contained in:
+51
-21
@@ -7,8 +7,12 @@ import configparser
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
# Erhöht den DNS-Timeout für dkimpy bei großen Keys
|
||||||
|
dkim.dns_timeout = 15
|
||||||
|
|
||||||
CONFIG_PATH = "/etc/pyarc/milter.conf"
|
CONFIG_PATH = "/etc/pyarc/milter.conf"
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
@@ -79,6 +83,15 @@ class ArcMilter(Milter.Base):
|
|||||||
full_mail = b"".join([b"%s: %s\r\n" % (k, v) for k, v in self.headers]) + b"\r\n" + self.body_buffer.read()
|
full_mail = b"".join([b"%s: %s\r\n" % (k, v) for k, v in self.headers]) + b"\r\n" + self.body_buffer.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# 1. Vorhandene X-ARC Header aus früheren Stationen entfernen
|
||||||
|
idx = 1
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
self.changeheader('X-ARC', idx, '')
|
||||||
|
idx += 1
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
|
||||||
# --- 1. Eingehend: ARC Validierung ---
|
# --- 1. Eingehend: ARC Validierung ---
|
||||||
arc_verifier = dkim.ARC(full_mail)
|
arc_verifier = dkim.ARC(full_mail)
|
||||||
cv, results, comment = arc_verifier.verify()
|
cv, results, comment = arc_verifier.verify()
|
||||||
@@ -87,41 +100,58 @@ class ArcMilter(Milter.Base):
|
|||||||
logger.info(f"[{self.id}] Validierung für Domain '{self.from_domain}': CV={cv_str} ({comment})")
|
logger.info(f"[{self.id}] Validierung für Domain '{self.from_domain}': CV={cv_str} ({comment})")
|
||||||
self.addheader('Authentication-Results', f"{AUTH_SERV_ID}; arc={cv_str}")
|
self.addheader('Authentication-Results', f"{AUTH_SERV_ID}; arc={cv_str}")
|
||||||
|
|
||||||
is_arc_valid = (cv_str == "pass")
|
# Kette ist valide, wenn pass ODER ein unbeflecktes none vorliegt
|
||||||
|
is_arc_valid = (cv_str in ["pass", "none"] and "fail" not in comment.lower())
|
||||||
|
|
||||||
if cv_str == "fail" and REJECT_ON_FAIL:
|
if cv_str == "fail" and REJECT_ON_FAIL:
|
||||||
logger.warning(f"[{self.id}] Mail abgewiesen: ARC Validation fehlgeschlagen.")
|
logger.warning(f"[{self.id}] Mail abgewiesen: ARC Validation fehlgeschlagen.")
|
||||||
self.setreply('550', '5.7.1', 'ARC validation failed')
|
self.setreply('550', '5.7.1', 'ARC validation failed')
|
||||||
return Milter.REJECT
|
return Milter.REJECT
|
||||||
|
|
||||||
# --- 2. Ausgehend: Dynamische ARC Signierung ---
|
# --- 2. Ausgehend / First-Hop: Dynamische ARC Signierung ---
|
||||||
|
sign_domain = None
|
||||||
|
selector = None
|
||||||
|
key_path = None
|
||||||
|
|
||||||
if self.from_domain and config.has_section(self.from_domain):
|
if self.from_domain and config.has_section(self.from_domain):
|
||||||
|
sign_domain = self.from_domain
|
||||||
selector = config.get(self.from_domain, "selector")
|
selector = config.get(self.from_domain, "selector")
|
||||||
key_path = config.get(self.from_domain, "private_key_path")
|
key_path = config.get(self.from_domain, "private_key_path")
|
||||||
|
|
||||||
if os.path.exists(key_path):
|
elif cv_str == "none":
|
||||||
with open(key_path, "rb") as f:
|
main_domain = ".".join(AUTH_SERV_ID.split(".")[-2:])
|
||||||
private_key = f.read()
|
if config.has_section(main_domain):
|
||||||
|
sign_domain = main_domain
|
||||||
|
selector = config.get(main_domain, "selector")
|
||||||
|
key_path = config.get(main_domain, "private_key_path")
|
||||||
|
logger.info(f"[{self.id}] Keine ARC-Kette vorhanden (CV=none). Starte neue Kette für lokale Hauptdomain {main_domain}.")
|
||||||
|
|
||||||
sig_headers = dkim.arc_sign(
|
if sign_domain and key_path and os.path.exists(key_path):
|
||||||
full_mail,
|
with open(key_path, "rb") as f:
|
||||||
selector=selector.encode('utf-8'),
|
private_key = f.read()
|
||||||
domain=self.from_domain.encode('utf-8'),
|
|
||||||
privkey=private_key,
|
|
||||||
srv_id=AUTH_SERV_ID.encode('utf-8')
|
|
||||||
)
|
|
||||||
|
|
||||||
for header_line in sig_headers:
|
sig_headers = dkim.arc_sign(
|
||||||
if b':' in header_line:
|
full_mail,
|
||||||
name, val = header_line.split(b':', 1)
|
selector=selector.encode('utf-8'),
|
||||||
self.addheader(name.decode('utf-8').strip(), val.decode('utf-8').strip())
|
domain=sign_domain.encode('utf-8'),
|
||||||
|
privkey=private_key,
|
||||||
|
srv_id=AUTH_SERV_ID.encode('utf-8')
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(f"[{self.id}] Mail für {self.from_domain} erfolgreich signiert (Selector: {selector}).")
|
for header_line in sig_headers:
|
||||||
is_arc_valid = True
|
if b':' in header_line:
|
||||||
else:
|
name, val = header_line.split(b':', 1)
|
||||||
logger.error(f"[{self.id}] Key für {self.from_domain} nicht gefunden unter {key_path}")
|
self.addheader(name.decode('utf-8').strip(), val.decode('utf-8').strip())
|
||||||
|
|
||||||
self.addheader('X-ARC', 'TRUE' if is_arc_valid else 'FALSE')
|
logger.info(f"[{self.id}] Mail erfolgreich ARC-versiegelt (Domain: {sign_domain}, Selector: {selector}).")
|
||||||
|
is_arc_valid = True
|
||||||
|
elif sign_domain:
|
||||||
|
logger.error(f"[{self.id}] Key für {sign_domain} nicht gefunden unter {key_path}")
|
||||||
|
|
||||||
|
# --- 3. Einmaliges Setzen des X-ARC Headers ---
|
||||||
|
already_added = any(h[0].lower() == b'x-arc' for h in self.headers)
|
||||||
|
if not already_added:
|
||||||
|
self.addheader('X-ARC', 'TRUE' if is_arc_valid else 'FALSE')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[{self.id}] Fehler beim ARC-Processing: {e}", exc_info=True)
|
logger.error(f"[{self.id}] Fehler beim ARC-Processing: {e}", exc_info=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user