From b916c542c6c963cbea49473de3f74a7ecfdb0d8e Mon Sep 17 00:00:00 2001 From: Scott Savarese Date: Thu, 26 Jul 2018 00:42:40 -0400 Subject: [PATCH] Add option to skip SPF checks on exempt domains based on /etc/postfix/exempt_spf_domains --- README | 6 +++++ postfix-policyd-spf-perl | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/README b/README index 85adea8..ecd954b 100644 --- a/README +++ b/README @@ -36,6 +36,12 @@ relay_addresses on line 78 using standard CIDR notation in a space separated list. For these addresses, 'X-Comment: SPF skipped for whitelisted relay' is prepended and logged. IPv6 localhost is also skipped. +A configuration file, /etc/postfix/exempt_spf_domains, can be used to +ignore domains that have broken SPF configurations that would normally +fail. For those domains, add the domain to the file (one per line), and +restart postfix so that the policy server can reload its configuration. +The policy server will ignore the domain going forward. + Error conditions within the policy server (that don't result in a crash) or from Mail::SPF will return DUNNO. diff --git a/postfix-policyd-spf-perl b/postfix-policyd-spf-perl index 18941b4..b5f36a9 100755 --- a/postfix-policyd-spf-perl +++ b/postfix-policyd-spf-perl @@ -64,6 +64,10 @@ my @HANDLERS = ( code => \&exempt_relay }, { + name => 'exempt_domains', + code => \&exempt_domains + }, + { name => 'sender_policy_framework', code => \&sender_policy_framework } @@ -73,6 +77,9 @@ my $VERBOSE = 0; my $DEFAULT_RESPONSE = 'DUNNO'; +# Read in exempt domains list +my $exempt_domains = get_exempt_domains( "/etc/postfix/exempt_spf_domains" ); + # # Syslogging options for verbose mode and for fatal errors. # NOTE: comment out the $syslog_socktype line if syslogging does not @@ -184,6 +191,50 @@ while () { %attr = (); } +# ---------------------------------------------------------- +# handler: domain exemption +# ---------------------------------------------------------- +sub get_exempt_domains { + my ( $file ) = @_; + + my $list = {}; + + # Return nothing if file not found + if ( ! -r $file ) { + return $list; + } + + # Read the file into one variable, split on space or comma (or all) + open ( FILE, $file ) or die "Can't open $file: $!\n"; + my $text = ""; + while ( my $tmp = ) { + $text .= $tmp; + } + close( FILE ); + + foreach my $domain ( split( /[\s,]+/, $text ) ) { + $list->{$domain} = 1; + } + + return $list; +} + +sub exempt_domains { + my %options = @_; + my $attr = $options{attr}; + + my $domain = ( split( /\@/, $attr->{sender} ) )[1]; + return 'DUNNO' if ( ( ! defined( $domain ) ) or ( $domain eq '' ) ); + + # Check the domain against our list of ignored domains + if ( defined( $exempt_domains->{$domain} ) ) { + return "PREPEND Authentication-Results: $host; none " . + "(SPF exempted by policy)"; + } + + return 'DUNNO'; +} + # ---------------------------------------------------------- # handler: localhost exemption # ----------------------------------------------------------