Mail-DMARC

 view release on metacpan or  search on metacpan

lib/Mail/DMARC/Base.pm  view on Meta::CPAN

}

{
    my $public_suffixes;
    my $public_suffixes_stamp;

    sub get_public_suffix_list($self) {
        if ($public_suffixes) { return $public_suffixes; }
        no warnings 'once';    ## no critic
        $Mail::DMARC::psl_loads++;
        my $file = $self->find_psl_file();
        $public_suffixes_stamp = ( stat($file) )[9];

        open my $fh, '<:encoding(UTF-8)', $file
            or croak "unable to open $file for read: $!\n";

        # load PSL into hash for fast lookups, esp. for long running daemons
        my %psl = map { $_ => 1 }
            grep { $_ !~ /^[\/\s]/ }    # weed out comments & whitespace
            map  { chomp($_); $_ }      ## no critic, remove line endings
            <$fh>;
        close $fh;
        return $public_suffixes = \%psl;
    }

    sub check_public_suffix_list($self) {
        my $file                      = $self->find_psl_file();
        my $new_public_suffixes_stamp = ( stat($file) )[9];
        if ( $new_public_suffixes_stamp != $public_suffixes_stamp ) {
            $public_suffixes = undef;
            $self->get_public_suffix_list();
            return 1;
        }
        return 0;
    }
}

sub is_public_suffix( $self, $zone ) {
    croak "missing zone name!" if !$zone;

    my $public_suffixes = $self->get_public_suffix_list();

    $zone = URI::_idna::decode( $zone, 0 ) // $zone if $zone =~ /xn--/;

    # Check for exception rules
    return 0 if $public_suffixes->{"!$zone"};

    # Check for direct match
    return 1 if $public_suffixes->{$zone};

    # Check for wildcard match
    my @labels = split /\./, $zone;
    if ( @labels > 1 ) {
        my $wildcard = join '.', '*', (@labels)[ 1 .. scalar(@labels) - 1 ];
        return 1 if $public_suffixes->{$wildcard};
    }

    return 0;
}

sub update_psl_file( $self, $dryrun = undef ) {
    my $psl_file = $self->find_psl_file();

    die "No Public Suffix List file found\n"                  if ( !$psl_file );
    die "Public suffix list file $psl_file not found\n"       if ( !-f $psl_file );
    die "Cannot write to Public Suffix List file $psl_file\n" if ( !-w $psl_file );

    my $url = 'https://publicsuffix.org/list/effective_tld_names.dat';
    if ($dryrun) {
        print
            "Will attempt to update the Public Suffix List file at $psl_file (dryrun mode)\n";
        return;
    }

    my $response = HTTP::Tiny->new->mirror( $url, $psl_file );
    my $content  = $response->{'content'};
    if ( !$response->{'success'} ) {
        my $status = $response->{'status'};
        die
            "HTTP Request for Public Suffix List file failed with error $status ($content)\n";
    }
    else {
        if ( $response->{'status'} eq '304' ) {
            print "Public Suffix List file $psl_file not modified\n";
        }
        else {
            print "Public Suffix List file $psl_file updated\n";
        }
    }
    return;
}

sub find_psl_file($self) {
    my $file
        = $self->config->{dns}{public_suffix_list} || 'share/public_suffix_list';
    if ( $file =~ /^\// && -f $file && -r $file ) {
        print "using $file for Public Suffix List\n" if $self->verbose;
        return $file;
    }

    foreach my $path ( $self->get_prefix($file) ) {
        if ( -f $path && -r $path ) {
            print "using $path for Public Suffix List\n";    # if $self->verbose;
            return $path;
        }
    }

    # Fallback to included suffic list
    return $self->get_sharefile('public_suffix_list');
}

sub has_dns_rr( $self, $type, $domain ) {
    my @matches;
    my $res   = $self->get_resolver();
    my $query = $res->query( $domain, $type ) or do {
        return 0 if !wantarray;
        return @matches;
    };
    for my $rr ( $query->answer ) {
        next if $rr->type ne $type;
        push @matches,



( run in 0.464 second using v1.01-cache-2.11-cpan-bbe5e583499 )