diff --git a/plugins/async/resolvable_fromhost b/plugins/async/resolvable_fromhost index 4bfe7d8..acf93d6 100644 --- a/plugins/async/resolvable_fromhost +++ b/plugins/async/resolvable_fromhost @@ -15,7 +15,7 @@ my $has_ipv6 = Qpsmtpd::TcpServer::has_ipv6(); sub register { my ( $self, $qp ) = @_; - + foreach my $i ( $self->qp->config("invalid_resolvable_fromhost") ) { $i =~ s/^\s*//; $i =~ s/\s*$//; @@ -35,7 +35,7 @@ sub register { sub hook_mail_start { my ( $self, $transaction, $sender ) = @_; - + return DECLINED if ($self->connection->notes('whitelisthost')); @@ -63,7 +63,7 @@ sub hook_mail_start { sub hook_mail_done { my ( $self, $transaction, $sender ) = @_; - + return DECLINED if ( $self->connection->notes('whitelisthost') ); @@ -81,7 +81,7 @@ sub check_dns { my $qp = $self->qp; $qp->input_sock->pause_read; - + my $a_records = []; my $num_queries = 1; # queries in progress my $mx_found = 0; @@ -159,7 +159,7 @@ sub finish_up { return; } } - + unless ($num_queries) { # all queries returned no valid response $qp->transaction->notes('resolvable_fromhost', 0); diff --git a/plugins/resolvable_fromhost b/plugins/resolvable_fromhost index e3ff208..d65bece 100644 --- a/plugins/resolvable_fromhost +++ b/plugins/resolvable_fromhost @@ -51,11 +51,11 @@ Default: temp (temporary, aka soft, aka 4xx). =head1 EXAMPLE LOG ENTRIES - 80072 (mail) resolvable_fromhost: googlegroups.com has valid MX at gmr-smtp-in.l.google.com - 80108 (mail) resolvable_fromhost: zerobarriers.net has valid MX at zerobarriers.net - 80148 (mail) resolvable_fromhost: uhin.com has valid MX at filter.itsafemail.com - 86627 (mail) resolvable_fromhost: no MX records for palmalar.com - 86627 (mail) resolvable_fromhost: fail: palmalar.com (SERVFAIL) + 80072 (mail) resolvable_fromhost: pass, googlegroups.com has MX at gmr-smtp-in.l.google.com + 80108 (mail) resolvable_fromhost: pass, zerobarriers.net has MX at zerobarriers.net + 80148 (mail) resolvable_fromhost: pass, uhin.com has MX at filter.itsafemail.com + 86627 (mail) resolvable_fromhost: palmalar.com has no MX + 86627 (mail) resolvable_fromhost: fail, palmalar.com (SERVFAIL) =head1 AUTHORS @@ -65,7 +65,6 @@ Default: temp (temporary, aka soft, aka 4xx). =cut - use strict; use warnings; @@ -95,32 +94,36 @@ sub register { sub hook_mail { my ($self, $transaction, $sender, %param) = @_; - $self->populate_invalid_networks(); + return DECLINED if $self->is_immune(); - # check first, so results are noted for other plugins + if ( $sender eq '<>' ) { + $transaction->notes('resolvable_fromhost', 'null'); + $self->log(LOGINFO, "pass, null sender"); + return DECLINED; + }; + + $self->populate_invalid_networks(); my $resolved = $self->check_dns($sender->host, $transaction); return DECLINED if $resolved; # success, no need to continue - return DECLINED if $self->is_immune( $sender, $transaction ); - return DECLINED if ! $self->{_args}{reject}; + #return DECLINED if $sender->host; # reject later - return DECLINED if $sender->host; # reject later + if ( ! $self->{_args}{reject} ) {; + $self->log(LOGINFO, 'skip, reject disabled' ); + return DECLINED; + }; - $self->log(LOGWARN, "FQDN required in envelope sender"); - return Qpsmtpd::DSN->addr_bad_from_system( $self->get_reject_type(), - "FQDN required in the envelope sender"); -} + my $result = $transaction->notes('resolvable_fromhost') or do { + return Qpsmtpd::DSN->temp_resolver_failed( $self->get_reject_type(), '' ); + }; -sub hook_rcpt { - my ($self, $transaction, $recipient, %args) = @_; - - my $result = $transaction->notes('resolvable_fromhost'); - return DECLINED if ! $self->{_args}{reject}; # no reject policy - return DECLINED if $result =~ /^(a|ip|mx)$/; # success - return DECLINED if $result =~ /^(whitelist|null|config)$/; # immunity + return DECLINED if $result =~ /^(?:a|ip|mx)$/; # success + return DECLINED if $result =~ /^(?:whitelist|null|naughty)$/; # immunity $self->log(LOGINFO, $result ); # log error - return Qpsmtpd::DSN->temp_resolver_failed( $self->get_reject_type(), $result ); + + return Qpsmtpd::DSN->addr_bad_from_system( $self->get_reject_type(), + "FQDN required in the envelope sender"); } sub check_dns { @@ -135,7 +138,7 @@ sub check_dns { $transaction->notes('resolvable_fromhost_host', $host); if ( $host =~ m/^\[(\d{1,3}\.){3}\d{1,3}\]$/ ) { - $self->log(LOGINFO, "skip: $host is an IP"); + $self->log(LOGINFO, "skip, $host is an IP"); $transaction->notes('resolvable_fromhost', 'ip'); return 1; }; @@ -151,12 +154,12 @@ sub check_dns { my @host_answers = $self->get_host_records( $res, $host, $transaction ); foreach my $rr (@host_answers) { if ( $rr->type eq 'A' || $rr->type eq 'AAAA' ) { - $self->log(LOGINFO, "pass: found valid A for $host"); + $self->log(LOGINFO, "pass, found A for $host"); $transaction->notes('resolvable_fromhost', 'a'); return $self->ip_is_valid($rr->address); }; if ( $rr->type eq 'MX' ) { - $self->log(LOGINFO, "pass: found valid MX for $host"); + $self->log(LOGINFO, "pass, found MX for $host"); $transaction->notes('resolvable_fromhost', 'mx'); return $self->mx_address_resolves($rr->exchange, $host); }; @@ -184,21 +187,21 @@ sub get_and_validate_mx { my @mx = mx($res, $host); if ( ! scalar @mx ) { # no mx records - $self->log(LOGINFO, "no MX records for $host"); + $self->log(LOGINFO, "$host has no MX"); return 0; }; foreach my $mx (@mx) { # if any MX is valid, then we consider the domain resolvable if ( $self->mx_address_resolves($mx->exchange, $host) ) { - $self->log(LOGINFO, "pass: $host has valid MX at " . $mx->exchange); + $self->log(LOGINFO, "pass, $host has MX at " . $mx->exchange); $transaction->notes('resolvable_fromhost', 'mx'); return 1; }; } # if there are MX records, and we got here, none are valid - $self->log(LOGINFO, "fail: invalid MX for $host"); + $self->log(LOGINFO, "fail, invalid MX for $host"); $transaction->notes('resolvable_fromhost', "invalid MX for $host"); return -1; }; @@ -226,7 +229,7 @@ sub get_host_records { if ( ! scalar @answers) { if ( $res->errorstring ne 'NXDOMAIN' ) { - $self->log(LOGWARN, "$$ query for $host failed: ", $res->errorstring); + $self->log(LOGWARN, "fail, query for $host, ", $res->errorstring); }; return; }; @@ -257,8 +260,9 @@ sub mx_address_resolves { } } if (! @mx_answers) { - $self->log(LOGWARN, "query for $fromhost failed: ", $res->errorstring) - unless $res->errorstring eq "NXDOMAIN"; + if ( $res->errorstring eq 'NXDOMAIN' ) { + $self->log(LOGWARN, "fail, query for $fromhost, ", $res->errorstring); + }; return; } @@ -282,37 +286,3 @@ sub populate_invalid_networks { } }; -sub is_immune { - my ($self, $sender, $transaction) = @_; - - if ( $self->qp->connection->notes('whitelisthost') ) { - $transaction->notes('resolvable_fromhost', 'whitelist'); - $self->log(LOGINFO, "pass: whitelisted"); - return 1; - }; - - if ( $sender eq '<>' ) { - $transaction->notes('resolvable_fromhost', 'null'); - $self->log(LOGINFO, "pass: null sender"); - return 1; - }; - - if ( ! $self->{_args}{reject} ) { - $transaction->notes('resolvable_fromhost', 'config'); - $self->log(LOGINFO, "skip: reject not enabled in config."); - return; - }; - - return; -}; - -sub get_reject_type { - my $self = shift; - my $default = shift || DENYSOFT; - my $deny = $self->{_args}{reject_type} or return $default; - - return $deny =~ /^(temp|soft)$/i ? DENYSOFT - : $deny =~ /^(perm|hard)$/i ? DENY - : $deny eq 'disconnect' ? DENY_DISCONNECT - : $default; -};