summaryrefslogtreecommitdiffstats
path: root/dmarc_milter.pl
diff options
context:
space:
mode:
Diffstat (limited to 'dmarc_milter.pl')
-rwxr-xr-xdmarc_milter.pl116
1 files changed, 116 insertions, 0 deletions
diff --git a/dmarc_milter.pl b/dmarc_milter.pl
new file mode 100755
index 0000000..bdb6e0b
--- /dev/null
+++ b/dmarc_milter.pl
@@ -0,0 +1,116 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use feature 'say';
+
+use lib '.';
+
+use Sendmail::Milter;
+use Spline::DMARC qw(check_addresses);
+use Spline::Log qw(set_verbose debug info);
+use Spline::Data;
+
+use Data::Dumper;
+
+my %milter_callbacks = (
+ 'envfrom' => \&from_callback,
+ 'envrcpt' => \&rcpt_callback,
+ 'header' => \&header_callback,
+ 'eoh' => \&eom_callback,
+ 'abort' => \&abort_callback,
+ 'close' => \&close_callback,
+);
+
+sub from_callback($$@) {
+ my $ctx = shift;
+ my $from = shift;
+
+ my $data = Spline::Data->new($ctx);
+ $data->set('counter', 0);
+
+ debug "MAIL FROM: $from";
+ return SMFIS_CONTINUE;
+}
+
+sub rcpt_callback($$@) {
+ my $ctx = shift;
+ my $rcpt_to = shift;
+
+ my $data = Spline::Data->load($ctx);
+ debug "RCPT TO: $rcpt_to";
+
+ my $next_hop = $ctx->getsymval('{rcpt_host}');
+ if ($next_hop eq '[lists.spline.inf.fu-berlin.de]') {
+ info "Mailinglist address: $rcpt_to";
+ $data->set('counter', 1);
+ }
+
+ return SMFIS_CONTINUE;
+}
+
+sub header_callback($$$) {
+ my $ctx = shift;
+ my ($field, $value) = @_;
+
+ my $data = Spline::Data->load($ctx);
+ debug "HEADER '$field': $value";
+
+ if (lc($field) eq 'from') {
+ return SMFIS_CONTINUE if $data->get('counter') == 0;
+
+ my $reject = check_addresses($value);
+ if ($reject) {
+ info 'Rejecting mail';
+ $ctx->setreply('550', '5.7.2', 'Your provider does not permit sending to mailing lists (DMARC policy)');
+ return SMFIS_REJECT;
+ }
+ }
+
+ # We cannot SMFIS_ACCEPT here, because there could
+ # be multiple From headers.
+ return SMFIS_CONTINUE;
+}
+
+sub eoh_callback($) {
+ my $ctx = shift;
+
+ my $data = Spline::Data->load($ctx);
+ $data->set('counter', 0);
+
+ debug 'END OF HEADER';
+ return SMFIS_ACCEPT;
+}
+
+sub abort_callback($) {
+ my $ctx = shift;
+
+ my $data = Spline::Data->load($ctx);
+ $data->set('counter', 0);
+
+ debug 'ABORT';
+ return SMFIS_CONTINUE;
+}
+
+sub close_callback($) {
+ my $ctx = shift;
+
+ Spline::Data->load($ctx);
+ $ctx->setpriv(undef);
+
+ debug 'CLOSE';
+ return SMFIS_CONTINUE;
+}
+
+sub main($) {
+ my $listen = shift;
+
+ Sendmail::Milter::setconn($listen);
+ Sendmail::Milter::register("dmarc_lists_filter",
+ \%milter_callbacks, SMFI_CURR_ACTS);
+ Sendmail::Milter::main();
+}
+
+main('inet:12345@localhost');
+
+# vim: set et tabstop=4 tw=70: