1package Mail::DMARC::Report; 2our $VERSION = '1.20190308'; # VERSION 3use strict; 4use warnings; 5 6use Carp; 7use IO::Compress::Gzip; 8use IO::Compress::Zip; 9 10use parent 'Mail::DMARC::Base'; 11 12require Mail::DMARC::Report::Aggregate; 13require Mail::DMARC::Report::Send; 14require Mail::DMARC::Report::Store; 15require Mail::DMARC::Report::Receive; 16require Mail::DMARC::Report::URI; 17 18sub compress { 19 my ( $self, $xml_ref ) = @_; 20 croak "xml is not a reference!" if 'SCALAR' ne ref $xml_ref; 21 my $shrunk; 22 my $zipper = { 23 gz => \&IO::Compress::Gzip::gzip, # 2013 draft 24 zip => \&IO::Compress::Zip::zip, # legacy format 25 }; 26# WARNING: changes here MAY require updates in SMTP::assemble_message 27# my $cf = ( time > 1372662000 ) ? 'gz' : 'zip'; # gz after 7/1/13 28 my $cf = 'gz'; 29 $zipper->{$cf}->( $xml_ref, \$shrunk ) or croak "unable to compress: $!"; 30 return $shrunk; 31} 32 33sub init { 34 my $self = shift; 35 delete $self->{dmarc}; 36 delete $self->{aggregate}; 37 return; 38} 39 40sub aggregate { 41 my $self = shift; 42 return $self->{aggregate} if ref $self->{aggregate}; 43 return $self->{aggregate} = Mail::DMARC::Report::Aggregate->new(); 44} 45 46sub dmarc { 47 my $self = shift; 48 return $self->{dmarc}; 49} 50 51sub receive { 52 my $self = shift; 53 return $self->{receive} if ref $self->{receive}; 54 return $self->{receive} = Mail::DMARC::Report::Receive->new; 55} 56 57sub sendit { 58 my $self = shift; 59 return $self->{sendit} if ref $self->{sendit}; 60 return $self->{sendit} = Mail::DMARC::Report::Send->new(); 61} 62 63sub store { 64 my $self = shift; 65 return $self->{store} if ref $self->{store}; 66 return $self->{store} = Mail::DMARC::Report::Store->new(); 67} 68 69sub uri { 70 my $self = shift; 71 return $self->{uri} if ref $self->{uri}; 72 return $self->{uri} = Mail::DMARC::Report::URI->new(); 73} 74 75sub save_aggregate { 76 my $self = shift; 77 return $self->store->backend->save_aggregate( $self->aggregate ); 78} 79 801; 81 82# ABSTRACT: A DMARC report interface 83 84=pod 85 86=head1 NAME 87 88Mail::DMARC::Report - A DMARC report interface 89 90=head1 VERSION 91 92version 1.20190308 93 94=head1 DESCRIPTION 95 96DMARC reports are information that a DMARC implementing Mail Transfer Agent (MTA) sends to Author Domains and also something that an Author Domain owner receives from other DMARC implementing MTAs. Mail::DMARC supports both roles, as a sender and a receiver. 97 98There are two report types, L<aggregate|Mail::DMARC::Report::Aggregate> and forensic. 99 100=head1 Aggregate Reports 101 102See L<Mail::DMARC::Report::Aggregate> 103 104=head2 Forensic Reports 105 106TODO 107 108=head2 Report Sender 109 110See L<Mail::DMARC::Report::Send> 111 112 1. store reports 113 2. bundle aggregated reports 114 3. format report in XML 115 4. gzip the XML 116 5. deliver report to Author Domain 117 118=head2 Report Receiver 119 120See L<Mail::DMARC::Report::Receive> 121 122 1. accept reports via HTTP or SMTP 123 2. parse the compressed XML message 124 3. store the report 125 4. present stored data 126 127=head2 Verify External Destinations 128 129 1. Extract the host portion of the authority component of the URI. 130 Call this the "destination host". 131 132 2. Prepend the string "_report._dmarc". 133 134 3. Prepend the domain name from which the policy was retrieved. 135 136 4. Query the DNS for a TXT record at the constructed name. If the 137 result of this request is a temporary DNS error of some kind 138 (e.g., a timeout), the Mail Receiver MAY elect to temporarily 139 fail the delivery so the verification test can be repeated later. 140 141 5. If the result includes no TXT resource records or multiple TXT 142 resource records, a positive determination of the external 143 reporting relationship cannot be made; stop. 144 145 6. Parse the result, if any, as a series of "tag=value" pairs, i.e., 146 the same overall format as the policy record. In particular, the 147 "v=DMARC1" tag is mandatory and MUST appear first in the list. 148 If at least that tag is present and the record overall is 149 syntactically valid per Section 6.3, then the external reporting 150 arrangement was authorized by the destination ADMD. 151 152 7. If a "rua" or "ruf" tag is thus discovered, replace the 153 corresponding value extracted from the domain's DMARC policy 154 record with the one found in this record. This permits the 155 report receiver to override the report destination. However, to 156 prevent loops or indirect abuse, the overriding URI MUST use the 157 same destination host from the first step. 158 159=head1 ERROR REPORTS 160 16112.2.4. Error Reports 162 163When a Mail Receiver is unable to complete delivery of a report via 164any of the URIs listed by the Domain Owner, the Mail Receiver SHOULD 165generate an error message. An attempt MUST be made to send this 166report to all listed "mailto" URIs and MAY also be sent to any or all 167other listed URIs. 168 169The error report MUST be formatted per [MIME]. A text/plain part 170MUST be included that contains field-value pairs such as those found 171in Section 2 of [DSN]. The fields required, which may appear in any 172order, are: 173 174Report-Date: A [MAIL]-formatted date expression indicating when the transport failure occurred. 175 176Report-Domain: The domain-name about which the failed report was generated. 177 178Report-ID: The Report-ID: that the report tried to use. 179 180Report-Size: The size, in bytes, of the report that was unable to be 181 sent. This MUST represent the number of bytes that the Mail 182 Receiver attempted to send. Where more than one transport system 183 was attempted, the sizes may be different; in such cases, separate 184 error reports MUST be generated so that this value matches the 185 actual attempt that was made. For example, a "mailto" error 186 report would be sent to the "mailto" URIs with one size, while the 187 "https" reports might be POSTed to those URIs with a different 188 size, as they have different transport and encoding requirements. 189 190Submitter: The domain-name representing the Mail Receiver that generated, but was unable to submit, the report. 191 192Submitting-URI: The URI(s) to which the Mail Receiver tried, but failed, to submit the report. 193 194An additional text/plain part MAY be included that gives a human- 195readable explanation of the above, and MAY also include a URI that 196can be used to seek assistance. 197 198[NOTE: A more rigorous syntax specification, including ABNF and 199possible registration of a new media type, will be added here when 200more operational experience is acquired.] 201 202=head1 AFRF reports 203 204=head1 IODEF reports 205 206https://datatracker.ietf.org/doc/draft-kucherawy-dmarc-base/?include_text=1 207 208Section 3.5 Out of Scope: 209 210 This first version of DMARC supports only a single reporting format. 211 212=head1 AUTHORS 213 214=over 4 215 216=item * 217 218Matt Simerson <msimerson@cpan.org> 219 220=item * 221 222Davide Migliavacca <shari@cpan.org> 223 224=back 225 226=head1 COPYRIGHT AND LICENSE 227 228This software is copyright (c) 2018 by Matt Simerson. 229 230This is free software; you can redistribute it and/or modify it under 231the same terms as the Perl 5 programming language system itself. 232 233=cut 234 235__END__ 236sub {} 237 238