|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Mail::Milter::Authentication::Handler::SPF;  | 
| 
2
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
9452
 | 
 use 5.20.0;  | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
231
 | 
    | 
| 
3
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
294
 | 
 use strict;  | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
127
 | 
    | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
944
 | 
    | 
| 
4
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
354
 | 
 use warnings;  | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
131
 | 
    | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1108
 | 
    | 
| 
5
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
287
 | 
 use Mail::Milter::Authentication::Pragmas;  | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
151
 | 
    | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
353
 | 
    | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ABSTRACT: Handler class for SPF  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '3.20230629'; # VERSION  | 
| 
8
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
9419
 | 
 use base 'Mail::Milter::Authentication::Handler';  | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
130
 | 
    | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4381
 | 
    | 
| 
9
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
414
 | 
 use Mail::SPF;  | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
128
 | 
    | 
| 
 
 | 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64048
 | 
    | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub default_config {  | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return {  | 
| 
13
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
         'hide_received-spf_header' => 0,  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'hide_none'                => 0,  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'best_guess'               => 0,  | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub grafana_rows {  | 
| 
20
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ( $self ) = @_;  | 
| 
21
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my @rows;  | 
| 
22
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     push @rows, $self->get_json( 'SPF_metrics' );  | 
| 
23
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return \@rows;  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub setup_callback {  | 
| 
27
 | 
142
 | 
 
 | 
 
 | 
  
142
  
 | 
  
0
  
 | 
680
 | 
     my ( $self ) = @_;  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $self->set_object_maker( 'spf_server' , sub {  | 
| 
30
 | 
56
 | 
 
 | 
 
 | 
  
56
  
 | 
 
 | 
198
 | 
         my ( $self, $name ) = @_;  | 
| 
31
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
183
 | 
         my $thischild = $self->{'thischild'};  | 
| 
32
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
433
 | 
         $self->dbgout( 'Object created', $name, LOG_DEBUG );  | 
| 
33
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
246
 | 
         my $object;  | 
| 
34
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
301
 | 
         eval {  | 
| 
35
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
631
 | 
             my $resolver = $self->get_object('resolver');  | 
| 
36
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
675
 | 
             $object = Mail::SPF::Server->new(  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 'hostname'     => $self->get_my_hostname(),  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 'dns_resolver' => $resolver,  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             );  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         };  | 
| 
41
 | 
56
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
29107
 | 
         if ( my $error = $@ ) {  | 
| 
42
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $self->handle_exception( $error );  | 
| 
43
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $self->log_error( 'SPF Object Setup Error ' . $error );  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
45
 | 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
427
 | 
         $thischild->{'object'}->{$name} = {  | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'object'  => $object,  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'destroy' => 0,  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         };  | 
| 
49
 | 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3291
 | 
     });  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub register_metrics {  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return {  | 
| 
54
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
  
1
  
 | 
296
 | 
         'spf_total'      => 'The number of emails processed for SPF',  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub wrap_header {  | 
| 
59
 | 
100
 | 
 
 | 
 
 | 
  
100
  
 | 
  
0
  
 | 
407
 | 
     my ( $self, $value ) = @_;  | 
| 
60
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
803
 | 
     $value =~ s/ /\n    /;  | 
| 
61
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
793
 | 
     $value =~ s/\) /\)\n    /;  | 
| 
62
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
810
 | 
     $value =~ s/; /;\n    /g;  | 
| 
63
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
383
 | 
     return $value;  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub helo_callback {  | 
| 
67
 | 
114
 | 
 
 | 
 
 | 
  
114
  
 | 
  
0
  
 | 
644
 | 
     my ( $self, $helo_host ) = @_;  | 
| 
68
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
615
 | 
     $self->{'failmode'} = 0;  | 
| 
69
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
544
 | 
     $self->{'helo_name'} = $helo_host;  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub envfrom_callback {  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # On MAILFROM  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #...  | 
| 
76
 | 
114
 | 
 
 | 
 
 | 
  
114
  
 | 
  
0
  
 | 
737
 | 
     my ( $self, $env_from ) = @_;  | 
| 
77
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
750
 | 
     my $config = $self->handler_config();  | 
| 
78
 | 
114
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
995
 | 
     return if ( $self->is_local_ip_address() );  | 
| 
79
 | 
106
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
766
 | 
     return if ( $self->is_trusted_ip_address() );  | 
| 
80
 | 
104
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
814
 | 
     return if ( $self->is_authenticated() );  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
82
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
992
 | 
     my $spf_server = $self->get_object('spf_server');  | 
| 
83
 | 
104
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
540
 | 
     if ( ! $spf_server ) {  | 
| 
84
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->log_error( 'SPF Setup Error' );  | 
| 
85
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->metric_count( 'spf_total', { 'result' => 'error' } );  | 
| 
86
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         my $header = Mail::AuthenticationResults::Header::Entry->new()->set_key( 'spf' )->safe_set_value( 'temperror' );  | 
| 
87
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->add_auth_header($header);  | 
| 
88
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return;  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
91
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
484
 | 
     my $scope = 'mfrom';  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
93
 | 
104
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
461
 | 
     $env_from = q{} if $env_from eq '<>';  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
95
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
335
 | 
     my $identity;  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $domain;  | 
| 
97
 | 
104
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
387
 | 
     if ( !$env_from ) {  | 
| 
98
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
         $identity = $self->{'helo_name'};  | 
| 
99
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
         $domain   = $identity;  | 
| 
100
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
         $scope    = 'helo';  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else {  | 
| 
103
 | 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
798
 | 
         $identity = $self->get_address_from($env_from);  | 
| 
104
 | 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
805
 | 
         $domain   = $self->get_domain_from($identity);  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
107
 | 
104
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
630
 | 
     if ( !$identity ) {  | 
| 
108
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $identity = $self->{'helo_name'};  | 
| 
109
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $domain   = $identity;  | 
| 
110
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $scope    = 'helo';  | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
113
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
294
 | 
     eval {  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $spf_request = Mail::SPF::Request->new(  | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'versions'      => [1],  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'scope'         => $scope,  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'identity'      => $identity,  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'ip_address'    => $self->ip_address(),  | 
| 
119
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
856
 | 
             'helo_identity' => $self->{'helo_name'},  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         );  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
122
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
139236
 | 
         my $spf_result = $spf_server->process($spf_request);  | 
| 
123
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1523024
 | 
         my $spf_results = $self->get_object('spf_results');  | 
| 
124
 | 
104
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
650
 | 
         $spf_results = [] if ! $spf_results;  | 
| 
125
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
385
 | 
         push @$spf_results, $spf_result;  | 
| 
126
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
882
 | 
         $self->set_object('spf_results',$spf_results,1);  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
128
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
809
 | 
         my $result_code = $spf_result->code();  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Best Guess SPF based on org domain  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # ToDo report this in both metrics and AR header  | 
| 
132
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
341
 | 
         my $auth_domain;  | 
| 
133
 | 
104
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
567
 | 
         if ( $result_code eq 'none' ) {  | 
| 
134
 | 
14
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
75
 | 
             if ( $config->{'best_guess'} ) {  | 
| 
135
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 if ( $self->is_handler_loaded( 'DMARC' ) ) {  | 
| 
136
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     my $dmarc_handler = $self->get_handler('DMARC');  | 
| 
137
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     my $dmarc_object = $dmarc_handler->get_dmarc_object();  | 
| 
138
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     if ( $domain ) {  | 
| 
139
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         my $org_domain = eval{ $dmarc_object->get_organizational_domain( $domain ); };  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
140
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         $self->handle_exception( $@ );  | 
| 
141
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         if ( $org_domain ne $domain ) {  | 
| 
142
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                             $auth_domain = $org_domain;  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $spf_request = Mail::SPF::Request->new(  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'versions'         => [1],  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'scope'            => $scope,  | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'identity'         => $identity,  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'authority_domain' => $org_domain,  | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'ip_address'       => $self->ip_address(),  | 
| 
149
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                                 'helo_identity'    => $self->{'helo_name'},  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             );  | 
| 
151
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                             $spf_result = $spf_server->process($spf_request);  | 
| 
152
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                             my $spf_results = $self->get_object('spf_results');  | 
| 
153
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                             $spf_results = [] if ! $spf_results;  | 
| 
154
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                             push @$spf_results, $spf_result;  | 
| 
155
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                             $self->set_object('spf_results',$spf_results,1);  | 
| 
156
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                             $result_code = $spf_result->code();  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         }  | 
| 
158
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
163
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1087
 | 
         $self->metric_count( 'spf_total', { 'result' => $result_code } );  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
165
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1894
 | 
         my $header = Mail::AuthenticationResults::Header::Entry->new()->set_key( 'spf' )->safe_set_value( $result_code );  | 
| 
166
 | 
104
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
9954
 | 
         if ( $auth_domain ) {  | 
| 
167
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $header->add_child( Mail::AuthenticationResults::Header::SubEntry->new()->set_key( 'policy.authdomain' )->safe_set_value( $auth_domain ) );  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
169
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1028
 | 
         $header->add_child( Mail::AuthenticationResults::Header::SubEntry->new()->set_key( 'smtp.mailfrom' )->safe_set_value( $self->get_address_from( $env_from ) ) );  | 
| 
170
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10337
 | 
         $header->add_child( Mail::AuthenticationResults::Header::SubEntry->new()->set_key( 'smtp.helo' )->safe_set_value( $self->{ 'helo_name' } ) );  | 
| 
171
 | 
104
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
11235
 | 
         if ( !( $config->{'hide_none'} && $result_code eq 'none' ) ) {  | 
| 
172
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
871
 | 
             $self->add_auth_header($header);  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Set for DMARC  | 
| 
176
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
543
 | 
         $self->{'dmarc_domain'} = $domain;  | 
| 
177
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
461
 | 
         $self->{'dmarc_scope'}  = $scope;  | 
| 
178
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
439
 | 
         $self->{'dmarc_result'} = $result_code;  | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
180
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
583
 | 
         $self->dbgout( 'SPFCode', $result_code, LOG_DEBUG );  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
104
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
944
 | 
         if ( !( $config->{'hide_received-spf_header'} ) ) {  | 
| 
183
 | 
104
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
1143
 | 
             if ( !( $config->{'hide_none'} && $result_code eq 'none' ) ) {  | 
| 
184
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
986
 | 
                 my $result_header = $spf_result->received_spf_header();  | 
| 
185
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88925
 | 
                 my ( $header, $value ) = split( ': ', $result_header, 2 );  | 
| 
186
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
710
 | 
                 $value = $self->wrap_header( $value );  | 
| 
187
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
989
 | 
                 $self->prepend_header( $header, $value );  | 
| 
188
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
565
 | 
                 $self->dbgout( 'SPFHeader', $result_header, LOG_DEBUG );  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
192
 | 
104
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1117
 | 
     if ( my $error = $@ ) {  | 
| 
193
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->handle_exception( $error );  | 
| 
194
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->log_error( 'SPF Error ' . $error );  | 
| 
195
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->{'failmode'} = 1;  | 
| 
196
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         my $header = Mail::AuthenticationResults::Header::Entry->new()->set_key( 'spf' )->safe_set_value( 'temperror' );  | 
| 
197
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->add_auth_header($header);  | 
| 
198
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $self->metric_count( 'spf_total', { 'result' => 'error' } );  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub close_callback {  | 
| 
203
 | 
118
 | 
 
 | 
 
 | 
  
118
  
 | 
  
0
  
 | 
369
 | 
     my ( $self ) = @_;  | 
| 
204
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
449
 | 
     delete $self->{'dmarc_domain'};  | 
| 
205
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
341
 | 
     delete $self->{'dmarc_scope'};  | 
| 
206
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
324
 | 
     delete $self->{'dmarc_result'};  | 
| 
207
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
336
 | 
     delete $self->{'failmode'};  | 
| 
208
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
332
 | 
     delete $self->{'helo_name'};  | 
| 
209
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
626
 | 
     $self->destroy_object('spf_results');  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =pod  | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =encoding UTF-8  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Mail::Milter::Authentication::Handler::SPF - Handler class for SPF  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 VERSION  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 version 3.20230629  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION  | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Implements the SPF standard checks.  | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 CONFIGURATION  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         "SPF" : {                                       | Config for the SPF Module  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             "hide_received-spf_header" : 0,             | Do not add the "Received-SPF" header  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             "hide_none"                : 0,             | Hide auth line if the result is 'none'  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                                         | if not hidden at all  | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             "best_guess"               : 0              | Fallback to Org domain for SPF checks  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                                         | if result is none.  | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         },  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 AUTHOR  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Marc Bradshaw <marc@marcbradshaw.net>  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 COPYRIGHT AND LICENSE  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This software is copyright (c) 2020 by Marc Bradshaw.  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This is free software; you can redistribute it and/or modify it under  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the same terms as the Perl 5 programming language system itself.  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  |