Inhaltsverzeichnis
Postfix CentOS 7 - OpenDMARC anbinden (opendmarc-milter)
DMARC ist an sich kein eigenständiger Prozess in der e-Mail-Verarbeitung, vielmehr erweitert DMARC die Ergebnisprüfung der beiden Techniken SPF und OpenDKIM. DMARC ergänzt somit SPF und OpenDKIM, ohne die DMARC nicht funktionieren kann.
DMARC ergänzt SPF und OpenDKIM, indem festgelegt wird, was der empfangende e-Mail-Server mit einer e-Mail tun soll, welche die SPF oder OpenDKIM Prüfung nicht erfolgreich bestanden hat. Hierfür sind zwei Dinge notwendig:
- Ein DNS TXT Record, der dem empfangenden e-Mail-Server sagt, was zu tun ist
Beschreibung | Externer Link |
---|---|
Homepage | http://www.trusteddomain.org/opendmarc/ |
Dokumentation | http://www.trusteddomain.org/opendmarc/opendmarc-README |
Ab hier werden zur Ausführung nachfolgender Befehle root
-Rechte benötigt. Um der Benutzer root
zu werden, melden Sie sich bitte als root
-Benutzer am System an, oder wechseln mit nachfolgendem Befehl zum Benutzer root
:
$ su - Password:
Voraussetzungen
Die Installation und korrekt Konfiguration von nachfolgenden Diensten/Daemon bzw. MILTER ist erforderlich, da ohne diese OpenDMARC nicht funktionieren kann!
- SPF,
- Siehe auch nachfolgenden internen Link: Postfix CentOS 7 - SPF anbinden (spf-milter)
-
- Siehe auch nachfolgenden internen Link: Postfix CentOS 7 - OpenDKIM anbinden (opendkim-milter)
OpenDMARC führt seine Auswertungen nach den Einträgen im e-Mail-Header welche von SPF und OpenDKIM durch und trifft aufgrund dieser Einträge auch letztendlich die Entscheidung ob eine e-Mail angenommen oder abgelehnt wird.
Herunterladen
Nachfolgend sollen das Drittanbieter-Repository von EPEL, welches wie unter nachfolgendem internen Link dargestellt, eingebunden werden:
Installation
Nachfolgendes rpm
-Paket ist zur Installation erforderlich:
Zusätzlich wird nachfolgendes rpm
-Paket als Abhängigkeit zusätzlich installiert:
Die Installation von opendmarc
, kann durch ausführen des nachfolgenden Befehls durchgeführt werden:
# yum install opendmarc Loaded plugins: changelog, priorities 149 packages excluded due to repository priority protections Resolving Dependencies --> Running transaction check ---> Package opendmarc.x86_64 0:1.4.1-1.el7 will be installed --> Processing Dependency: libopendmarc(x86-64) = 1.4.1-1.el7 for package: opendmarc-1.4.1-1.el7.x86_64 --> Processing Dependency: perl(Switch) for package: opendmarc-1.4.1-1.el7.x86_64 --> Processing Dependency: perl(DBD::mysql) for package: opendmarc-1.4.1-1.el7.x86_64 --> Processing Dependency: libopendmarc.so.2()(64bit) for package: opendmarc-1.4.1-1.el7.x86_64 --> Running transaction check ---> Package libopendmarc.x86_64 0:1.4.1-1.el7 will be installed ---> Package perl-DBD-MySQL.x86_64 0:4.023-5.el7 will be installed ---> Package perl-Switch.noarch 0:2.16-7.el7 will be installed --> Finished Dependency Resolution Changes in packages about to be updated: Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: opendmarc x86_64 1.4.1-1.el7 epel 121 k Installing for dependencies: libopendmarc x86_64 1.4.1-1.el7 epel 27 k perl-DBD-MySQL x86_64 4.023-5.el7 base 140 k perl-Switch noarch 2.16-7.el7 base 22 k Transaction Summary ================================================================================ Install 1 Package (+3 Dependent packages) Total download size: 310 k Installed size: 757 k Is this ok [y/d/N]: y Downloading packages: (1/4): libopendmarc-1.4.1-1.el7.x86_64.rpm | 27 kB 00:00 (2/4): opendmarc-1.4.1-1.el7.x86_64.rpm | 121 kB 00:00 (3/4): perl-DBD-MySQL-4.023-5.el7.x86_64.rpm | 140 kB 00:00 (4/4): perl-Switch-2.16-7.el7.noarch.rpm | 22 kB 00:00 -------------------------------------------------------------------------------- Total 712 kB/s | 310 kB 00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : perl-Switch-2.16-7.el7.noarch 1/4 Installing : libopendmarc-1.4.1-1.el7.x86_64 2/4 Installing : perl-DBD-MySQL-4.023-5.el7.x86_64 3/4 Installing : opendmarc-1.4.1-1.el7.x86_64 4/4 Verifying : perl-DBD-MySQL-4.023-5.el7.x86_64 1/4 Verifying : opendmarc-1.4.1-1.el7.x86_64 2/4 Verifying : libopendmarc-1.4.1-1.el7.x86_64 3/4 Verifying : perl-Switch-2.16-7.el7.noarch 4/4 Installed: opendmarc.x86_64 0:1.4.1-1.el7 Dependency Installed: libopendmarc.x86_64 0:1.4.1-1.el7 perl-DBD-MySQL.x86_64 0:4.023-5.el7 perl-Switch.noarch 0:2.16-7.el7 Complete!
Die Installation von opendmarc
, kann durch ausführen des nachfolgenden Befehls durchgeführt werden:
# rpm -qil opendmarc Name : opendmarc Version : 1.4.1 Release : 1.el7 Architecture: x86_64 Install Date: Mon 07 Jun 2021 03:08:31 PM CEST Group : Unspecified Size : 250395 License : BSD and Sendmail Signature : RSA/SHA256, Sat 22 May 2021 08:49:51 PM CEST, Key ID 6a2faea2352c64e5 Source RPM : opendmarc-1.4.1-1.el7.src.rpm Build Date : Sat 22 May 2021 08:44:46 PM CEST Build Host : buildhw-x86-06.iad2.fedoraproject.org Relocations : (not relocatable) Packager : Fedora Project Vendor : Fedora Project URL : http://www.trusteddomain.org/opendmarc.html Bug URL : https://bugz.fedoraproject.org/opendmarc Summary : A Domain-based Message Authentication, Reporting & Conformance (DMARC) milter and library Description : OpenDMARC (Domain-based Message Authentication, Reporting & Conformance) provides an open source library that implements the DMARC verification service plus a milter-based filter application that can plug in to any milter-aware MTA, including sendmail, Postfix, or any other MTA that supports the milter protocol. The DMARC sender authentication system is still a draft standard, working towards RFC status. The database schema required for some functions is provided in /usr/share/opendmarc/db. The rddmarc tools are provided in /usr/share/opendmarc/contrib/rddmarc. /etc/opendmarc /etc/opendmarc.conf /etc/sysconfig/opendmarc /etc/tmpfiles.d/opendmarc.conf /run/opendmarc /usr/lib/systemd/system/opendmarc.service /usr/sbin/opendmarc /usr/sbin/opendmarc-check /usr/sbin/opendmarc-expire /usr/sbin/opendmarc-import /usr/sbin/opendmarc-importstats /usr/sbin/opendmarc-params /usr/sbin/opendmarc-reports /usr/share/doc/opendmarc-1.4.1 /usr/share/doc/opendmarc-1.4.1/README /usr/share/doc/opendmarc-1.4.1/RELEASE_NOTES /usr/share/licenses/opendmarc-1.4.1 /usr/share/licenses/opendmarc-1.4.1/LICENSE /usr/share/licenses/opendmarc-1.4.1/LICENSE.Sendmail /usr/share/man/man5/opendmarc.conf.5.gz /usr/share/man/man8/opendmarc-check.8.gz /usr/share/man/man8/opendmarc-expire.8.gz /usr/share/man/man8/opendmarc-import.8.gz /usr/share/man/man8/opendmarc-importstats.8.gz /usr/share/man/man8/opendmarc-params.8.gz /usr/share/man/man8/opendmarc-reports.8.gz /usr/share/man/man8/opendmarc.8.gz /usr/share/opendmarc /usr/share/opendmarc/contrib /usr/share/opendmarc/contrib/rddmarc /usr/share/opendmarc/contrib/rddmarc/README.rddmarc /usr/share/opendmarc/contrib/rddmarc/dmarcfail.py /usr/share/opendmarc/contrib/rddmarc/dmarcfail.pyc /usr/share/opendmarc/contrib/rddmarc/dmarcfail.pyo /usr/share/opendmarc/contrib/rddmarc/mkdmarc /usr/share/opendmarc/contrib/rddmarc/mysql_ip6.c /usr/share/opendmarc/contrib/rddmarc/rddmarc /usr/share/opendmarc/db /usr/share/opendmarc/db/README.schema /usr/share/opendmarc/db/schema.mysql /var/spool/opendmarc
iptables Regel
Damit der SPF auch über den Postfix - spf-milter
erreichbar ist und nicht das Empfangen der IP-Paket vom Paketfilter iptables
blockiert wird, muss nachfolgende Regel zum iptables
-Regelwerk hinzugefügt werden.
Um die aktuellen iptables
-Regeln erweitern zu können, sollten diese erst einmal aufgelistet werden, was mit nachfolgendem Befehl durchgeführt werden kann:
# iptables -L -nv --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 2 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 3 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 5 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination
Nachfolgender Befehl, fügt folgende iptables
-Regel dem iptables
-Regelwerk nach der Position 4 hinzu, ohne das der Paketfilter angehalten werden muss:
-A INPUT -p tcp --dport 10013 -j ACCEPT
und hier der Befehl:
# iptables -I INPUT 5 -p tcp --dport 10013 -j ACCEPT
Ein erneute Abfrage des iptables
-Regelwerts, sollte dann nachfolgend dargestellte Ausgabe ergeben, was mit folgendem Befehl durchgeführt werden kann:
# iptables -L -nv --line-numbers Chain INPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 2 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 3 0 0 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0 4 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22 5 0 0 ACCEPT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:10013 state NEW 6 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination
Die neue Zeile ist an Position 5 (INPUT) zu sehen, hier nachfolgend zur Verdeutlichung noch einmal dargestellt (nur relevanter Ausschnitt):
... 5 0 0 ACCEPT tcp -- eth0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:10013 state NEW ...
Um diese iptables
-Regel dauerhaft, auch nach einem Neustart des Server, weiterhin im iptables
-Regelwerk zu speichern, muss nachfolgend dargestellter Befehl abschließend noch ausgeführt werden:
# /usr/sbin/iptables-save > /etc/sysconfig/iptables
Konfiguration: DNS
Damit bei ausgehenden e-Mails auch unsere DMARC-Übrprüfung erfolgreich ist, wir nachfolgender Eintrag im DNS benötigt, damit der Abfragende bestimmen kann, wie er mit Nachrichten von uns selbst umgehen soll, wenn die DMARC-Überprüfung seinerseits fehl schlägt.
Unter nachfolgendem externen Link, kann ein TXT-Record, welcher DMARC-Informationen enthalten soll, komfortabel erstellt werden:
Nach der Erstellung über oben genannten Assistenten, kann der TXT-RECORD zur DMARC-Überprüfung wie folgt aussehen:
v=DMARC1; p=none; rua=mailto:dmarc-aggregate@tachtler.net; ruf=mailto:dmarc-incorrect@tachtler.net; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400; sp=none
Parameter | Wert | Erklärung |
---|---|---|
v | DMARC1 | Identifiziert den Datensatz als DMARC-Record. Der Parameter muss als erster wert im DMARC-Record gesetzt sein. Fehlt dieser ist der gesamte DMARC-Record zu verwerfen! |
p | none | Beschreibt, wie der Empfänger auf die Nachrichten des Domain-Inhabers reagieren soll, wenn die DMARC-Überprüfung fehl schlägt. Dies gilt auch für die Subdomains, sofern für diese mit dem Parameter sp keine separate Definition vorliegt. Mögliche Werte sind: none : Der Domaininhaber hat keine Vorgaben zur Verabeitung/Zustellung der e-Mails gemacht. quarantine : Der Domaininhaber wünscht, dass e-Mails, als verdächtig gewertet werden sollen. Abhängig vom Empfänger können diese als verdächtig markiert werden, mit weiteren/zusätzlichen SPAM Prüfungen zu belegen ist, oder in einen SPAM-Ordner verschoben werden soll. reject : Der Domaininhaber wünscht, dass e-Mails abgewiesen, also nicht angenommen werden sollen. Dies sollte, wenn möglich, noch während des SMTP-Dialogs passieren. |
rua | mailto:dmarc-aggregate@tachtler.net | Der Domaininhaber wünscht, per e-Mail mit aufbereiteten Statistikdaten der verarbeiteten e-Mails informiert zu werden. Ist dieser Parameter nicht gesetzt, braucht der Empfänger keine Statistikdaten aufzubereiten. |
ruf | mailto:dmarc-incorrect@tachtler.net | Der Domaininhaber wünscht, per e-Mail mit detaillierten forensischen Statistikdaten der verarbeiteten e-Mails informiert zu werden. Ist dieser Parameter nicht gesetzt, braucht der Empfänger keine Statistikdaten aufzubereiten. |
fo | 0 | Optionen zu den Fehlerreports, welche die gewünschte Detaillierung angeben. |
adkim | r | Definiert, wie konservativ das Ergebnis der DKIM-Signaturüberprüfung bewertet werden soll. Mögliche Werte sind: r=relaxed s=strikt |
aspf | r | Definiert, wie konservativ das Ergebnis der SPF-Üüberprüfung bewertet werden soll. Mögliche Werte sind: r=relaxed s=strikt |
pct | 100 | Der Domaininhaber wünscht, dass der angegebene Prozentwert an Nachrichten von den DMARC-Überprüfungen benutzt werden soll. Der Wert beschreibt nicht das Verhältnis in den DMARC-Reports! |
rf | afrf | Der Domaininhaber wünscht, dass die aufbereiteten forensischen Prüfberichte im Format AFRF oder IODEF zu erhalten, wenn sowohl die DKIM- wie auch der SPF-Überprüfung negativ ausfällt. |
ri | 86400 | Der Domaininhaber wünscht, dass die aufbereiteten Statistik- und Forensikdaten spätestens alle 86400 Sekunden verschickt werden sollen (86400 Sekunden = 1 Tag) |
sp | none | Beschreibt, wie der Empfänger die Nachrichten des Domain-Inhabers einer Subdomäne verwerten soll. Der Parameter beschreibt nur die abgefragte Subdomäne, nicht die Domäne an sich! Mögliche Werte sind: none : Der Domaininhaber hat keine Vorgaben zur Verabeitung/Zustellung der e-Mails gemacht. quarantine : Der Domaininhaber wünscht, dass e-Mails, als verdächtig gewertet werden sollen. Abhängig vom Empfänger können diese als verdächtig markiert werden, mit weiteren/zusätzlichen SPAM Prüfungen zu belegen ist, oder in einen SPAM-Ordner verschoben werden soll. reject : Der Domaininhaber wünscht, dass e-Mails abgewiesen, also nicht angenommen werden sollen. Dies sollte, wenn möglich, noch während des SMTP-Dialogs passieren. |
Dieser so erstelle Inhalt des TXT-RECORD zur DMARC-Überprüfung, muss nun im DNS veröffentlicht werden und zwar unter nachfolgendem Eintrag-Schema im DNS:
_dmarc.<DOMAIN>.<TLD>
Nachfolgend würde ein Eintrag für die Domäne tachtler.net
, wie folgt aussehen:
# dig _dmarc.tachtler.net TX ; <<>> DiG 9.9.4-RedHat-9.9.4-18.el7_1.5 <<>> _dmarc.tachtler.net TXT ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1217 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;_dmarc.tachtler.net. IN TXT ;; ANSWER SECTION: _dmarc.tachtler.net. 3591 IN TXT "v=DMARC1\; p=none\; rua=mailto:dmarc-aggregate@tachtler.net\; ruf=mailto:dmarc-incorrect@tachtler.net\; fo=0\; adkim=r\; aspf=r\; pct=100\; rf=afrf\; ri=86400\; sp=none" ;; Query time: 3 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Thu Oct 22 14:20:04 2015 ;; MSG SIZE rcvd: 208
WICHTIG - Als absendende Domains für die DMARC-Reports an andere, sollte ein SUB-Domain verwendet werden, welche selbst keine
rua
ruf
Einträge besitzt, um so tägliche DMARC Ping-Pong Schleifen (loops) zu vermeiden.
v=DMARC1; p=none; fo=0; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400; sp=none
Dieser so erstelle Inhalt des TXT-RECORD zur DMARC-Überprüfung, muss nun im DNS veröffentlicht werden und zwar unter nachfolgendem Eintrag-Schema im DNS:
_dmarc.<SUB>.<DOMAIN>.<TLD>
# dig _dmarc.dmarcreports.tachtler.net TXT ; <<>> DiG 9.9.4-RedHat-9.9.4-38.el7_3.3 <<>> @127.0.0.1 _dmarc.dmarcreports.tachtler.net TXT ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14708 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;_dmarc.dmarcreports.tachtler.net. IN TXT ;; ANSWER SECTION: _dmarc.dmarcreports.tachtler.net. 10800 IN TXT "v=DMARC1\; p=none\; fo=0\; adkim=r\; aspf=r\; pct=100\; rf=afrf\; ri=86400\; sp=none" ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Mon May 01 09:43:27 CEST 2017 ;; MSG SIZE rcvd: 189
* Mein Dank für die Hinweise geht an Juri Haberland
Konfiguration: OpenDMARC
/etc/sysconfig/opendmarc
Nachfolgende Konfigurationsdatei von OpenDMARC setzt Standardparameter für den Start des OpenDMARC Dienst/Daemons.
HINWEIS - Änderungen an dieser Konfigurationsdatei sind grundsätzlich nicht erforderlich!
# Set the necessary startup options OPTIONS="-c /etc/opendmarc.conf -P /var/run/opendmarc/opendmarc.pid"
/etc/opendmarc.conf
Standardmäßig wird nach der Installation von OpenDMARC - opendmarc-milter
in nachfolgendem Verzeichnis mit nachfolgendem Namen die Hauptkonfigurationsdatei für den OpenDMARC - opendmarc-milter
hinterlegt:
/etc/opendmarc.conf
Nachfolgende Änderungen sind an der Konfigurationsdatei /etc/opendmarc.conf
durchzuführen:
(Komplette Konfigurationsdatei)
# cat /etc/opendmarc.conf ## ## opendmarc.conf -- configuration file for OpenDMARC filter ## ## Copyright (c) 2012-2015, The Trusted Domain Project. All rights reserved. ## ## AuthservID (string) ## defaults to MTA name ## ## Sets the "authserv-id" to use when generating the Authentication-Results: ## header field after verifying a message. If the string "HOSTNAME" is ## provided, the name of the host running the filter (as returned by the ## gethostname(3) function) will be used. # # Tachtler # default: # AuthservID name AuthservID mx1.tachtler.net ## AuthservIDWithJobID { true | false } ## default "false" ## ## If "true", requests that the authserv-id portion of the added ## Authentication-Results header fields contain the job ID of the message ## being evaluated. # # Tachtler # default: # AuthservIDWithJobID false AuthservIDWithJobID true ## AutoRestart { true | false } ## default "false" ## ## Automatically re-start on failures. Use with caution; if the filter fails ## instantly after it starts, this can cause a tight fork(2) loop. # # AutoRestart false ## AutoRestartCount n ## default 0 ## ## Sets the maximum automatic restart count. After this number of automatic ## restarts, the filter will give up and terminate. A value of 0 implies no ## limit. # # AutoRestartCount 0 ## AutoRestartRate n/t[u] ## default (no limit) ## ## Sets the maximum automatic restart rate. If the filter begins restarting ## faster than the rate defined here, it will give up and terminate. This ## is a string of the form n/t[u] where n is an integer limiting the count ## of restarts in the given interval and t[u] defines the time interval ## through which the rate is calculated; t is an integer and u defines the ## units thus represented ("s" or "S" for seconds, the default; "m" or "M" ## for minutes; "h" or "H" for hours; "d" or "D" for days). For example, a ## value of "10/1h" limits the restarts to 10 in one hour. There is no ## default, meaning restart rate is not limited. # # AutoRestartRate n/t[u] ## Background { true | false } ## default "true" ## ## Causes opendmarc to fork and exits immediately, leaving the service ## running in the background. # # Background true ## BaseDirectory (string) ## default (none) ## ## If set, instructs the filter to change to the specified directory using ## chdir(2) before doing anything else. This means any files referenced ## elsewhere in the configuration file can be specified relative to this ## directory. It's also useful for arranging that any crash dumps will be ## saved to a specific location. # # BaseDirectory /var/run/opendmarc ## ChangeRootDirectory (string) ## default (none) ## ## Requests that the operating system change the effective root directory of ## the process to the one specified here prior to beginning execution. ## chroot(2) requires superuser access. A warning will be generated if ## UserID is not also set. # # ChangeRootDirectory /var/chroot/opendmarc ## CopyFailuresTo (string) ## default (none) ## ## Requests addition of the specified email address to the envelope of ## any message that fails the DMARC evaluation. # # Tachtler # default: # CopyFailuresTo postmaster@localhost CopyFailuresTo postmaster@tachtler.net ## DNSTimeout (integer) ## default 5 ## ## Sets the DNS timeout in seconds. A value of 0 causes an infinite wait. ## (NOT YET IMPLEMENTED) # # DNSTimeout 5 ## EnableCoredumps { true | false } ## default "false" ## ## On systems that have such support, make an explicit request to the kernel ## to dump cores when the filter crashes for some reason. Some modern UNIX ## systems suppress core dumps during crashes for security reasons if the ## user ID has changed during the lifetime of the process. Currently only ## supported on Linux. # # EnableCoreDumps false ## FailureReports { true | false } ## default "false" ## ## Enables generation of failure reports when the DMARC test fails and the ## purported sender of the message has requested such reports. Reports are ## formatted per RFC6591. # # Tachtler # default: # FailureReports false FailureReports true ## FailureReportsBcc (string) ## default (none) ## ## When failure reports are enabled and one is to be generated, always ## send one to the address(es) specified here. If a failure report is ## requested by the domain owner, the address(es) are added in a Bcc: field. ## If no request is made, they address(es) are used in a To: field. There ## is no default. # # Tachtler # default: # FailureReportsBcc postmaster@example.coom FailureReportsBcc postmaster@tachtler.net ## FailureReportsOnNone { true | false } ## default "false" ## ## Supplements the "FailureReports" setting by generating reports for ## domains that advertise "none" policies. By default, reports are only ## generated (when enabled) for sending domains advertising a "quarantine" ## or "reject" policy. # # FailureReportsOnNone false ## FailureReportsSentBy string ## default "USER@HOSTNAME" ## ## Specifies the email address to use in the From: field of failure ## reports generated by the filter. The default is to use the userid of ## the user running the filter and the local hostname to construct an ## email address. "postmaster" is used in place of the userid if a name ## could not be determined. # # Tachtler # default: # FailureReportsSentBy USER@HOSTNAME FailureReportsSentBy postmaster@dmarcreports.tachtler.net ## HistoryFile path ## default (none) ## ## If set, specifies the location of a text file to which records are written ## that can be used to generate DMARC aggregate reports. Records are groups ## of rows containing information about a single received message, and ## include all relevant information needed to generate a DMARC aggregate ## report. It is expected that this will not be used in its raw form, but ## rather periodically imported into a relational database from which the ## aggregate reports can be extracted by a tool such as opendmarc-import(8). # # Tachtler # default: # HistoryFile /var/spool/opendmarc/opendmarc.dat HistoryFile /var/spool/opendmarc/opendmarc.dat ## IgnoreAuthenticatedClients { true | false } ## default "false" ## ## If set, causes mail from authenticated clients (i.e., those that used ## SMTP AUTH) to be ignored by the filter. # # IgnoreAuthenticatedClients false ## IgnoreHosts path ## default (internal) ## ## Specifies the path to a file that contains a list of hostnames, IP ## addresses, and/or CIDR expressions identifying hosts whose SMTP ## connections are to be ignored by the filter. If not specified, defaults ## to "127.0.0.1" only. # # Tachtler # default: # IgnoreHosts /etc/opendmarc/ignore.hosts IgnoreHosts /etc/opendmarc/ignore.hosts ## IgnoreMailFrom domain[,...] ## default (none) ## ## Gives a list of domain names whose mail (based on the From: domain) is to ## be ignored by the filter. The list should be comma-separated. Matching ## against this list is case-insensitive. The default is an empty list, ## meaning no mail is ignored. # # IgnoreMailFrom example.com ## MilterDebug (integer) ## default 0 ## ## Sets the debug level to be requested from the milter library. # # Tachtler # default: # MilterDebug 0 MilterDebug 5 ## PidFile path ## default (none) ## ## Specifies the path to a file that should be created at process start ## containing the process ID. ## # # PidFile /var/run/opendmarc.pid ## PublicSuffixList path ## default (none) ## ## Specifies the path to a file that contains top-level domains (TLDs) that ## will be used to compute the Organizational Domain for a given domain name, ## as described in the DMARC specification. If not provided, the filter will ## not be able to determine the Organizational Domain and only the presented ## domain will be evaluated. # # PublicSuffixList path ## RecordAllMessages { true | false } ## default "false" ## ## If set and "HistoryFile" is in use, all received messages are recorded ## to the history file. If not set (the default), only messages for which ## the From: domain published a DMARC record will be recorded in the ## history file. # # RecordAllMessages false ## RejectFailures { true | false } ## default "false" ## ## If set, messages will be rejected if they fail the DMARC evaluation, or ## temp-failed if evaluation could not be completed. By default, no message ## will be rejected or temp-failed regardless of the outcome of the DMARC ## evaluation of the message. Instead, an Authentication-Results header ## field will be added. # # RejectFailures false ## ReportCommand string ## default "/usr/sbin/sendmail -t" ## ## Indicates the shell command to which failure reports should be passed for ## delivery when "FailureReports" is enabled. # # ReportCommand /usr/sbin/sendmail -t ## RequiredHeaders { true | false } ## default "false" ## ## If set, the filter will ensure the header of the message conforms to the ## basic header field count restrictions laid out in RFC5322, Section 3.6. ## Messages failing this test are rejected without further processing. A ## From: field from which no domain name could be extracted will also be ## rejected. # # RequiredHeaders false ## Socket socketspec ## default (none) ## ## Specifies the socket that should be established by the filter to receive ## connections from sendmail(8) in order to provide service. socketspec is ## in one of two forms: local:path, which creates a UNIX domain socket at ## the specified path, or inet:port[@host] or inet6:port[@host] which creates ## a TCP socket on the specified port for the appropriate protocol family. ## If the host is not given as either a hostname or an IP address, the ## socket will be listening on all interfaces. This option is mandatory ## either in the configuration file or on the command line. If an IP ## address is used, it must be enclosed in square brackets. # # Tachtler # default: Socket inet:8893@localhost Socket inet:10013@192.168.0.70 ## SoftwareHeader { true | false } ## default "false" ## ## Causes the filter to add a "DMARC-Filter" header field indicating the ## presence of this filter in the path of the message from injection to ## delivery. The product's name, version, and the job ID are included in ## the header field's contents. # SoftwareHeader true ## SPFIgnoreResults { true | false } ## default "false" ## ## Causes the filter to ignore any SPF results in the header of the ## message. This is useful if you want the filter to perfrom SPF checks ## itself, or because you don't trust the arriving header. # # Tachtler # default: SPFIgnoreResults true SPFIgnoreResults false ## SPFSelfValidate { true | false } ## default false ## ## Enable internal spf checking with --with-spf ## To use libspf2 instead: --with-spf --with-spf2-include=path --with-spf2-lib=path ## ## Causes the filter to perform a fallback SPF check itself when ## it can find no SPF results in the message header. If SPFIgnoreResults ## is also set, it never looks for SPF results in headers and ## always performs the SPF check itself when this is set. # # Tachtler # default: SPFSelfValidate true SPFSelfValidate false ## Syslog { true | false } ## default "false" ## ## Log via calls to syslog(3) any interesting activity. # Syslog true ## SyslogFacility facility-name ## default "mail" ## ## Log via calls to syslog(3) using the named facility. The facility names ## are the same as the ones allowed in syslog.conf(5). # # SyslogFacility mail ## TrustedAuthservIDs string ## default HOSTNAME ## ## Specifies one or more "authserv-id" values to trust as relaying true ## upstream DKIM and SPF results. The default is to use the name of ## the MTA processing the message. To specify a list, separate each entry ## with a comma. The key word "HOSTNAME" will be replaced by the name of ## the host running the filter as reported by the gethostname(3) function. # # TrustedAuthservIDs HOSTNAME ## UMask mask ## default (none) ## ## Requests a specific permissions mask to be used for file creation. This ## only really applies to creation of the socket when Socket specifies a ## UNIX domain socket, and to the HistoryFile and PidFile (if any); temporary ## files are normally created by the mkstemp(3) function that enforces a ## specific file mode on creation regardless of the process umask. See ## umask(2) for more information. # UMask 007 ## UserID user[:group] ## default (none) ## ## Attempts to become the specified userid before starting operations. ## The process will be assigned all of the groups and primary group ID of ## the named userid unless an alternate group is specified. # UserID opendmarc:mail
Nachfolgende Änderungen sollten vorgenommen werden:
AuthservID mx1.tachtler.net
Explizites setzen des HOST-Namen, welcher bei Einträgen durch OpenDMARC verwendet werden soll. Standardmäßig würde hier der FQDN des Servers verwendet werden, auf dem der OpenDMARC ausgeführt wird.
AuthservIDWithJobID true
Die „Authserv-ID“ soll in den e-Mail-Header bei der Eintragung des Authentikations-Ergebnisses durchgeführt werden. Es wird die ID der e-Mail verwendet.
CopyFailuresTo postmaster@tachtler.net
Sendet eine Kopie der e-Mail an die angegeben e-Mail-Adresse, wenn eine DMARC-Überprüfung fehlgeschlagenen ist.
FailureReports true
Es soll eine Fehlerreport erstellt werden, falls die DMARC-Fehlerüberprüfung fehl schlägt und der Absender der e-Mail solch einen Report angefordert hat. Die Reports werden im so formatiert, wie dies im RFC6591 festgelegt wurde.
FailureReportsBcc postmaster@tachtler.net
Falls die Erstellung von Fehlerreports durchgeführt wird und ein Fehlerreport erstellt wird, soll an nachfolgende e-Mailadresse eine Blindkopie dieses Fehlerreports gesendet werden, wenn der Absender einen solchen Report angefordert hat. Falls der Absender keinen Report angefordert hat, wird eine e-Mail an die angegebene Adresse als Empfänger gesendet.
FailureReportsSentBy postmaster@dmarcreports.tachtler.net
Absender e-Mail-Adresse des Reports der per e-Mail an den Absender geht, bei dem die DMARC-Überprüfung fehlgeschlagen ist und der Absender einen solchen Report angefordert hat.
Es sollte eine SUB-Domain verwendet werden, da sonst die DMARC-Reports und -Failure-Messages von der Haupt-Domain verschickt werden, generiert jeder Report bei den Empfängern einen Report zurück. Das ist an sich nicht schlimm, aber generiert unter Umständen sinnlos Reports die nur sich selber als Report in sich tragen. Deshalb sollten die DMARC-Reports und -Failure-Messages von einer Subdomain aus zu verschickt werden, die eine eigenen DMARC-Record ohne rua- und ruf-Tags hat.
HistoryFile /var/spool/opendmarc/opendmarc.dat
Falls hier die Angabe einer Datei ggf. mit Pfadangabe durchgeführt wird, wird eine Textdatei erstellt, deren Inhalt ein DMARC Summenreport ist. Diese Datei kann dann mit dem opendmarc-import
Programm extrahiert werden und in eine Datenbank geschrieben werden um daraus später weitere Reports erstellen zu können.
IgnoreHosts /etc/opendmarc/ignore.hosts
Bezeichnet den Pfad zu einer Datei, welche als Inhalt HOST-Namen, IP-Adressen oder auch Netzwerk-Angaben beinhaltet, welche von der DMARC-Überprüfung ausgeschlossen werden sollen. Falls keine Angaben hier erfolgt, wird Standardmäßig nur die IP-Adresse: 127.0.0.1 ausgeschlossen.
HINWEIS - Diese Datei sollte für später vorbereitet werden, um ggf. Ausschlüsse von der Prüfung durchführen zu können!
MilterDebug 5
Setzen des Levels der Informationsausgabe, welche in das LOG geschrieben werden.
Socket inet:10013@192.168.0.70
Setzen des Sockets bzw. der IP-Adresse und des Ports, über den der MILTER angesprochen werden kann.
SPFIgnoreResults false
Die DMARC-Überprüfung von bereits vorhandenen e-Mail-Header Einträgen zur SPF-Überprüfung sollen nicht ignoriert werden, da diese bereits im Vorfeld in diesem Beispiel durch den SPF-MILTER gesetzt wurden. Hier könnte auch eine SPF-Überprüfung durch den DMARC-MILTER durchgeführt werden, was jedoch aus Stabilitätsgründen hier nicht erfolgen soll.
SPFSelfValidate false
Deaktiviert die SPF-Überprüfung, welche auch durch den DMARC-MILTER durchgeführt werden kann, wenn nicht bereits im e-Mail-Header SPF-Überprüfungsinformationen enhalten sind, was jedoch aus Stabilitätsgründen hier nicht erfolgen soll.
/etc/opendmarc/ignore.hosts
Nachfolgende Konfigurationsdatei in nachfolgendem Verzeichnis mit ebenfalls nachfolgendem Namen:
/etc/opendmarc/ignore.hosts
beinhaltet HOST-Namen, IP-Adressen oder ganze Netze, für die keine DMARC-Überprüfung durchgeführt werden soll.
Bevor die Angaben zu den HOST-Namen, IP-Adressen oder ganze Netze, für die keine DMARC-Überprüfung durchgeführt werden soll gemacht werden können, muss die Konfigurationsdatei mit nachfolgendem Befehl angelegt werden:
# touch /etc/opendmarc/ignore.hosts
Nachfolgende Einstellungen sind an der Konfigurationsdatei /etc/opendkim/TrustedHosts
durchzuführen:
(Komplette Konfigurationsdatei)
## File that contains a list of hostnames, IP addresses, and/or CIDR expressions ## identifying hosts whose SMTP connections are to be ignored by the filter. 127.0.0.1
OpenDMARC Dienst/Daemon-Start einrichten
Um den OpenDMARC der als Dienst/Deamon als Hintergrundprozess läuft, auch nach einem Neustart des Servers zur Verfügung zu haben, soll der Dienst/Daemon mit dem Server mit gestartet werden, was mit nachfolgendem Befehl realisiert werden kann:
# systemctl enable opendmarc ln -s '/usr/lib/systemd/system/opendmarc.service' '/etc/systemd/system/multi-user.target.wants/opendmarc.service'
Eine Überprüfung, ob beim Neustart des Server der opendmarc
-Dienst/Deamon wirklich mit gestartet wird, kann mit nachfolgendem Befehl erfolgen und sollte eine Anzeige, wie ebenfalls nachfolgend dargestellt ausgeben:
# systemctl list-unit-files --type=service | grep -e opendmarc opendmarc.service enabled
bzw.
# systemctl is-enabled opendmarc enabled
Erster Start OpenDMARC
Um den OpenDMARC zu starten kann nachfolgender Befehl angewandt werden:
# systemctl start opendmarc
Eine Überprüfung ob der Start des OpenDMARC erfolgreich war kann mit nachfolgendem Befehl durchgeführt werden, welcher eine Ausgabe in etwa wie nachfolgende erzeugen sollte:
# systemctl status opendmarc opendmarc.service - Domain-based Message Authentication, Reporting & Conformance (DMARC) Milter Loaded: loaded (/usr/lib/systemd/system/opendmarc.service; enabled) Active: active (running) since Thu 2015-10-22 09:23:26 CEST; 4s ago Docs: man:opendmarc(8) man:opendmarc.conf(5) man:opendmarc-import(8) man:opendmarc-reports(8) http://www.trusteddomain.org/opendmarc/ Process: 2481 ExecStart=/usr/sbin/opendmarc $OPTIONS (code=exited, status=0/SUCCESS) Main PID: 2482 (opendmarc) CGroup: /system.slice/opendmarc.service └─2482 /usr/sbin/opendmarc -c /etc/opendmarc.conf -P /var/run/open... Oct 22 09:23:26 server70.idmz.tachtler.net systemd[1]: Starting Domain-based ... Oct 22 09:23:26 server70.idmz.tachtler.net opendmarc[2482]: OpenDMARC Filter ... Oct 22 09:23:26 server70.idmz.tachtler.net opendmarc[2482]: additional truste... Oct 22 09:23:26 server70.idmz.tachtler.net systemd[1]: Started Domain-based M... Hint: Some lines were ellipsized, use -l to show in full.
bzw. mit nachfolgendem Befehl, ob der Dienst/Daemon in der Prozessliste erscheint:
# ps aux | grep opendmarc opendma+ 2482 0.0 0.0 39884 712 ? Ssl 09:23 0:00 /usr/sbin/opendmarc -c /etc/opendmarc.conf -P /var/run/opendmarc/opendmarc.pid root 2487 0.0 0.0 112640 928 pts/0 S+ 09:24 0:00 grep --color=auto opendmarc
Eine weitere Möglichkeit ist die Überprüfung des journal
, was mit nachfolgendem Befehl durchgeführt werden kann:
Oct 22 09:23:26 server70.idmz.tachtler.net systemd[1]: Starting Domain-based Mes -- Subject: Unit opendmarc.service has begun with start-up -- Defined-By: systemd -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel -- -- Unit opendmarc.service has begun starting up. Oct 22 09:23:26 server70.idmz.tachtler.net opendmarc[2481]: OpenDMARC Filter: Op Oct 22 09:23:26 server70.idmz.tachtler.net opendmarc[2482]: OpenDMARC Filter v1. Oct 22 09:23:26 server70.idmz.tachtler.net opendmarc[2482]: additional trusted a Oct 22 09:23:26 server70.idmz.tachtler.net systemd[1]: Started Domain-based Mess -- Subject: Unit opendmarc.service has finished start-up -- Defined-By: systemd -- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel -- -- Unit opendmarc.service has finished starting up. -- -- The start-up result is done.
Konfiguration: opendmarc-milter
Nachfolgende Änderungen werden an den Konfigurationsdateien
/etc/postfix/main.cf
/etc/postfix/master.cf
durchgeführt, um eine Anbindung des Postfix an den OpenDMARC zu realisieren.
Dabei soll die Anbindung von Postfix an den OpenDMARC mit dem Verfahren
opendmarc-milter
erfolgen.
/etc/postfix/main.cf
Hier die Änderungen an der Konfigurationsdatei /etc/postfix/main.cf
(Nur relevanter Ausschnitt):
... # OpenDMARC (opendmarc-milter) opendmarc_milter = inet:192.168.0.70:10013 ...
/etc/postfix/master.cf
Hier die Änderungen an der Konfigurationsdatei /etc/postfix/master.cf
(Nur relevanter Ausschnitt):
# # Postfix master process configuration file. For details on the format # of the file, see the master(5) manual page (command: "man 5 master" or # on-line: http://www.postfix.org/master.5.html). # # Do not forget to execute "postfix reload" after editing this file. # # ========================================================================== # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== # Tachtler - disabled - #smtp inet n - n - - smtpd # Tachtler - new - # Incoming traffic from untrust networks, with postscreen. 192.168.1.60:2525 inet n - n - 1 postscreen # Tachtler - enabled - # Incoming traffic passed from untrust networks, with postscreen. smtpd pass - - n - - smtpd -o smtpd_milters=${opendmarc_milter} ...
Nachfolgend Erklärungen zu den WICHTIGSTEN Konfigurationen:
-o smtpd_milters=${opendmarc_milter}
Die Option sorgt dafür, dass dem Parameter smtpd_milter
der Inhalt des Parameters opendmarc_milter
übergeben wird. Falls mehrere MILTER zum Einsatz kommen, wird hier die Reihenfolge festgelegt, in der diese aufgerufen werden!
Neustart
Falls vorstehende Änderungen (natürlich an die jeweiligen Bedürfnisse angepasst) durchgeführt wurden, muss ein Neustart von Postfix durchgeführt werden.
Danach kann der postfix-Server mit nachfolgendem Befehle neu gestartet werden:
# systemctl restart postfix
Mit nachfolgendem Befehl kann der Status des abgefragt werden:
# systemctl status postfix postfix.service - Postfix Mail Transport Agent Loaded: loaded (/usr/lib/systemd/system/postfix.service; enabled) Active: active (running) since Thu 2015-10-15 11:11:26 CEST; 7s ago Process: 1128 ExecStop=/usr/sbin/postfix stop (code=exited, status=0/SUCCESS) Process: 1144 ExecStart=/usr/sbin/postfix start (code=exited, status=0/SUCCESS) Process: 1141 ExecStartPre=/usr/libexec/postfix/chroot-update (code=exited, status=0/SUCCESS) Process: 1138 ExecStartPre=/usr/libexec/postfix/aliasesdb (code=exited, status=0/SUCCESS) Main PID: 1216 (master) CGroup: /system.slice/postfix.service ├─1216 /usr/libexec/postfix/master -w ├─1217 pickup -l -t unix -u -o content_filter=lmtp:[192.168.0.70]... └─1218 qmgr -l -t unix -u Oct 15 11:11:26 server60.idmz.tachtler.net systemd[1]: Starting Postfix Mail... Oct 15 11:11:26 server60.idmz.tachtler.net postfix/postfix-script[1214]: sta... Oct 15 11:11:26 server60.idmz.tachtler.net postfix/master[1216]: daemon star... Oct 15 11:11:26 server60.idmz.tachtler.net systemd[1]: Started Postfix Mail ... Hint: Some lines were ellipsized, use -l to show in full.
Test
Nachfolgend soll ein Test darin bestehen, dass eine e-Mail von einem externen Server an Postfix gesendet wird, und dieser dann die DKIM-Signatur des absendenden e-Mail-Servers prüft.
Wichtig sind zwei Einträge, in
- den Header-Zeilen der eingehenden e-Mail
- die LOG-Einträge im Server, auf dem OpenDMARC -
opendmarc-milter
läuft:
Überprüfung: Header-Zeilen
Nachfolgender Eintrag sollte in den Header-Zeilen einer eingehenden e-Mail zu finden sein, um das Ergebnis der OpenDMARC - opendmarc-milter
Überprüfung zu zeigen:
DMARC-Filter: OpenDMARC Filter v1.4.1 mx1.tachtler.net EDCFE1800089 Authentication-Results: mx1.tachtler.net/EDCFE1800089; dmarc=pass header.from=nausch.org
* Das Ergbenis kann hier pass
, fail
und none
sein.
Überprüfung: /var/log/maillog
Nachfolgender Eintrag sollte in den LOG-Einträgen des Servers auf dem der OpenDMARC - opendmarc-milter
läuft bei einer eingehenden e-Mail zu finden sein, um das Ergebnis der OpenDMARC - opendmarc-milter
Überprüfung zu dokumentieren:
Oct 22 09:39:23 server70 opendmarc[2482]: implicit authentication service: mx1.tachtler.net Oct 22 09:39:23 server70 opendmarc[2482]: EDCFE1800089: nausch.org pass
Konfiguration: Reports ausgehend
Um Reports erstellen zu können, welche durch einliefernde e-Mail-Server im Rahmen von OpenDMARC angefordert werden, ist es vorgesehen, dass die Daten zuerst von OpenDMARC in eine Datei geschrieben werden, welche sich in nachfolgendem Verzeichnis mit nachfolgendem Namen befindet.
/var/spool/opendmarc/opendmarc.dat
Die in der oben genannten Datei befindlichen Daten müssen allerdings zuerst in eine Datenbank geschrieben werden, um daraus dann die gewünschten Reports erstellen zu können und anschließend auch versenden zu können. Nicht zu vergessen ist hierbei auch, das aus der Datenbank auch wieder entsprechend nach einer gewissen Zeit, ältere Daten gelöscht werden, damit diese nicht überlaufen kann.
Nachfolgende Konfiguration ist erforderlich, damit Daten durch das Skript in nachfolgendem Verzeichnis mit nachfolgendem Namen
/usr/sbin/opendmarc-import
in die Datenbank geschrieben werden können. Dazu ist die entsprechende Datenbank und die benötigten Tabellen und Felder anzulegen.
Dies kann durch ein, ebenfalls im rpm
-Paket mitgeliefertes Skript, welches in nachfolgendem Verzeichnis mit nachfolgendem Namen zu finden ist:
/usr/share/opendmarc/db/schema.mysql
durchgeführt werden.
HINWEIS - Falls von einem HOST anstelle von localhost
Daten in die Datenbank geschrieben werden sollen, muss das Skript entsprechend erweitert bzw. angepasst werden!
/usr/share/opendmarc/db/schema.mysql
HINWEIS - Nachfolgend sollen vom HOST mit der IP-Adresse 192.168.0.70
die Daten in die Datenbank geschrieben werden und nicht von localhost
wie dies standardmäßig der Fall ist!
Die erforderlichen Anpassungen, befinden sich am Ende des Skripts, welches sonst nicht angepasst werden sollte!
-- OpenDMARC database schema -- -- Copyright (c) 2012, 2016, 2018, 2021, The Trusted Domain Project. -- All rights reserved. CREATE DATABASE IF NOT EXISTS opendmarc; USE opendmarc; -- A table for mapping domain names and their DMARC policies to IDs CREATE TABLE IF NOT EXISTS domains ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, firstseen TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), UNIQUE KEY(name) ); -- A table for logging encountered ARC selectors CREATE TABLE IF NOT EXISTS selectors ( id INT NOT NULL AUTO_INCREMENT, domain INT NOT NULL, name VARCHAR(255) NOT NULL, firstseen TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), KEY(name), UNIQUE KEY(name, domain) ); -- A table for logging ARC-Authentication-Results information CREATE TABLE IF NOT EXISTS arcauthresults ( id INT NOT NULL AUTO_INCREMENT, message INT UNSIGNED NOT NULL, instance INT UNSIGNED NOT NULL, arc_client_addr VARCHAR(64) NOT NULL DEFAULT '', PRIMARY KEY(id), KEY(message), UNIQUE KEY(message, instance) ); -- A table for logging ARC-Seal information CREATE TABLE IF NOT EXISTS arcseals ( id INT NOT NULL AUTO_INCREMENT, message INT UNSIGNED NOT NULL, domain INT UNSIGNED NOT NULL, selector INT UNSIGNED NOT NULL, instance INT UNSIGNED NOT NULL, firstseen TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), KEY(message), UNIQUE KEY(message, domain, selector, instance) ); -- A table for logging reporting requests CREATE TABLE IF NOT EXISTS requests ( id INT NOT NULL AUTO_INCREMENT, domain INT NOT NULL, repuri VARCHAR(255) NOT NULL DEFAULT '', adkim TINYINT NOT NULL DEFAULT '0', aspf TINYINT NOT NULL DEFAULT '0', policy TINYINT NOT NULL DEFAULT '0', spolicy TINYINT NOT NULL DEFAULT '0', pct TINYINT NOT NULL DEFAULT '0', locked TINYINT NOT NULL DEFAULT '0', firstseen TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, lastsent TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY(id), KEY(lastsent), UNIQUE KEY(domain) ); -- A table for reporting hosts CREATE TABLE IF NOT EXISTS reporters ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, firstseen TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), UNIQUE KEY(name) ); -- A table for connecting client IP addresses CREATE TABLE IF NOT EXISTS ipaddr ( id INT NOT NULL AUTO_INCREMENT, addr VARCHAR(64) NOT NULL, firstseen TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), UNIQUE KEY(addr) ); -- A table for messages CREATE TABLE IF NOT EXISTS messages ( id INT NOT NULL AUTO_INCREMENT, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, jobid VARCHAR(128) NOT NULL, reporter INT UNSIGNED NOT NULL, policy TINYINT UNSIGNED NOT NULL, disp TINYINT UNSIGNED NOT NULL, ip INT UNSIGNED NOT NULL, env_domain INT UNSIGNED NOT NULL, from_domain INT UNSIGNED NOT NULL, policy_domain INT UNSIGNED NOT NULL, spf TINYINT NOT NULL, align_dkim TINYINT UNSIGNED NOT NULL, align_spf TINYINT UNSIGNED NOT NULL, sigcount TINYINT UNSIGNED NOT NULL, arc TINYINT UNSIGNED NOT NULL, arc_policy TINYINT UNSIGNED NOT NULL, PRIMARY KEY(id), KEY(date), UNIQUE KEY(reporter, date, jobid) ); -- A table for signatures CREATE TABLE IF NOT EXISTS signatures ( id INT NOT NULL AUTO_INCREMENT, message INT UNSIGNED NOT NULL, domain INT UNSIGNED NOT NULL, selector INT UNSIGNED NOT NULL, pass TINYINT UNSIGNED NOT NULL, error TINYINT UNSIGNED NOT NULL, PRIMARY KEY(id), KEY(message) ); -- CREATE USER 'opendmarc'@'localhost' IDENTIFIED BY 'changeme'; -- GRANT ALL ON opendmarc.* to 'opendmarc'@'localhost'; -- # Tachtler - Grant ALL privileges to new users. GRANT ALL PRIVILEGES ON *.* TO 'opendmarc_user'@'192.168.0.70' IDENTIFIED BY 'password' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'opendmarc_user'@'server70.idmz.tachtler.net' IDENTIFIED BY 'password' WITH GRANT OPTION; -- # Tachtler - Make sure that priviliges are reloaded. FLUSH PRIVILEGES;
Nachfolgende Änderungen wurden am Skript durchgeführt:
Austausch des TIMESTAMP
von '1970-01-01 00:00:00
' zu '0000-00-00 00:00:00
', da es sonst zu einer Fehlermeldung kommt, das '1970-01-01 00:00:00
' kein gültiger DEFAULT
-Wert ist.
Erstellen von zwei neuen Benutzer, opendmarc_user'@'192.168.0.70
und opendmarc_user'@'server70.idmz.tachtler.net
, welche via IP-Adresse oder FQDN vom Server 192.168.0.70
bzw. server70.idmz.tachtler.net
agieren dürfen und ein Passwort besitzen
Den beiden Benutzern opendmarc_user'@'192.168.0.70
und opendmarc_user'@'server70.idmz.tachtler.net
werden alle Privilegien in auf die Datenbank opendmarc
gewährt.
-- # Tachtler - Make sure that priviliges are reloaded. FLUSH PRIVILEGES;
Die Benutzerrechte, inklusive der neu angelegten Benutzer mit den entsprechenden Rechten, sollen aktiviert werden, in dem die Rechte neu eingelesen werden sollen.
Die Ausführung des Skriptes und die damit verbunden Anlage der Datenbank, der Tabellen und Felder und der Nutzer, kann durch Ausführung des nachfolgenden Befehls durchgeführt werden, zudem jedoch das Kennwort zum Datenbankbenutzer root
erforderlich ist!:
# /usr/bin/mysql -u root -p < /usr/share/opendmarc/db/schema.mysql Enter password:
/etc/opendmarc/opendmarc_report_out.sh
Nachfolgend soll ein Skript erstellt werden, welches alle drei nachfolgende Aufgaben durchführen soll:
- Übernahme der Daten aus der Konfigurationsdatei
/var/run/opendmarc/opendmarc.dat
in die Datenbank - Erstellen und versenden der Reports, zu den externen e-Mail-Servern, auf dessen Anforderung hin
- Aufräumen der Datenbank und löschen der älteren Datensätze um einem Überlauf der Datenbank vorzubeugen
#!/bin/bash ############################################################################## # Script-Name : opendmarc_report_out.sh # # Description : Add opendmarc report data from file # # - /var/spool/opendmarc/opendmarc.dat # # to a Database. Generate and sent reports to recipients who # # request a report. Delete old data from Database to protect # # the Database from overflow. # # # # # Last update : 23.10.2015 # # Version : 1.00 # ############################################################################## ############################################################################## # H I S T O R Y # ############################################################################## # Version : x.xx # # Description : <Description> # # -------------------------------------------------------------------------- # # Version : x.xx # # Description : <Description> # # -------------------------------------------------------------------------- # ############################################################################## # Source function library. . /etc/init.d/functions # Variable declarations. ############################################################################## # >>> Please edit following lines for personal command and/or configuration! # ############################################################################## # CUSTOM - Script-Name. SCRIPT_NAME='opendmarc_report_out.sh' # CUSTOM - Variables. FILE_OPENDMARC_DAT='/var/spool/opendmarc/opendmarc.dat' FILE_OPENDMARC_USER='opendmarc' FILE_OPENDMARC_PERMISSION='660' REPORT_INTERVAL='86400' REPORT_SENDER='postmaster@dmarcreports.tachtler.net' REPORT_ORG='tachtler.net' REPORT_EXPIRE='90' # CUSTOM - Database. DB_HOST='mariadb.idmz.tachtler.net' DB_PORT='3306' DB_NAME='opendmarc' DB_USER='opendmarc_user' DB_PSWD='geheim' # CUSTOM - Mail-Recipient. MAIL_RECIPIENT='you@example.com' # CUSTOM - Status-Mail [Y|N]. MAIL_STATUS='N' ############################################################################## # >>> Normaly there is no need to change anything below this comment line. ! # ############################################################################## # Binarys. BIN_OPENDMARC_IMPORT=`command -v opendmarc-import` BIN_OPENDMARC_REPORTS=`command -v opendmarc-reports` BIN_OPENDMARC_EXPIRE=`command -v opendmarc-expire` # Variables. TOUCH_COMMAND=`command -v touch` RM_COMMAND=`command -v rm` CAT_COMMAND=`command -v cat` DATE_COMMAND=`command -v date` PROG_SENDMAIL=`command -v sendmail` CHOWN_COMMAND=`command -v chown` CHMOD_COMMAND=`command -v chmod` FILE_LOCK='/tmp/'$SCRIPT_NAME'.lock' FILE_LOG='/var/log/'$SCRIPT_NAME'.log' FILE_LAST_LOG='/tmp/'$SCRIPT_NAME'.log' FILE_MAIL='/tmp/'$SCRIPT_NAME'.mail' VAR_HOSTNAME=`uname -n` VAR_SENDER='root@'$VAR_HOSTNAME VAR_EMAILDATE=`$DATE_COMMAND '+%a, %d %b %Y %H:%M:%S (%Z)'` # Functions. function log() { echo $1 echo `$DATE_COMMAND '+%Y/%m/%d %H:%M:%S'` " INFO:" $1 >>${FILE_LAST_LOG} } function retval() { if [ "$?" != "0" ]; then case "$?" in *) log "ERROR: Unknown error $?" ;; esac fi } function movelog() { $CAT_COMMAND $FILE_LAST_LOG >> $FILE_LOG $RM_COMMAND -f $FILE_LAST_LOG $RM_COMMAND -f $FILE_LOCK } function sendmail() { case "$1" in 'STATUS') MAIL_SUBJECT='Status execution '$SCRIPT_NAME' script.' ;; *) MAIL_SUBJECT='ERROR while execution '$SCRIPT_NAME' script !!!' ;; esac $CAT_COMMAND <<MAIL >$FILE_MAIL Subject: $MAIL_SUBJECT Date: $VAR_EMAILDATE From: $VAR_SENDER To: $MAIL_RECIPIENT MAIL $CAT_COMMAND $FILE_LAST_LOG >> $FILE_MAIL $PROG_SENDMAIL -f $VAR_SENDER -t $MAIL_RECIPIENT < $FILE_MAIL $RM_COMMAND -f $FILE_MAIL } # Main. log "" log "+-----------------------------------------------------------------+" log "| Start processing opendmarc database jobs and e-Mail-report gen. |" log "+-----------------------------------------------------------------+" log "" log "Run script with following parameter:" log "" log "SCRIPT_NAME...........: $SCRIPT_NAME" log "" log "MAIL_RECIPIENT........: $MAIL_RECIPIENT" log "MAIL_STATUS...........: $MAIL_STATUS" log "" log "FILE_OPENDMARC_DAT....: $FILE_OPENDMARC_DAT" log "" log "" # Check if command (file) NOT exist OR IS empty. if [ ! -s "$TOUCH_COMMAND" ]; then log "Check if command '$TOUCH_COMMAND' was found....................[FAILED]" sendmail ERROR movelog exit 10 else log "Check if command '$TOUCH_COMMAND' was found....................[ OK ]" fi # Check if command (file) NOT exist OR IS empty. if [ ! -s "$RM_COMMAND" ]; then log "Check if command '$RM_COMMAND' was found.......................[FAILED]" sendmail ERROR movelog exit 11 else log "Check if command '$RM_COMMAND' was found.......................[ OK ]" fi # Check if command (file) NOT exist OR IS empty. if [ ! -s "$CAT_COMMAND" ]; then log "Check if command '$CAT_COMMAND' was found......................[FAILED]" sendmail ERROR movelog exit 12 else log "Check if command '$CAT_COMMAND' was found......................[ OK ]" fi # Check if command (file) NOT exist OR IS empty. if [ ! -s "$DATE_COMMAND" ]; then log "Check if command '$DATE_COMMAND' was found.....................[FAILED]" sendmail ERROR movelog exit 13 else log "Check if command '$DATE_COMMAND' was found.....................[ OK ]" fi # Check if command (file) NOT exist OR IS empty. if [ ! -s "$PROG_SENDMAIL" ]; then log "Check if command '$PROG_SENDMAIL' was found................[FAILED]" sendmail ERROR movelog exit 14 else log "Check if command '$PROG_SENDMAIL' was found................[ OK ]" fi # Check if command (file) NOT exist OR IS empty. if [ ! -s "$CHOWN_COMMAND" ]; then log "Check if command '$CHOWN_COMMAND' was found....................[FAILED]" sendmail ERROR movelog exit 15 else log "Check if command '$CHOWN_COMMAND' was found....................[ OK ]" fi # Check if command (file) NOT exist OR IS empty. if [ ! -s "$CHMOD_COMMAND" ]; then log "Check if command '$CHMOD_COMMAND' was found....................[FAILED]" sendmail ERROR movelog exit 16 else log "Check if command '$CHMOD_COMMAND' was found....................[ OK ]" fi # Check if LOCK file NOT exist. if [ ! -e "$FILE_LOCK" ]; then log "Check if script is NOT already runnig .....................[ OK ]" $TOUCH_COMMAND $FILE_LOCK else log "Check if script is NOT already runnig .....................[FAILED]" log "" log "ERROR: The script was already running, or LOCK file already exists!" log "" sendmail ERROR movelog exit 20 fi # Check if NOT exist. if [ ! -e "$FILE_OPENDMARC_DAT" ]; then log "Check if $FILE_OPENDMARC_DAT exists ........[FAILED]" log "" log "INFO : The file $FILE_OPENDMARC_DAT does NOT exists!!!" log "INFO : Nothing to do." log "INFO : Exit script." log "" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 50 else log "Check if $FILE_OPENDMARC_DAT exists ........[ OK ]" fi # Start process. log "" log "+-----------------------------------------------------------------+" log "| Run process from $SCRIPT_NAME ...................... |" log "+-----------------------------------------------------------------+" log "" # Import DMARC data into the database from file. $BIN_OPENDMARC_IMPORT --dbhost=$DB_HOST --dbport=$DB_PORT --dbname=$DB_NAME --dbuser=$DB_USER --dbpasswd=$DB_PSWD --verbose < $FILE_OPENDMARC_DAT if [ "$?" != 0 ]; then retval $? log "Import DMARC data into the database from file .............[FAILED]" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 51 else log "Import DMARC data into the database from file .............[ OK ]" fi log "" # Generate reports and sent them. $BIN_OPENDMARC_REPORTS --dbhost=$DB_HOST --dbport=$DB_PORT --dbname=$DB_NAME --dbuser=$DB_USER --dbpasswd=$DB_PSWD --verbose --interval=$REPORT_INTERVAL --report-email=$REPORT_SENDER --report-org=$REPORT_ORG if [ "$?" != 0 ]; then retval $? log "Generate reports and sent them ............................[FAILED]" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 52 else log "Generate reports and sent them ............................[ OK ]" fi log "" # Clean the database. $BIN_OPENDMARC_EXPIRE --alltables --dbhost=$DB_HOST --dbport=$DB_PORT --dbname=$DB_NAME --dbuser=$DB_USER --dbpasswd=$DB_PSWD --verbose --expire=$REPORT_EXPIRE if [ "$?" != 0 ]; then retval $? log "Clean the database ........................................[FAILED]" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 53 else log "Clean the database ........................................[ OK ]" fi log "" # Remove OpenDMARC file. $RM_COMMAND $FILE_OPENDMARC_DAT if [ "$?" != 0 ]; then retval $? log "Remove OpenDMARC HistoryFile ..............................[FAILED]" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 54 else log "Remove OpenDMARC HistoryFile ..............................[ OK ]" fi # Create OpenDMARC file. $TOUCH_COMMAND $FILE_OPENDMARC_DAT if [ "$?" != 0 ]; then retval $? log "Create OpenDMARC HistoryFile ..............................[FAILED]" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 55 else log "Create OpenDMARC HistoryFile ..............................[ OK ]" fi # Set owner to OpenDMARC file. $CHOWN_COMMAND $FILE_OPENDMARC_USER:$FILE_OPENDMARC_USER $FILE_OPENDMARC_DAT if [ "$?" != 0 ]; then retval $? log "Set owner to OpenDMARC HistoryFile ........................[FAILED]" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 56 else log "Set owner to OpenDMARC HistoryFile ........................[ OK ]" fi # Set rights to OpenDMARC file. $CHMOD_COMMAND $FILE_OPENDMARC_PERMISSION $FILE_OPENDMARC_DAT if [ "$?" != 0 ]; then retval $? log "Set rights to OpenDMARC HistoryFile .......................[FAILED]" $RM_COMMAND -f $FILE_LOCK sendmail ERROR movelog exit 57 else log "Set rights to OpenDMARC HistoryFile .......................[ OK ]" fi # Finish process. log "" log "+-----------------------------------------------------------------+" log "| End process from $SCRIPT_NAME ...................... |" log "+-----------------------------------------------------------------+" log "" # Status e-mail. if [ $MAIL_STATUS = 'Y' ]; then sendmail STATUS fi # Move temporary log to permanent log movelog exit 0
Nachfolgender Befehl setzte die Datei- und Besitzrechte für das Skript wie folgt:
# chmod 750 /etc/opendmarc/opendmarc_report_out.sh
und
# chown root:root /etc/opendmarc/opendmarc_report_out.sh
Nach der erfolgreichen Ausführung des Skripts, wie nachfolgender manueller Aufruf zeigt, sind die Daten in der Datenbank und eine e-Mail an den einliefernden e-Mail-Server, welcher einen Report angefordert hat wurde ebenfalls generiert. Zum Abschluss ist dann noch eine Datenbankbereinigung angestoßen worden:
+-----------------------------------------------------------------+ | Start processing opendmarc database jobs and e-Mail-report gen. | +-----------------------------------------------------------------+ Run script with following parameter: SCRIPT_NAME...........: opendmarc_report_out.sh MAIL_RECIPIENT........: root@tachtler.net MAIL_STATUS...........: N FILE_OPENDMARC_DAT....: /var/spool/opendmarc/opendmarc.dat Check if command '/bin/touch' was found....................[ OK ] Check if command '/bin/rm' was found.......................[ OK ] Check if command '/bin/cat' was found......................[ OK ] Check if command '/bin/date' was found.....................[ OK ] Check if command '/sbin/sendmail' was found................[ OK ] Check if script is NOT already runnig .....................[ OK ] Check if /var/spool/opendmarc/opendmarc.dat exists ........[ OK ] +-----------------------------------------------------------------+ | Run process from opendmarc_report_out.sh ...................... | +-----------------------------------------------------------------+ Import DMARC data into the database from file .............[ OK ] opendmarc-reports: started at Fri Oct 23 11:10:33 2015 opendmarc-reports: selected 1 domain(s) opendmarc-reports: sent report for nausch.org to dmarc-reports@nausch.org (2.0.0 Ok: queued as 27894805BB4) opendmarc-reports: terminating at Fri Oct 23 11:10:34 2015 Generate reports and sent them ............................[ OK ] opendmarc-expire: started at Fri Oct 23 11:10:34 2015 opendmarc-expire: connected to database opendmarc-expire: expiring messages older than 90 day(s) opendmarc-expire: no rows deleted opendmarc-expire: expiring signatures on expired messages (id < 1) opendmarc-expire: no rows deleted opendmarc-expire: expiring request data older than 90 days opendmarc-expire: no rows deleted opendmarc-expire: terminating at Fri Oct 23 11:10:34 2015 Clean the database ........................................[ OK ] Remove OpenDMARC HistoryFile ..............................[ OK ] Create OpenDMARC HistoryFile ..............................[ OK ] Set owner to OpenDMARC HistoryFile ........................[ OK ] Set rights to OpenDMARC HistoryFile .......................[ OK ] +-----------------------------------------------------------------+ | End process from opendmarc_report_out.sh ...................... | +-----------------------------------------------------------------+
/etc/crontab
Abschließend soll das Skript nun ein mal pro Tag ausgeführt werden. Die soll nicht durch den anacron
-job-Lauf erfolgen, sondern durch einen klassiscen cron
-job.
Dazu soll nachfolgender Eintrag in der Konfigurationsdatei:
/etc/crontab
eingefügt werden:
(Komplette Konfigurationsdatei:)
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # For details see man 4 crontabs # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed # Tachtler # OpenDMARC data import, report generation and e-Mail sent process and database cleaning. 0 4 * * * root /root/bin/opendmarc_report_out.sh 1>/dev/null 2>&1
* Das Skript soll jeden Tag um 4:00 Uhr ausgeführt werden!
Konfiguration: Reports eingehend
Um eingehende OpenDMARC-Reports, welche als e-Mail mit einem ZIP-Anhang versandt werden, ebenfalls verarbeiten zu können und in einer Datenbank speichern zu können, sind nachfolgende Schritte notwendig.
Die original Anleitung zu diesem Thema ist unter nachfolgendem externen Link zu finden:
Dank der Vorarbeiten und den Skripten von John Levine, ist die Einbindung einfacher möglich geworden, da hier sonst keine Unterstützung von Seiten OpenDMARC geboten wird.
Installation: Skriptabhängigkeiten
Nachfolgende rpm
-Pakete müssen als Abhängigkeiten zum Skript readdmarc.pl
zusätzlich installiert werden:
Die Installation der Skriptabhängigkeiten, kann durch ausführen des nachfolgenden Befehls durchgeführt werden:
# yum install perl-DBI perl-Getopt-Simple perl-IO-Socket-INET6 perl-MIME-tools perl-NetAddr-IP perl-PerlIO-gzip perl-XML-Parser perl-XML-SAX perl-XML-Simple Loaded plugins: changelog, priorities 149 packages excluded due to repository priority protections Package perl-DBI-1.627-4.el7.x86_64 already installed and latest version Package perl-IO-Socket-INET6-2.69-5.el7.noarch already installed and latest version Package perl-MIME-tools-5.505-1.el7.noarch already installed and latest version Package perl-NetAddr-IP-4.069-3.el7.x86_64 already installed and latest version Resolving Dependencies --> Running transaction check ---> Package perl-PerlIO-gzip.x86_64 0:0.19-1.el7 will be installed ---> Package perl-XML-Parser.x86_64 0:2.41-10.el7 will be installed ---> Package perl-XML-SAX.noarch 0:0.99-9.el7 will be installed ---> Package perl-XML-Simple.noarch 0:2.20-5.el7 will be installed --> Finished Dependency Resolution Changes in packages about to be updated: Dependencies Resolved =============================================================================== Package Arch Version Repository Size =============================================================================== Installing: perl-PerlIO-gzip x86_64 0.19-1.el7 epel 23 k perl-XML-Parser x86_64 2.41-10.el7 base 223 k perl-XML-SAX noarch 0.99-9.el7 base 63 k perl-XML-Simple noarch 2.20-5.el7 base 74 k Transaction Summary =============================================================================== Install 4 Packages Total download size: 384 k Installed size: 943 k Is this ok [y/d/N]: y Downloading packages: (1/4): perl-PerlIO-gzip-0.19-1.el7.x86_64.rpm | 23 kB 00:00 (2/4): perl-XML-Parser-2.41-10.el7.x86_64.rpm | 223 kB 00:00 (3/4): perl-XML-Simple-2.20-5.el7.noarch.rpm | 74 kB 00:00 (4/4): perl-XML-SAX-0.99-9.el7.noarch.rpm | 63 kB 00:00 ------------------------------------------------------------------------------- Total 1.1 MB/s | 384 kB 00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : perl-XML-Parser-2.41-10.el7.x86_64 1/4 Installing : perl-XML-SAX-0.99-9.el7.noarch 2/4 Installing : perl-XML-Simple-2.20-5.el7.noarch 3/4 Installing : perl-PerlIO-gzip-0.19-1.el7.x86_64 4/4 Verifying : perl-XML-Simple-2.20-5.el7.noarch 1/4 Verifying : perl-PerlIO-gzip-0.19-1.el7.x86_64 2/4 Verifying : perl-XML-SAX-0.99-9.el7.noarch 3/4 Verifying : perl-XML-Parser-2.41-10.el7.x86_64 4/4 Installed: perl-PerlIO-gzip.x86_64 0:0.19-1.el7 perl-XML-Parser.x86_64 0:2.41-10.el7 perl-XML-SAX.noarch 0:0.99-9.el7 perl-XML-Simple.noarch 0:2.20-5.el7 Complete!
Nachfolgende rpm
-Pakete müssen als Abhängigkeiten zum Skript readdmarcfailure.py
zusätzlich installiert werden:
Die Installation der Skriptabhängigkeiten, kann durch ausführen des nachfolgenden Befehls durchgeführt werden:
# yum install MySQL-python Loaded plugins: changelog, priorities 262 packages excluded due to repository priority protections Resolving Dependencies --> Running transaction check ---> Package MySQL-python.x86_64 0:1.2.5-1.el7 will be installed --> Finished Dependency Resolution Changes in packages about to be updated: Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: MySQL-python x86_64 1.2.5-1.el7 base 90 k Transaction Summary ================================================================================ Install 1 Package Total download size: 90 k Installed size: 284 k Is this ok [y/d/N]: y Downloading packages: MySQL-python-1.2.5-1.el7.x86_64.rpm | 90 kB 00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : MySQL-python-1.2.5-1.el7.x86_64 1/1 Verifying : MySQL-python-1.2.5-1.el7.x86_64 1/1 Installed: MySQL-python.x86_64 0:1.2.5-1.el7 Complete!
/etc/opendmarc/mkdmarc
Das Skript mkdmarc
erstellt eine Datenbank, Tabellen und die dazugehörigen Felder um DMARC-Reports, die per e-Mail eintreffen in die Datenbank zu transferieren.
HINWEIS - Nachfolgende Änderungen sollten am Skript vorgenommen werden, um die Datenbank, Tabellen und Felder möglichst einfach anlegen zu können
Alle Anpassungen am Skript sind mit
-- # Tachtler
gekennzeichnet.
-- Create database for DMARC data -- Copyright 2012, 2016, Taughannock Networks. All rights reserved. -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions -- are met: -- Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution. -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -- AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY -- WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -- POSSIBILITY OF SUCH DAMAGE. -- # Tachtler CREATE DATABASE IF NOT EXISTS dmarc; USE dmarc; -- # Tachtler CREATE TABLE IF NOT EXISTS report ( serial int(10) unsigned NOT NULL AUTO_INCREMENT, mindate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, maxdate timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', domain varchar(255) NOT NULL, org varchar(255) NOT NULL, reportid varchar(255) NOT NULL, email varchar(255), extra_contact_info varchar(255), policy_adkim varchar(20), policy_aspf varchar(20), policy_p varchar(20), policy_sp varchar(20), policy_pct tinyint unsigned, PRIMARY KEY (serial), UNIQUE KEY domain (domain,reportid) ); -- Use these commands to change the old IPv4 only DMARC table to the new one /*** alter table rptrecord modify ip int(10) unsigned; alter table rptrecord add column ip6 binary(16) after ip; alter table rptrecord add key serial6(serial,ip6); ***/ -- Use these commands to load in the optional IPv6 formatting functions /*** CREATE FUNCTION inet_6top RETURNS STRING SONAME 'mysql_ip6.so'; CREATE FUNCTION inet_pto6 RETURNS STRING SONAME 'mysql_ip6.so'; ***/ -- # Tachtler CREATE TABLE IF NOT EXISTS rptrecord ( serial int(10) unsigned NOT NULL, ip int(10) unsigned, ip6 binary(16), rcount int(10) unsigned NOT NULL, disposition enum('none','quarantine','reject'), reason varchar(255), dkimdomain varchar(255), dkimresult enum('none','pass','fail','neutral','policy','temperror','permerror'), spfdomain varchar(255), spfresult enum('none','neutral','pass','fail','softfail','temperror','permerror'), spf_align enum('fail', 'pass'), dkim_align enum('fail', 'pass'), identifier_hfrom varchar(255), KEY serial (serial,ip), KEY serial6 (serial,ip6) ) ENGINE=MyISAM; -- # Tachtler CREATE TABLE IF NOT EXISTS failure ( serial int(10) unsigned NOT NULL AUTO_INCREMENT, org varchar(255) NOT NULL, -- reported-domain bouncedomain varchar(255), -- MAIL FROM bouncebox@bouncedomain bouncebox varchar(255), fromdomain varchar(255), -- From: frombox@fromdomain frombox varchar(255), arrival TIMESTAMP, sourceip int unsigned, -- inet_aton(source-ip) sourceip6 BINARY(16), -- inet_6top(source-ip) headers TEXT, authres TEXT, PRIMARY KEY(serial), KEY(sourceip), KEY(fromdomain), KEY(bouncedomain) ) charset=utf8; -- # Tachtler -- GRANT all on dmarc.* to dmarc identified by 'xxx'; -- GRANT all on dmarc.* to dmarc@localhost identified by 'xxx'; -- # Tachtler - Create new users. CREATE USER 'dmarc_user'@'192.168.0.70' IDENTIFIED BY 'password'; CREATE USER 'dmarc_user'@'server70.idmz.tachtler.net' IDENTIFIED BY 'password'; -- # Tachtler - Grant ALL privileges to new users. GRANT ALL PRIVILEGES ON *.* TO 'dmarc_user'@'192.168.0.70' IDENTIFIED BY 'password' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON *.* TO 'dmarc_user'@'server70.idmz.tachtler.net' IDENTIFIED BY 'password' WITH GRANT OPTION; -- # Tachtler - Make sure that priviliges are reloaded. FLUSH PRIVILEGES;
Nachfolgende Änderungen wurden am Skript durchgeführt:
Erstellen der Datenbank dmarc
, wenn diese nocht nicht existieren sollte und anbringen eines ;
(Semikolon) hinter USE dmarc
.
Austausch des Syntax CREATE TABLE <Tabellenname>
gegen CREATE TABLE IF NOT EXISTS <Tabellenname>
.
Erstellen von zwei neuen Benutzer, dmarc_user'@'192.168.0.70
und dmarc_user'@'server70.idmz.tachtler.net
, welche via IP-Adresse oder FQDN vom Server 192.168.0.70
bzw. server70.idmz.tachtler.net
agieren dürfen und ein Passwort besitzen
Den beiden Benutzern dmarc_user'@'192.168.0.70
und dmarc_user'@'server70.idmz.tachtler.net
werden alle Privilegien in auf die Datenbank dmarc
gewährt.
-- # Tachtler - Make sure that priviliges are reloaded. FLUSH PRIVILEGES;
Die Benutzerrechte, inklusive der neu angelegten Benutzer mit den entsprechenden Rechten, sollen aktiviert werden, in dem die Rechte neu eingelesen werden sollen.
Die Ausführung des Skriptes und die damit verbunden Anlage der Datenbank, der Tabellen und Felder und der Nutzer, kann durch Ausführung des nachfolgenden Befehls durchgeführt werden, zudem jedoch das Kennwort zum Datenbankbenutzer root
erforderlich ist!:
# /usr/bin/mysql -u root -p < /etc/opendmarc/mkdmarc Enter password:
/usr/local/bin/readdmarc.pl
Das Skript readdmarc.pl
liest eine eingehende e-Mail, welche einen Report in einer ZIP-Datei enthält direkt vom Postfix dadurch ein, das Postfix die e-Mail direkt an das Skript übergibt und dieses dann alle Informationen extrahiert und in die Datenbank schreibt.
HINWIES - Anpassungen müssen beim Datenbankzugriff durchgeführt werden!
#!/usr/bin/perl # Script zum automatischen Verarbeiten der DMARC-Reportmails in die mySQL-Datenbank dmarc # basierend auf den DMARC Reporting scripts (http://www.taugh.com/rddmarc) von John Levine (http://www.johnlevine.com/) # Über STDIN wird dem Script readdmarc die eMail übergeben, also z.B.: $ readdmarc < mailtext # 2014-05-15 : V.01 by Django (django@mailserver.guru) - mit freundlicher Unterstützung von Klaus (klaus@tachtler.net) use strict; use MIME::Parser; use MIME::Words qw(:all); use XML::Simple; use DBI; use IO::Socket::INET6; use Socket6; use Socket qw(:DEFAULT :crlf); use NetAddr::IP; use PerlIO::gzip; #use IO::Compress; my $buffer = ''; my $input = ''; # Debugmeldungen ausgeben? Wenn ja, dann $opt_d = 1 my $opt_d = 0; my $db_host = "mariadb.idmz.tachtler.net"; my $db_port = "3306"; my $db_name = "dmarc"; my $db_user = "dmarc_user"; my $db_pass = ""; my $dbh = DBI -> connect ("DBI:mysql:database=$db_name;host=$db_host;port=$db_port","$db_user",'geheim') or die "Cannot connect to database\n"; while (sysread(STDIN, $input, 1024) > 0) { $buffer .= $input; } print "parsing \n"; my ($zip, $ent, $isgzip); my $parser = new MIME::Parser; $parser->output_dir("/tmp"); $ent = $parser->parse_data($buffer); my $body = $ent->bodyhandle; $zip = $body; my $mtype = $ent->mime_type; my $subj = decode_mimewords($ent->get('subject')); print " $subj"; # if multipart/whatever, look through the parts to find a ZIP if(lc $mtype =~ "multipart/") { print "Look through $mtype\n"; $zip = undef; my $npart = $ent->parts; for my $n (0..($npart-1)) { my $part = $ent->parts($n); if(lc $part->mime_type eq "application/gzip") { $zip = $part->bodyhandle; $isgzip = 1; last; } elsif(lc $part->mime_type eq "application/zip" or lc $part->mime_type eq "application/x-zip-compressed" or lc $part->mime_type eq "application/octet-stream") { $zip = $part->bodyhandle; last; } else { $part->bodyhandle->purge; # not useful } } die "no zip" unless $zip; } elsif(lc $mtype ne "application/zip") { print "don't understand $mtype\n"; next; } if(defined($zip->path)) { print "body is in " . $zip->path . "\n" if $opt_d; } else { print "body is nowhere\n"; next; } if($isgzip) { open(XML, "<:gzip", $zip->path) or die "cannot ungzip $zip->path"; } else { open(XML,"unzip -p " . $zip->path . " |") or die "cannot unzip $zip->path"; } my $xml = ""; $xml .= $_ while <XML>; $ent->purge if $ent; $zip->purge if $zip; my $xs = XML::Simple->new(); print "XML is ======\n$xml\n=====\n" if $opt_d; my $ref = $xs->XMLin($xml, SuppressEmpty => ''); my %xml = %{$ref}; my $from = $xml{'report_metadata'}->{'date_range'}->{'begin'}; my $to = $xml{'report_metadata'}->{'date_range'}->{'end'}; my $org = $xml{'report_metadata'}->{'org_name'}; my $id = $xml{'report_metadata'}->{'report_id'}; my $email = $xml{'report_metadata'}->{'email'}; my $extra = $xml{'report_metadata'}->{'extra_contact_info'}; my $domain = $xml{'policy_published'}->{'domain'}; my $policy_adkim = $xml{'policy_published'}->{'adkim'}; my $policy_aspf = $xml{'policy_published'}->{'aspf'}; my $policy_p = $xml{'policy_published'}->{'p'}; my $policy_sp = $xml{'policy_published'}->{'sp'}; my $policy_pct = $xml{'policy_published'}->{'pct'}; print "report $org ($id) $from to $to for $domain\n" if $opt_d; # see if already stored my ($xorg, $xid, $serial) = $dbh->selectrow_array(qq{SELECT org,reportid,serial FROM report WHERE reportid=?}, undef, $id); if($xorg) { print "Already have $xorg $xid, skipped\n"; } my $sql = qq{INSERT INTO report(serial,mindate,maxdate,domain,org,reportid,email,extra_contact_info,policy_adkim,policy_aspf,policy_p,policy_sp,policy_pct) VALUES(NULL,FROM_UNIXTIME(?),FROM_UNIXTIME(?),?,?,?,?,?,?,?,?,?,?)}; $sql = qq{REPLACE INTO report(serial,mindate,maxdate,domain,org,reportid,email,extra_contact_info,policy_adkim,policy_aspf,policy_p,policy_sp,policy_pct) VALUES('$serial',FROM_UNIXTIME(?),FROM_UNIXTIME(?),?,?,?,?,?,?,?,?,?,?)} if $xorg; $dbh->do($sql, undef, $from, $to, $domain, $org, $id, $email, $extra, $policy_adkim, $policy_aspf, $policy_p, $policy_sp, $policy_pct) or die "cannot make report" . $dbh->errstr; $serial = $dbh->{'mysql_insertid'} || $dbh->{'insertid'} unless $xorg; print " serial $serial "; my $record = $xml{'record'}; sub dorow($$) { my ($serial,$recp) = @_; my %r = %$recp; my $ip = $r{'row'}->{'source_ip'}; my $count = $r{'row'}->{'count'}; my $disp = $r{'row'}->{'policy_evaluated'}->{'disposition'}; my $dkim_align = $r{'row'}->{'policy_evaluated'}->{'dkim'}; my $spf_align = $r{'row'}->{'policy_evaluated'}->{'spf'}; my $identifier_hfrom = $r{'identifiers'}->{'header_from'}; print "\nip $ip, count $count, disp $disp" if $opt_d; my ($dkim, $dkimresult, $spf, $spfresult, $reason); my $rp = $r{'auth_results'}->{'dkim'}; printf " rp $rp\n" if $opt_d; if(ref $rp eq "HASH") { $dkim = $rp->{'domain'}; $dkim = undef if ref $dkim eq "HASH"; $dkimresult = $rp->{'result'}; } else { # array # glom sigs together, report first result $dkim = join '/',map { my $d = $_->{'domain'}; ref $d eq "HASH"?"": $d } @$rp; $dkimresult = $rp->[0]->{'result'}; } $rp = $r{'auth_results'}->{'spf'}; if(ref $rp eq "HASH") { $spf = $rp->{'domain'}; $spfresult = $rp->{'result'}; } else { # array # glom domains together, report first result $spf = join '/',map { my $d = $_->{'domain'}; ref $d eq "HASH"? "": $d } @$rp; $spfresult = $rp->[0]->{'result'}; } $rp = $r{'row'}->{'policy_evaluated'}->{'reason'}; if(ref $rp eq "HASH") { $reason = $rp->{'type'}; } else { $reason = join '/',map { $_->{'type'} } @$rp; } #print "ip=$ip, count=$count, disp=$disp, r=$reason,"; #print "dkim=$dkim/$dkimresult, spf=$spf/$spfresult\n"; # figure out if it's IPv4 or IPv6 my ($nip, $iptype, $ipval); if($nip = inet_pton(AF_INET, $ip)) { $ipval = unpack "N", $nip; $iptype = "ip"; } elsif($nip = inet_pton(AF_INET6, $ip)) { $ipval = "X'" . unpack("H*",$nip) . "'"; $iptype = "ip6"; } else { print "??? mystery ip $ip\n"; next; } print "$iptype = $ipval\n" if $opt_d; print "$iptype = $ipval, spf $spf_align, dkim $dkim_align\n" if $opt_d; $dbh->do(qq{INSERT INTO rptrecord(serial,$iptype,rcount,disposition,spf_align,dkim_align,reason,dkimdomain,dkimresult,spfdomain,spfresult,identifier_hfrom) VALUES(?,$ipval,?,?,?,?,?,?,?,?,?,?)},undef, $serial,$count,$disp,$spf_align,$dkim_align,$reason,$dkim,$dkimresult,$spf,$spfresult,$identifier_hfrom) or die "cannot insert record " . $dbh->{'mysql_error'}; } # dorow if(ref $record eq "HASH") { print "single record\n"; dorow($serial,$record); } elsif(ref $record eq "ARRAY") { print "multi record\n"; foreach my $row (@$record) { dorow($serial,$row); } } else { print "mystery type " . ref($record) . "\n"; }
Nachfolgende Änderungen wurden am Skript durchgeführt:
Anpassen des Datenbankzugriffs in Bezug auf den Datenbank-Server, Datenbank-Port, den Benutzernamen und das Passwort.
HINWEIS - Die Variable $db_pass
wird hier nicht genutzt, sondern das Passwort wird direkt in den Verbindungsaufbau eingetragen, da bei komplexen Passwörtern mit Sonderzeichenkombinationen sonst Probleme auftreten könnten!
Nachfolgender Befehl setzte die Datei- und Besitzrechte für das Skript wie folgt:
# chmod 755 /usr/local/bin/readdmarc.pl
und
# chown root:root /usr/local/bin/readdmarc.pl
/usr/local/bin/readdmarcfailure.py
Das Skript readdmarcfailure.py
liest eine eingehende e-Mail, welche einen Fehlerreport in einer ZIP-Datei enthält direkt vom Postfix dadurch ein, das Postfix die e-Mail direkt an das Skript übergibt und dieses dann alle Informationen extrahiert und in die Datenbank schreibt.
HINWIES - Anpassungen müssen beim Datenbankzugriff durchgeführt werden!
#!/usr/bin/python # $Header: /home/johnl/hack/dmarc/RCS/dmarcfail.py,v 1.2 2015/05/02 20:15:02 johnl Exp $ # parse DMARC failure reports, add it to the mysql database # optional arguments are names of files containing ARF messages, # otherwise it reads stdin # Copyright 2012, Taughannock Networks. All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY # WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #!/usr/local/bin/python # parse a DMARC failure report, add it to the mysql database import re import email import time import MySQLdb # Tachtler # default: db = MySQLdb.connect(user='dmarc',passwd='x',db='dmarc', use_unicode=True) db = MySQLdb.connect(host='mariadb.idmz.tachtler.net',port=3306,user='dmarc_user',passwd='geheim',db='dmarc', MySQLdb.paramstyle='format' def dmfail(h,f): e = email.message_from_file(h) if(e.get_content_type() != "multipart/report"): print f,"is not a report" return for p in e.get_payload(): if(p.get_content_type() == "message/feedback-report"): r = email.parser.Parser() fr = r.parsestr(p.get_payload()[0].as_string(), True) fx = re.search(r'<(.+?)@(.+?)>', fr['original-mail-from']) if fx: origbox,origdom = fx.group(1,2) else: origbox,origdom = (None,None) if 'arrival-date' in fr: arr = int(email.utils.mktime_tz(email.utils.parsedate_tz(fr['arrival-date']))) else: # fake it with message date arr = int(email.utils.mktime_tz(email.utils.parsedate_tz(e['date']))) authres = fr['authentication-results'] if 'authentication-results' in fr else None elif(p.get_content_type() == "message/rfc822" or p.get_content_type() == "text/rfc822-headers"): if p.is_multipart(): # library thinks message/rfc822 is multipart m = email.message_from_string(p.get_payload(0).as_string()) else: m = email.message_from_string(p.get_payload()) frombox = fromdom = None if 'from' in m: fx = re.search(r'<(.+)@(.+)>', m['from']) if(fx): frombox,fromdom = fx.group(1,2) else: t = re.sub(m['from'],r'\s+|\([^)]*\)',"") fx = re.match(r'(.+)@(.+)', t) if(fx): frombox,fromdom = fx.group(1,2) # OK, parsed it, now add an entry to the database #print fr['reported-domain'],origdom,origbox,fromdom,frombox,arr,fr['source-ip'],"===" #print m.as_string() #print "===" c = db.cursor() c.execute("""INSERT INTO failure(serial,org,bouncedomain,bouncebox,fromdomain, frombox,arrival,sourceip,headers,authres) VALUES(NULL,%s,%s,%s,%s,%s,FROM_UNIXTIME(%s),INET_ATON(%s),%s,%s)""", (fr['reported-domain'],origdom,origbox,fromdom,frombox,arr,fr['source-ip'],m.as_string(),authres)) print "Inserted failure report %s" % c.lastrowid c.close() db.commit() if __name__ == "__main__": import sys if(len(sys.argv) < 2): dmfail(sys.stdin,"stdin"); else: for f in sys.argv[1:]: h = open(f) dmfail(h, f) h.close()
Nachfolgende Änderungen wurden am Skript durchgeführt:
db = MySQLdb.connect(host='mariadb.idmz.tachtler.net',port=3306,user='dmarc_user',passwd='geheim',db='dmarc', use_unicode=True)
Anpassen des Datenbankzugriffs in Bezug auf den Datenbank-Server, Datenbank-Port, den Benutzernamen und das Passwort.
Nachfolgender Befehl setzte die Datei- und Besitzrechte für das Skript wie folgt:
# chmod 755 /usr/local/bin/readdmarcfailure.py
und
# chown root:root /usr/local/bin/readdmarcfailure.py
/etc/postfix/master.cf
Nachfolgende Definitionen sind erforderlich, damit Postfix das Skript bekannt ist und nutzen kann:
(Nur relevanter Ausschnitt:)
... # Tachtler readdmarc unix - n n - 1 pipe flags=DRhu user=nobody argv=/usr/local/bin/readdmarc.pl # Tachtler readdmarcfailure unix - n n - 1 pipe flags=DRhu user=nobody argv=/usr/local/bin/readdmarcfailure.py ...
/etc/postfix/main.cf
Nachfolgende Änderungen sind erforderlich, falls noch keine transport_maps
verwendet werden:
(Nur relevanter Ausschnitt):
... # TRANSPORT MAP # # See the discussion in the ADDRESS_REWRITING_README document. # Tachtler - new - transport_maps = btree:/etc/postfix/transport_maps, $relay_domains ...
/etc/postfix/transport_maps
Zur Weiterleitung von Postfix an die Skripte /usr/local/bin/readddmarc.pl
und /usr/local/bin/readddmarcfailure.py
, ist es erforderlich diese in der /etc/postfix/transport_maps
entsprechend zu definieren, wie nachfolgend gezeigt:
(Komplette Konfigurationsdatei:)
dmarc-aggregate@tachtler.net readdmarc: dmarc-incorrect@tachtler.net readdmarcfailure:
HINWEIS - Als Trennzeichen zwischen den beiden Einträgen, sollte am besten die [TAB]-Taste verwendet werden, es ist aber auch die Trennung durch [Leerzeichen] möglich!
WICHTIG - Zum Abschluss muss die Konfigurationsdatei in ein Datenbank-Format, z.B. das Format btree
mithilfe des Postfix eigenen Befehls postmap
umgewandelt werden, wie nachfolgender Befehl zeigt:
# postmap btree:/etc/postfix/transport_maps
Anschließend sollte eine neue Datei mit dem Namen /etc/postfix/transport_maps.db
entstanden sein, was mit nachfolgendem Befehl überprüft werden:
# ls -l /etc/postfix/transport_maps* -rw-r--r-- 1 root root 24 Aug 19 09:51 /etc/postfix/transport_maps -rw-r--r-- 1 root root 8192 Aug 19 09:51 /etc/postfix/transport_maps.db
**ODER BESSER** /etc/aliases
HINWEIS - Als alternative Weiterleitung von Postfix an die Skripte /usr/local/bin/readddmarc.pl
und /usr/local/bin/readddmarcfailure.py
, ist es ebenfalls möglich anstelle von /etc/postfix/transport_maps
, /etc/postfix/main.cf
und /etc/postfix/master.cf
diese in der /etc/aliases
entsprechend zu definieren, wie nachfolgend gezeigt:
(Nur relevanter Ausschnitt:)
... dmarc-aggregate: "|/usr/local/bin/readdmarc.pl" dmarc-aggregate+badhd: "|/usr/local/bin/readdmarc.pl" dmarc-incorrect: "|/usr/local/bin/readdmarcfailure.py" dmarc-incorrect+badhd: "|/usr/local/bin/readdmarcfailure.py"
Anschließend ist sind die Änderungen noch in ein für Postfix besser lesbares Datenbankformat umzuwandeln, was mit nachfolgendem Befehl durchgeführt werden kann:
# newaliases
Konfiguration: DMARC Reports Web GUI
Unter nachfolgenden externen Link
kann eine Web GUI heruntergeladen werden, welche zur Anzeige der Daten, die innerhalb der Datenbank gespeichert sind, genutzt werden kann.
Nachfolgend soll die Konfiguration eines Apache HTTP Servers durchgeführt werden, um die in PHP Net geschrieben DMARC Reports Web GUI zur anzeige zu bringen.
Voraussetzungen
Als Voraussetzung für die Installation von DMARC Reports sind folgende Komponenten erforderlich:
- Lauffähiger Datenbank-Server z.B. MariaDB
- Siehe auch den internen Link: MariaDB CentOS 7
- Lauffähiger Web-Server z.B. Apache HTTP Server
- Siehe auch den internen Link: Apache HTTP Server CentOS 7
- PHP PHP Net
Herunterladen
Bevor die in PHP Net geschriebene DMARC Reports Web GUI DMARC Reports heruntergeladen werden soll, muss zuerst auf dem Server auf dem der Apache HTTP Server läuft ein neues Verzeichnis angelegt werden, was mit nachfolgendem Befehl durchgeführt werden kann:
# mkdir /var/www/dmarcreports
Anschließend kann mit nachfolgendem Befehl die DMARC Reports Web GUI DMARC Reports direkt in das neu erstellte Verzeichnis heruntergeladen und umbenannt werden:
# wget https://github.com/techsneeze/dmarcts-report-viewer/archive/master.zip -P /tmp/ --2017-10-20 09:15:54-- https://github.com/techsneeze/dmarcts-report-viewer/archive/master.zip Resolving github.com (github.com)... 192.30.253.112, 192.30.253.113 Connecting to github.com (github.com)|192.30.253.112|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://codeload.github.com/techsneeze/dmarcts-report-viewer/zip/master [following] --2017-10-20 09:15:54-- https://codeload.github.com/techsneeze/dmarcts-report-viewer/zip/master Resolving codeload.github.com (codeload.github.com)... 192.30.253.121, 192.30.253.120 Connecting to codeload.github.com (codeload.github.com)|192.30.253.121|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 18293 (18K) [application/zip] Saving to: ‘/tmp/master.zip’ 100%[======================================>] 18,293 --.-K/s in 0.1s 2017-10-20 09:15:55 (133 KB/s) - ‘/tmp/master.zip’ saved [18293/18293
Anschließend soll das soeben heruntergeladene ZIP-Archiv mit nachfolgendem Befehl entpackt werden:
# unzip /tmp/master.zip -d /var/www/ Archive: /tmp/master.zip 5d97612e00bcce48d446fa85e19b392d8433376f creating: /var/www/dmarcts-report-viewer-master/ extracting: /var/www/dmarcts-report-viewer-master/.gitignore inflating: /var/www/dmarcts-report-viewer-master/LICENSE inflating: /var/www/dmarcts-report-viewer-master/README.md inflating: /var/www/dmarcts-report-viewer-master/default.css inflating: /var/www/dmarcts-report-viewer-master/dmarcts-report-viewer-config.php.sample inflating: /var/www/dmarcts-report-viewer-master/dmarcts-report-viewer.php
Das so entstandene Verzeichnis
/var/www/dmarcts-report-viewer-master/
kann nun mit nachfolgendem Befehl umbenannt werden:
# mv /var/www/dmarcts-report-viewer-master /var/www/dmarcreports
Nachfolgender Befehl zeigt nun den Inhalt des Verzeichnisses /var/www/dmarcreports
:
# ls -la /var/www/dmarcreports total 68 drwxr-xr-x 2 root root 149 Oct 2 20:34 . drwxr-xr-x. 10 root root 4096 Oct 20 09:21 .. -rw-r--r-- 1 root root 1307 Oct 2 20:34 default.css -rw-r--r-- 1 root root 358 Oct 2 20:34 dmarcts-report-viewer-config.php.sample -rw-r--r-- 1 root root 11254 Oct 2 20:34 dmarcts-report-viewer.php -rw-r--r-- 1 root root 47 Oct 2 20:34 .gitignore -rw-r--r-- 1 root root 35141 Oct 2 20:34 LICENSE -rw-r--r-- 1 root root 2132 Oct 2 20:34 README.md
/var/www/dmarcreports/dmarcts-report-viewer-config.php.
Bevor die in PHP Net geschriebene DMARC Reports Web GUI DMARC Reports genutzt werden kann, ist es noch erforderlich die Beispielkonfigurationsdatei
/var/www/dmarcreports/dmarcts-report-viewer-config.php.sample
zu kopieren und die darin befindlichen Variablen anzupassen, damit ein Zugriff auf die Datenbank durch das Skript durchgeführt werden kann, was mit nachfolgendem Befehl durchgeführt werden kann:
# cp -a /var/www/dmarcreports/dmarcts-report-viewer-config.php.sample /var/www/dmarcreports/dmarcts-report-viewer-config.php
(Komplettes Skript)
<?php // #################################################################### // ### configuration ################################################## // #################################################################### $dbhost="mariadb.idmz.tachtler.net"; $dbname="dmarc"; $dbuser="dmarc_user"; $dbpass="geheim"; $default_lookup = 0; # 1= on 0=off (on is old behaviour ) ?>
Nachfolgende Änderungen wurden am Skript durchgeführt:
$dbhost="mariadb.idmz.tachtler.net"; $dbname="dmarc"; $dbuser="dmarc_user"; $dbpass="geheim";
Anpassung der Zugriffsdaten für die Datenbank, wie Datenbank-Server, Benutzername und das Passwort.
$default_lookup = 0; # 1= on 0=off (on is old behaviour )
Standardmäßig keine DNS-Anfragen (lookups) zur Ermittelung der Host-Namen (DNS-Namensauflösung) basierend auf den IP-Adressen durchführen.
HINWEIS - Dies sollte deaktiviert werden, da sonst viele DSN-Anfrage den Seitenaufbau extrem verlangsamen können!
/var/www/dmarcreports/index.php
Abschließend soll noch ein symbolischer Link wie folgt gesetzt werden, damit der Aufruf des PGP-Scripts/Seite /var/www/dmarcreports/dmarcts-report-viewer.php
via /var/www/dmarcreports/index.php
erfolgen kann. Dies ist nicht unbedingt notwendig, aber schöner und ggf. auch bei Standard Webserver-Konfigurationen besser anzuwenden:
# ln -s /var/www/dmarcreports/dmarcts-report-viewer.php index.php
Abschließend zeigt nachfolgender Befehl nun den aktuellen Inhalt des Verzeichnisses /var/www/dmarcreports
:
# ls -la /var/www/dmarcreports total 76 drwxr-xr-x 2 root root 4096 Oct 20 09:32 . drwxr-xr-x. 10 root root 4096 Oct 20 09:21 .. -rw-r--r-- 1 root root 1307 Oct 2 20:34 default.css -rw-r--r-- 1 root root 378 Oct 20 07:58 dmarcts-report-viewer-config.php -rw-r--r-- 1 root root 358 Oct 2 20:34 dmarcts-report-viewer-config.php.sample -rw-r--r-- 1 root root 11254 Oct 2 20:34 dmarcts-report-viewer.php -rw-r--r-- 1 root root 47 Oct 2 20:34 .gitignore lrwxrwxrwx 1 root root 47 Oct 20 09:32 index.php -> /var/www/dmarcreports/dmarcts-report-viewer.php -rw-r--r-- 1 root root 35141 Oct 2 20:34 LICENSE -rw-r--r-- 1 root root 2132 Oct 2 20:34 README.md
/etc/httpd/conf.d/vhost.conf
Es soll ein virtueller Host im Apache HTTP Server eingerichtet werden.
Siehe dazu auch nachfolgende interne Links:
Dazu kann der Inhalt einer möglichen Konfigurationsdatei
/etc/httpd/conf.d/dmarcreports.conf
wie nachfolgend dargestellt entsprechend erstellt werden:
(Komplette Konfigurationsdatei)
# # dmarcreports.tachtler.net (DMARC-Reports for OpenDMARC) # <VirtualHost *:80> ServerAdmin webmaster@tachtler.net ServerName dmarcreports.tachtler.net ServerAlias www.dmarcreports.tachtler.net ServerPath / DocumentRoot "/var/www/dmarcreports" <Directory "/var/www/dmarcreports"> Options -Indexes +FollowSymLinks # Tachtler (enable for .htaccess file support) # AllowOverride AuthConfig AllowOverride None # Tachtler (enable for unlimited access) Require all granted </Directory> DirectoryIndex index.php ErrorLog logs/dmarcreports_error.log SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded CustomLog logs/dmarcreports_access.log combined env=!forwarded CustomLog logs/dmarcreports_access.log combined_proxypass env=forwarded </VirtualHost>
HINWEIS - Zu beachten sind hier, die Zeilen mit dem Inhalten
DirectoryIndex index.php
- da hier die erste Seite der Anwendung ein PHP-Script ist!
Nach Durchführung der vorhergehenden Konfigurationsschritte, sollte einem Neustart nichts im Wege stehen und die Apache VHOST-Konfiguration angezogen werden:
# systemctl restart httpd.service
HINWEIS - Es erfolgen keine weiteren Ausgaben, wenn der Start erfolgreich war !
Aufruf DMARC Reports Web GUI
Anschließend kann die DMARC Reports Web GUI DMARC Reports über den Browser aufgerufen werden. Falls bereits Daten in der Datenbank stehen, könnte die Bildschirmausgabe wie folgt aussehen:
Test Werkzeuge
Nachfolgende externe Links führen zu verschiedenen Test Werkzeugen: