Domain: pinupdatabase.com Server Adress: 208.122.217.104
privdayz.com / sbin /
Current File : //sbin/opendmarc-reports
#!/usr/bin/perl
#
# Copyright (c) 2012-2016, 2017-2018, The Trusted Domain Project.
# All rights reserved.
#
# Script to generate regular DMARC reports.
###
### Setup
###
use strict;
use warnings;
use Switch;
use DBI;
use File::Basename;
use File::Temp;
use Net::Domain qw(hostfqdn hostdomain);
use Getopt::Long;
use IO::Handle;
use IO::Compress::Zip qw(zip);
use POSIX;
use MIME::Base64;
use Net::SMTP;
use Time::Local;
require DBD::mysql;
require HTTP::Request;
# general
my $progname = basename($0);
my $version = "1.4.2";
my $verbose = 0;
my $helponly = 0;
my $showversion = 0;
my $interval;
my $gen;
my $uri;
my $buf;
my $mailout;
my $boundary;
my $tmpout;
my $repfile;
my $zipfile;
my $zipin;
my $now = time();
my $repstart;
my $repend;
my $domain;
my $domainid;
my $domainset;
my $forcedomain;
my @skipdomains;
my $policy;
my $spolicy;
my $policystr;
my $spolicystr;
my $pct;
my $repuri;
my @repuris;
my $lastsent;
my $aspf;
my $aspfstr;
my $adkim;
my $adkimstr;
my $align_dkim;
my $align_dkimstr;
my $align_spf;
my $align_spfstr;
my $spfresult;
my $dkimresult;
my $disp;
my $spfresultstr;
my $dkimresultstr;
my $dispstr;
my $ipaddr;
my $fromdomain;
my $envdomain;
my $dkimdomain;
my $dkimselector;
my $arc;
my $arcstr;
my $arcpolicy;
my $arcpolicystr;
my $repdest;
my $smtpstatus;
my $smtpfail;
my $doupdate = 1;
my $testmode = 0;
my $keepfiles = 0;
my $use_utc = 0;
my $daybound = 0;
my $report_maxbytes_global = 15728640; # default: 15M, per spec
my $msgid;
my $rowcount;
my $dbi_h;
my $dbi_s;
my $dbi_s2;
my $dbi_a;
my $dbi_hash;
# DB parameters
my $def_dbhost = "localhost";
my $def_dbname = "opendmarc";
my $def_dbuser = "opendmarc";
my $def_dbpasswd = "opendmarc";
my $def_dbport = "3306";
my $def_interval = "86400";
my $dbhost;
my $dbname;
my $dbuser;
my $dbpasswd;
my $dbport;
my $dbscheme = "mysql";
my $repdom = hostdomain();
my $repemail = "postmaster@" . $repdom;
my $smtp_server = '127.0.0.1';
my $smtp_port = 25;
my $smtp;
my $answer;
###
### NO user-serviceable parts beyond this point
###
sub usage
{
print STDERR "$progname: usage: $progname [options]\n";
print STDERR "\t--day send yesterday's data\n";
print STDERR "\t--dbhost=host database host [$def_dbhost]\n";
print STDERR "\t--dbname=name database name [$def_dbname]\n";
print STDERR "\t--dbpasswd=passwd database password [$def_dbpasswd]\n";
print STDERR "\t--dbport=port database port [$def_dbport]\n";
print STDERR "\t--dbuser=user database user [$def_dbuser]\n";
print STDERR "\t--domain=name force a report for named domain\n";
print STDERR "\t--help print help and exit\n";
print STDERR "\t--interval=secs report interval [$def_interval]\n";
print STDERR "\t--keepfiles keep xml files (in local directory)\n";
print STDERR "\t -n synonym for --test\n";
print STDERR "\t--nodomain=name omit a report for named domain\n";
print STDERR "\t--noupdate don't record report transmission\n";
print STDERR "\t--report-email reporting contact [$repemail]\n";
print STDERR "\t--report-org reporting organization [$repdom]\n";
print STDERR "\t--smtp-port smtp server port [$smtp_port]\n";
print STDERR "\t--smtp-server smtp server [$smtp_server]\n";
print STDERR "\t--test don't send reports\n";
print STDERR "\t (implies --keepfiles --noupdate)\n";
print STDERR "\t--utc operate in UTC\n";
print STDERR "\t--verbose verbose output\n";
print STDERR "\t (repeat for increased output)\n";
print STDERR "\t--version print version and exit\n";
}
# set locale
setlocale(LC_ALL, 'C');
# parse command line arguments
my $opt_retval = &Getopt::Long::GetOptions ('day!' => \$daybound,
'dbhost=s' => \$dbhost,
'dbname=s' => \$dbname,
'dbpasswd=s' => \$dbpasswd,
'dbport=s' => \$dbport,
'dbuser=s' => \$dbuser,
'domain=s' => \$forcedomain,
'help!' => \$helponly,
'interval=i' => \$interval,
'keepfiles' => \$keepfiles,
'n|test' => \$testmode,
'nodomain=s' => \@skipdomains,
'report-email=s' => \$repemail,
'report-org=s' => \$repdom,
'smtp-server=s' => \$smtp_server,
'smtp-port=i' => \$smtp_port,
'update!' => \$doupdate,
'utc!' => \$use_utc,
'verbose+' => \$verbose,
'version!' => \$showversion,
);
if (!$opt_retval || $helponly)
{
usage();
if ($helponly)
{
exit(0);
}
else
{
exit(1);
}
}
if ($showversion)
{
print STDOUT "$progname v$version\n";
exit(0);
}
# apply defaults
if (!defined($dbhost))
{
if (defined($ENV{'OPENDMARC_DBHOST'}))
{
$dbhost = $ENV{'OPENDMARC_DBHOST'};
}
else
{
$dbhost = $def_dbhost;
}
}
if (!defined($dbname))
{
if (defined($ENV{'OPENDMARC_DB'}))
{
$dbname = $ENV{'OPENDMARC_DB'};
}
else
{
$dbname = $def_dbname;
}
}
if (!defined($dbpasswd))
{
if (defined($ENV{'OPENDMARC_PASSWORD'}))
{
$dbpasswd = $ENV{'OPENDMARC_PASSWORD'};
}
else
{
$dbpasswd = $def_dbpasswd;
}
}
if (!defined($dbport))
{
if (defined($ENV{'OPENDMARC_PORT'}))
{
$dbport = $ENV{'OPENDMARC_PORT'};
}
else
{
$dbport = $def_dbport;
}
}
if (!defined($dbuser))
{
if (defined($ENV{'OPENDMARC_USER'}))
{
$dbuser = $ENV{'OPENDMARC_USER'};
}
else
{
$dbuser = $def_dbuser;
}
}
if (defined($interval) && $daybound)
{
print STDERR "$progname: WARN: --day overrides --interval\n";
}
if (!defined($interval) || $daybound)
{
$interval = $def_interval;
}
# Test mode requested, don't update last sent and keep xml files
$doupdate = ($testmode == 1) ? 0 : $doupdate;
$keepfiles = ($testmode == 1) ? 1 : $keepfiles;
if ($verbose)
{
print STDERR "$progname: started at " . localtime($now) . "\n";
}
my $dbi_dsn = "DBI:" . $dbscheme . ":database=" . $dbname .
";host=" . $dbhost . ";port=" . $dbport;
$dbi_h = DBI->connect($dbi_dsn, $dbuser, $dbpasswd, { PrintError => 0 });
if (!defined($dbi_h))
{
print STDERR "$progname: unable to connect to database: $DBI::errstr\n";
exit(1);
}
if ($verbose >= 2)
{
print STDERR "$progname: connected to database\n";
}
if ($use_utc)
{
$dbi_s = $dbi_h->prepare("SET TIME_ZONE='+00:00'");
if (!$dbi_s->execute())
{
print STDERR "$progname: failed to change to UTC: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
}
#
# Select domains on which to report
#
if ($verbose >= 2)
{
print STDERR "$progname: selecting target domains\n";
}
if (defined($forcedomain))
{
$dbi_s = $dbi_h->prepare("SELECT name FROM domains WHERE name = ?");
if (!$dbi_s->execute($forcedomain))
{
print STDERR "$progname: failed to test for database entry: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
}
elsif ($daybound)
{
$dbi_s = $dbi_h->prepare("SELECT domains.name FROM requests JOIN domains ON requests.domain = domains.id WHERE DATE(lastsent) < DATE(FROM_UNIXTIME(?))");
if (!$dbi_s->execute($now))
{
print STDERR "$progname: failed to collect domain names: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
}
else
{
$dbi_s = $dbi_h->prepare("SELECT domains.name FROM requests JOIN domains ON requests.domain = domains.id WHERE lastsent <= DATE_SUB(FROM_UNIXTIME(?), INTERVAL ? SECOND)");
if (!$dbi_s->execute($now, $interval))
{
print STDERR "$progname: failed to collect domain names: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
}
$domainset = $dbi_s->fetchall_arrayref([0]);
$dbi_s->finish;
if ($verbose)
{
print STDERR "$progname: selected " . scalar(@$domainset) . " domain(s)\n";
}
#
# For each domain:
# -- extract reporting address
# -- extract messages/signatures to report
# -- generate and send report
# -- update "last sent" timestamp
#
$smtp = Net::SMTP->new($smtp_server,
'Port' => $smtp_port,
'Hello' => hostfqdn());
if (!defined($smtp))
{
print STDERR "$progname: open SMTP server $smtp_server:$smtp_port failed\n";
exit(1);
}
foreach (@$domainset)
{
$domain = $_->[0];
if (!defined($domain))
{
next;
}
if (@skipdomains && grep({$_ eq $domain} @skipdomains) != 0)
{
next;
}
if ($verbose >= 2)
{
print STDERR "$progname: processing $domain\n";
}
# extract this domain's reporting parameters
$dbi_s = $dbi_h->prepare("SELECT id FROM domains WHERE name = ?");
if (!$dbi_s->execute($domain))
{
print STDERR "$progname: can't get ID for domain $domain: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
undef $domainid;
while ($dbi_a = $dbi_s->fetchrow_arrayref())
{
if (defined($dbi_a->[0]))
{
$domainid = $dbi_a->[0];
}
}
$dbi_s->finish;
if (!defined($domainid))
{
print STDERR "$progname: ID for domain $domain not found\n";
next;
}
$dbi_s = $dbi_h->prepare("SELECT repuri, adkim, aspf, policy, spolicy, pct, UNIX_TIMESTAMP(lastsent) FROM requests WHERE domain = ?");
if (!$dbi_s->execute($domainid))
{
print STDERR "$progname: can't get reporting URI for domain $domain: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
undef $repuri;
while ($dbi_a = $dbi_s->fetchrow_arrayref())
{
if (defined($dbi_a->[0]))
{
$repuri = $dbi_a->[0];
}
if (defined($dbi_a->[1]))
{
$adkim = $dbi_a->[1];
}
if (defined($dbi_a->[2]))
{
$aspf = $dbi_a->[2];
}
if (defined($dbi_a->[3]))
{
$policy = $dbi_a->[3];
}
if (defined($dbi_a->[4]))
{
$spolicy = $dbi_a->[4];
}
if (defined($dbi_a->[5]))
{
$pct = $dbi_a->[5];
}
if (defined($dbi_a->[6]))
{
$lastsent = $dbi_a->[6];
}
}
$dbi_s->finish;
if (!defined($repuri) || ("" eq $repuri))
{
if ($verbose >= 2)
{
print STDERR "$progname: no reporting URI for domain $domain; skipping\n";
}
next;
}
if ($daybound)
{
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now - $interval);
$repstart = timelocal(0, 0, 0, $mday, $mon, $year);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
$repend = timelocal(0, 0, 0, $mday, $mon, $year);
}
else
{
$repstart = $now - $interval;
$repend = $now;
}
# construct the temporary file
$repfile = $repdom . "!" . $domain . "!" . $repstart . "!" . $repend . ".xml";
$zipfile = $repdom . "!" . $domain . "!" . $repstart . "!" . $repend . ".zip";
if (!open($tmpout, ">", $repfile))
{
print STDERR "$progname: can't create report file for domain $domain\n";
next;
}
switch ($adkim)
{
case ord("r") { $adkimstr = "r"; }
case ord("s") { $adkimstr = "s"; }
else { $adkimstr = "unknown"; }
}
switch ($aspf)
{
case ord("r") { $aspfstr = "r"; }
case ord("s") { $aspfstr = "s"; }
else { $aspfstr = "unknown"; }
}
switch ($policy)
{
case ord("n") { $policystr = "none"; }
case ord("q") { $policystr = "quarantine"; }
case ord("r") { $policystr = "reject"; }
else { $policystr = "unknown"; }
}
switch ($spolicy)
{
case 0 { $spolicystr = $policystr; }
case ord("n") { $spolicystr = "none"; }
case ord("q") { $spolicystr = "quarantine"; }
case ord("r") { $spolicystr = "reject"; }
else { $spolicystr = "unknown"; }
}
print $tmpout "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
print $tmpout "<feedback>\n";
print $tmpout " <report_metadata>\n";
print $tmpout " <org_name>$repdom</org_name>\n";
print $tmpout " <email>$repemail</email>\n";
print $tmpout " <report_id>$domain:$now</report_id>\n";
print $tmpout " <date_range>\n";
print $tmpout " <begin>$repstart</begin>\n";
print $tmpout " <end>$repend</end>\n";
print $tmpout " </date_range>\n";
print $tmpout " </report_metadata>\n";
print $tmpout " <policy_published>\n";
print $tmpout " <domain>$domain</domain>\n";
print $tmpout " <adkim>$adkimstr</adkim>\n";
print $tmpout " <aspf>$aspfstr</aspf>\n";
print $tmpout " <p>$policystr</p>\n";
print $tmpout " <sp>$spolicystr</sp>\n";
print $tmpout " <pct>$pct</pct>\n";
print $tmpout " </policy_published>\n";
if ($daybound)
{
$dbi_s = $dbi_h->prepare(q{
SELECT messages.id, ipaddr.addr, messages.disp, d1.name, d2.name,
messages.spf, messages.align_spf, messages.align_dkim,
messages.arc, messages.arc_policy
FROM messages
JOIN ipaddr ON messages.ip = ipaddr.id
JOIN domains d1 ON messages.from_domain = d1.id
JOIN domains d2 ON messages.env_domain = d2.id
WHERE messages.from_domain = ?
AND DATE(messages.date) >= DATE(FROM_UNIXTIME(?))
AND DATE(messages.date) < DATE(FROM_UNIXTIME(?))
});
}
else
{
$dbi_s = $dbi_h->prepare(q{
SELECT messages.id, ipaddr.addr, messages.disp, d1.name, d2.name,
messages.spf, messages.align_spf, messages.align_dkim,
messages.arc, messages.arc_policy
FROM messages
JOIN ipaddr ON messages.ip = ipaddr.id
JOIN domains d1 ON messages.from_domain = d1.id
JOIN domains d2 ON messages.env_domain = d2.id
WHERE messages.from_domain = ?
AND messages.date > FROM_UNIXTIME(?)
AND messages.date <= FROM_UNIXTIME(?)
});
}
if (!$dbi_s->execute($domainid, $repstart, $repend))
{
print STDERR "$progname: can't extract report for domain $domain: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
$rowcount = 0;
while ($dbi_a = $dbi_s->fetchrow_arrayref())
{
undef $msgid;
if (defined($dbi_a->[0]))
{
$msgid = $dbi_a->[0];
}
if (defined($dbi_a->[1]))
{
$ipaddr = $dbi_a->[1];
}
if (defined($dbi_a->[2]))
{
$disp = $dbi_a->[2];
}
if (defined($dbi_a->[3]))
{
$fromdomain = $dbi_a->[3];
}
if (defined($dbi_a->[4]))
{
$envdomain = $dbi_a->[4];
}
if (defined($dbi_a->[5]))
{
$spfresult = $dbi_a->[5];
}
if (defined($dbi_a->[6]))
{
$align_spf = $dbi_a->[6];
}
if (defined($dbi_a->[7]))
{
$align_dkim = $dbi_a->[7];
}
if (defined($dbi_a->[8]))
{
$arc = $dbi_a->[8];
}
if (defined($dbi_a->[9]))
{
$arcpolicy = $dbi_a->[9];
}
if (!defined($msgid))
{
next;
}
$rowcount++;
switch ($disp)
{
case 0 { $dispstr = "reject"; }
case 1 { $dispstr = "reject"; }
case 2 { $dispstr = "none"; }
case 4 { $dispstr = "quarantine"; }
else { $dispstr = "unknown"; }
}
switch ($spfresult)
{
case 0 { $spfresultstr = "pass"; }
case 2 { $spfresultstr = "softfail"; }
case 3 { $spfresultstr = "neutral"; }
case 4 { $spfresultstr = "temperror"; }
case 5 { $spfresultstr = "permerror"; }
case 6 { $spfresultstr = "none"; }
case 7 { $spfresultstr = "fail"; }
case 8 { $spfresultstr = "policy"; }
case 9 { $spfresultstr = "nxdomain"; }
case 10 { $spfresultstr = "signed"; }
case 12 { $spfresultstr = "discard"; }
else { $spfresultstr = "unknown"; }
}
switch ($align_dkim)
{
case 4 { $align_dkimstr = "pass"; }
case 5 { $align_dkimstr = "fail"; }
else { $align_dkimstr = "unknown"; }
}
switch ($align_spf)
{
case 4 { $align_spfstr = "pass"; }
case 5 { $align_spfstr = "fail"; }
else { $align_spfstr = "unknown"; }
}
switch ($arc)
{
case 1 { $arcstr = "pass"; }
else { $arcstr = "fail"; }
}
switch ($arcpolicy)
{
case 0 { $arcpolicystr = "pass"; }
else { $arcpolicystr = "fail"; }
}
# retrieve arc_policy seals, join arcauthresults.arc_client_addr (smtp.client_ip)
$dbi_s2 = $dbi_h->prepare(q{
SELECT arcseals.instance, domains.name AS domain,
selectors.name AS selector,
arcauthresults.arc_client_addr as client_ip
FROM arcseals
JOIN domains on arcseals.domain = domains.id
JOIN selectors on arcseals.selector = selectors.id
JOIN arcauthresults on arcseals.message = arcauthresults.message
AND arcseals.instance = arcauthresults.instance
WHERE arcseals.message = ?
ORDER BY arcseals.instance DESC
});
if (!$dbi_s2->execute($msgid))
{
print STDERR "$progname: can't extract report for message $msgid: " . $dbi_h->errstr . "\n";
$dbi_s2->finish;
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
my $arc_policy_output = "arc=$arcpolicystr";
while ($dbi_hash = $dbi_s2->fetchrow_hashref())
{
$arc_policy_output .= " as[$dbi_hash->{instance}].d=$dbi_hash->{domain}";
$arc_policy_output .= " as[$dbi_hash->{instance}].s=$dbi_hash->{selector}";
if ($dbi_hash->{instance} == 1 && (defined($dbi_hash->{client_ip}) && $dbi_hash->{client_ip} ne ""))
{
$arc_policy_output .= " client-ip[$dbi_hash->{instance}]=$dbi_hash->{client_ip}";
}
}
$dbi_s2->finish;
print $tmpout " <record>\n";
print $tmpout " <row>\n";
print $tmpout " <source_ip>$ipaddr</source_ip>\n";
print $tmpout " <count>1</count>\n";
print $tmpout " <policy_evaluated>\n";
print $tmpout " <disposition>$dispstr</disposition>\n";
print $tmpout " <dkim>$align_dkimstr</dkim>\n";
print $tmpout " <spf>$align_spfstr</spf>\n";
print $tmpout " <reason>\n";
print $tmpout " <type>local_policy</type>\n";
print $tmpout " <comment>$arc_policy_output</comment>\n";
print $tmpout " </reason>\n";
print $tmpout " </policy_evaluated>\n";
print $tmpout " </row>\n";
print $tmpout " <identifiers>\n";
print $tmpout " <header_from>$fromdomain</header_from>\n";
print $tmpout " </identifiers>\n";
print $tmpout " <auth_results>\n";
print $tmpout " <spf>\n";
print $tmpout " <domain>$envdomain</domain>\n";
print $tmpout " <result>$spfresultstr</result>\n";
print $tmpout " </spf>\n";
$dbi_s2 = $dbi_h->prepare(q{
SELECT domains.name, selectors.name, pass
FROM signatures
JOIN domains ON signatures.domain = domains.id
JOIN selectors ON signatures.selector = selectors.id
WHERE signatures.message = ?
});
if (!$dbi_s2->execute($msgid))
{
print STDERR "$progname: can't extract report for message $msgid: " . $dbi_h->errstr . "\n";
$dbi_s2->finish;
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
my %dkim_domain_result_cache = ();
while ($dbi_a = $dbi_s2->fetchrow_arrayref())
{
undef $dkimdomain;
if (defined($dbi_a->[0]))
{
$dkimdomain = $dbi_a->[0];
}
if (defined($dbi_a->[1]))
{
$dkimselector = $dbi_a->[1];
}
if (defined($dbi_a->[2]))
{
$dkimresult = $dbi_a->[2];
}
if (!defined($dkimdomain))
{
next;
}
if (defined($dkim_domain_result_cache{$dkimdomain}{$dkimselector}{$dkimresult}))
{
next; # no duplicate per-record auth_result dkim sections
}
$dkim_domain_result_cache{$dkimdomain}{$dkimselector}{$dkimresult}++;
switch ($dkimresult)
{
case 0 { $dkimresultstr = "pass"; }
case 2 { $dkimresultstr = "softfail"; }
case 3 { $dkimresultstr = "neutral"; }
case 4 { $dkimresultstr = "temperror"; }
case 5 { $dkimresultstr = "permerror"; }
case 6 { $dkimresultstr = "none"; }
case 7 { $dkimresultstr = "fail"; }
case 8 { $dkimresultstr = "policy"; }
case 9 { $dkimresultstr = "nxdomain"; }
case 10 { $dkimresultstr = "signed"; }
case 12 { $dkimresultstr = "discard"; }
else { $dkimresultstr = "unknown"; }
}
print $tmpout " <dkim>\n";
print $tmpout " <domain>$dkimdomain</domain>\n";
print $tmpout " <selector>$dkimselector</selector>\n";
print $tmpout " <result>$dkimresultstr</result>\n";
print $tmpout " </dkim>\n";
}
$dbi_s2->finish;
print $tmpout " </auth_results>\n";
print $tmpout " </record>\n";
}
$dbi_s->finish;
print $tmpout "</feedback>\n";
close($tmpout);
if ($rowcount == 0)
{
if ($verbose >= 2)
{
print STDERR "$progname: no activity selected for $domain; skipping\n";
}
unlink($repfile);
next;
}
# zip the report
if (!zip [ $repfile ] => $zipfile)
{
print STDERR "$progname: can't zip report for domain $domain: $!\n";
next;
}
if ($keepfiles)
{
print STDERR "$progname: keeping report file \"$repfile\"\n";
}
# decode the URI
@repuris = split(',', $repuri);
for $repuri (@repuris)
{
$uri = URI->new($repuri);
if (!defined($uri) ||
!defined($uri->scheme) ||
$uri->opaque eq "")
{
print STDERR "$progname: can't parse reporting URI for domain $domain\n";
next;
}
$repdest = $uri->opaque;
my $report_maxbytes = $report_maxbytes_global;
# check for max report size
if ($repdest =~ m/^(\S+)!(\d{1,15})([kmgt])?$/i)
{
$repdest = $1;
$report_maxbytes = $2;
if ($3)
{
my $letter = lc($3);
if ($letter eq 'k')
{
$report_maxbytes = $report_maxbytes * 1024;
}
if ($letter eq 'm')
{
$report_maxbytes = $report_maxbytes * 1048576;
}
if ($letter eq 'g')
{
$report_maxbytes = $report_maxbytes * (2**30);
}
if ($letter eq 't')
{
$report_maxbytes = $report_maxbytes * (2**40);
}
}
}
# Test mode, just report what would have been done
if ($testmode)
{
print STDERR "$progname: would email $domain report for " .
"$rowcount records to " . $uri->opaque . "\n";
}
# ensure a scheme is present
elsif (!defined($uri->scheme))
{
if ($verbose >= 2)
{
print STDERR "$progname: unknown URI scheme in '$repuri' for domain $domain\n";
}
next;
}
# send/post report
elsif ($uri->scheme eq "mailto")
{
my $datestr;
my $report_id;
if (!open($zipin, $zipfile))
{
print STDERR "$progname: can't read zipped report for $domain: $!\n";
next;
}
$boundary = "report_section";
$report_id = $domain . "-" . $now . "@" . $repdom;
$datestr = strftime("%a, %e %b %Y %H:%M:%S %z (%Z)",
localtime);
$mailout = "To: $repdest\n";
$mailout .= "From: $repemail\n";
$mailout .= "Subject: Report Domain: " . $domain . " Submitter: " . $repdom . " Report-ID: " . $report_id . "\n";
$mailout .= "X-Mailer: " . $progname . " v" . $version ."\n";
$mailout .= "Date: " . $datestr . "\n";
$mailout .= "Message-ID: <$report_id>\n";
$mailout .= "Auto-Submitted: auto-generated\n";
$mailout .= "MIME-Version: 1.0\n";
$mailout .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\n";
$mailout .= "\n";
$mailout .= "This is a MIME-encapsulated message.\n";
$mailout .= "\n";
$mailout .= "--$boundary\n";
$mailout .= "Content-Type: text/plain;\n";
$mailout .= "\n";
$mailout .= "This is a DMARC aggregate report for $domain\n";
$mailout .= "generated at " . localtime() . "\n";
$mailout .= "\n";
$mailout .= "--$boundary\n";
$mailout .= "Content-Type: application/zip\n";
$mailout .= "Content-Disposition: attachment; filename=\"$zipfile\"\n";
$mailout .= "Content-Transfer-Encoding: base64\n";
$mailout .= "\n";
while (read($zipin, $buf, 60*57))
{
$mailout .= encode_base64($buf);
}
$mailout .= "\n";
$mailout .= "--$boundary--\n";
my $reportsize = length($mailout);
if ($reportsize > $report_maxbytes)
{
# XXX -- generate an error report here
print STDERR "$progname: report was too large ($reportsize bytes) per limitation of URI " . $uri->opaque . " for domain $domain\n";
}
else
{
$smtpstatus = "sent";
$smtpfail = 0;
if (!$smtp->mail($repemail) ||
!$smtp->to($repdest) ||
!$smtp->data() ||
!$smtp->datasend($mailout) ||
!$smtp->dataend())
{
$smtpfail = 1;
$smtpstatus = "failed to send";
}
if ($verbose || $smtpfail)
{
# now perl voodoo:
$answer = ${${*$smtp}{'net_cmd_resp'}}[1] || $smtp->message() || 'unknown error';
chomp($answer);
print STDERR "$progname: $smtpstatus report for $domain to $repdest ($answer)\n";
}
}
$smtp->reset();
close($zipin);
}
else
{
print STDERR "$progname: unsupported reporting URI scheme " . $uri->scheme . " for domain $domain\n";
next;
}
}
# update "last sent" timestamp
if ($doupdate)
{
$dbi_s = $dbi_h->prepare("UPDATE requests SET lastsent = FROM_UNIXTIME(?) WHERE domain = ?");
if (!$dbi_s->execute($repend, $domainid))
{
print STDERR "$progname: can't update last sent time for domain $domain: " . $dbi_h->errstr . "\n";
$dbi_s->finish;
$dbi_h->disconnect;
exit(1);
}
}
unlink($zipfile);
if (!$keepfiles)
{
unlink($repfile);
}
}
$smtp->quit();
#
# all done!
#
$dbi_s->finish;
if ($verbose)
{
print STDERR "$progname: terminating at " . localtime() . "\n";
}
$dbi_h->disconnect;
exit(0);
Pin Up Database - The Pinup Database
Sort By: Pin Up Name Pin Up Group Name City Zip Province Date posted Date last modified
Full Bio
Modern Day Pin Up Magazine features Pin Ups from around the world, articles, tutorials and small businesses that promote the vintage stye! Submissions are always open for anything Pin Up related. We are always looking for Retro inspired articles and small businesses to feature. www.moderndaypinupmagazine.com http://www.moderndaypinupmagazine.com
Short Bio Army Veteran turned pinup 😉
Full Bio I've always loved the vintage/pinup style. From the cars to the clothes, its always been so fascinating to me.
Published in the Following Publications Retro Lovely # 30 and Smitten Kitten
Full Bio Hey, Sugar! My name is Billie Jayne DeVille. I was born and raised a Georgia Peach but I now
call South Carolina my home. I'm a full-time artist/pinstriper and a total sucker for whitewall
tires and big tailfins! When I'm not painting, you can find me cruising in my 53 Chevy, my 55
Cadillac, my 63 T-bird or in the shop getting down and dirty with my 58 Plymouth restoration project! I am also co-owner of Deville Magazine, a quarterly kustom kulture publication available in both print and digital!
Published in the Following Publications Car Kulture Deluxe, Retro Lovely, Delicious Dolls, Bombshell Magazine, Garters & Grills, Smitten Kitten, Grease Magazine, Modern Day Pinup, The Social Pin, Pinup Kulture, Dappers & Dames, Rocket Magazine, Chica Boom, Hussy Magazine, Twisted Pulp, DeVille Magazine, Cherry Bomb Magazine
Pin Up Group Name erikasteelexoxo
Photography Studio Name KEARNEYINK78
Short Bio Easy riders centerfold,
myfreecams
dancer
Full Bio cabaret dancer at LUCKY LADY CABARET, internet chat model for myfreecams, published Easy riders centerfold and spokesmodel, Gold avenger for superheroinecentral.com, catfightcentral.com, always looking for cool photographers to shoot with...
Magazines include
Leg Show, Leg Sex, Leg Action, Easyriders motorcycle magazine, Busty Beauties, Gent
Titles include
Miss Easyriders (voted centerfold of the year for Easyriders)
Miss Nude Midwest
Miss Nude Northeast
Voted club favorite awarded by Exotic Dancers Publications
Television appearances
Ricki Lake - Life of a Dancer
Jerry Springer - Lesbian Love Triangle
Websites
Cosplay - The Gold Avenger for superheroinecentral.com
Catfight - catfightcentral.com/clips4sale.com
model for Babestation tv UK cams
erikasteele.net
Contact information erikasteelexoxo@gmail.com
Published in the Following Publications LEG SHOW, LEG SEX, BUSY; GENT Luckylady.com, lucky lady cabaret club advertisement
Pin Up Group Name Bay City Bombshells
Short Bio Our Mission: To empower women to peruse their dreams with style and class.
Full Bio Bay City Bombshells (BCB) is a group for women that love the pin-up/vintage/retro/rockabilly lifestyle, the fashion and look, or aspire to learn more about living a vintage lifestyle. Here we are able to share what makes us a bombshell, and share tips and tricks with each other.
Full Bio Lyndah Pizarro is reality TV personality with a love for all things Pin Up. Lyndah is globally syndicated thanks to her starring role on the hit TV show Operation Repo. Well know for being aired all across the globe and in numerous countries, Lyndah then took her notoriety to different areas where she found much success such as starting her own clothing link known as Pink Pizza, starting her own skin care line known as Lyndah face and make up known as Lyndah Beauty. Lyndah decided to then take a shot at modeling. After trying different genres if modeling, she finally landed where she was always meant to land, in the Pin up world. Since her first photo shoot as a pin up model with Girlie Show photography, Lyndah has been published twice in RetroLovely Magazine and can also be found in Pin Up Kulture Magazine. Then in 2020, Lyndah found herself in her very first international publication with BombShell Magazine.
Published in the Following Publications RetroLovely Magazine, Pin Up Kulture Magazine, BombShell Magazine
Pin Up Group Name Pin Ups & Pumps TN
Full Bio The Pin Ups & Pumps TN chapter empowers women through the art of pinup, blending vintage style with a passion for community outreach and volunteer work across Southeast Tennessee. We celebrate the charm of classic fashion and car culture while making a meaningful impact in our community!
Published in the Following Publications Retro Lovely, Smitten Kitten Pinup, Deville, Bombshell, Drive-In
Full Bio I was born in Indiana but moved to Tennessee in my late teens. My mother introduced me to Marilyn Monroe at a very young age and I have been enamored with everything pin-up, vintage, and retro ever since. I started pin-up modeling in 2019 with my best friend and photographer Pamela Claytor. I have been very lucky to be a part of her vision and have her expertise along the way. I have been published 7 times so far and have 5 more publications coming up!
Published in the Following Publications The Golden Exposure Inked Aug 2020 - RetroLovely Scrapbook Vol 10 - RetroLovely Heavy Ink No.5 - RetroLovely Taboo No. 34 - RetroLovely Hot Rods Special Edition Vol 1 - Bombshell October 2020 Book 1 - RetroMan Magazine Issue 3 Tiki Special Edition
Photography Studio Name Je m'adore fine art portraits
Short Bio I am a portrait photographer, a mother, a wife, a chocoholic and most importantly a woman. I started my portrait studio with the desire to empower women and celebrate all the many things we can be. There is no age limit, no size limit and no weight limit in my studio. Furthermore, there is ZERO judgement.
Full Bio I am a portrait photographer, a mother, a wife, a chocoholic and most importantly a woman. I started my portrait studio with the desire to empower women and celebrate all the many things we can be. There is no age limit, no size limit and no weight limit in my studio. Furthermore, there is ZERO judgement.
As a woman, our thoughts are often triggered by our emotions. Let’s play with that for a moment. Close your eyes and imagine for a moment that you have no limitations… what would that feel like? How would you dream of being photographed? Allow me to make that thought come true for you and capture beautiful images that you will cherish forever.
You deserve it. Come celebrate all your inner moments!
Short Bio Mom, pinup, designer
Full Bio Born and raised in California. Many summer evenings of my childhood could be found in the garage handing my dad a wrench or holding a flashlight. The smells of exhaust and motor oil bring back those happy memories, because of that, I can often be found at car shows. Most of my time is occupied with wrangling my two rambunctious young sons but when I have some free time I like to create. Whether that’s from either side of a lens, leaning over a craft table or dabbling away on a design, my mind is always thinking up a new creation.
Pin Up Group Membership PinUps with Heart, Hot Rod Hotties
Published in the Following Publications Rocket Magazine