use Net::DNS qw(mx); sub register { my ($self, $qp) = @_; $self->register_hook("mail", "mail_handler"); $self->register_hook("rcpt", "rcpt_handler"); } sub mail_handler { my ($self, $transaction, $sender) = @_; return DECLINED if $sender->format eq '<>'; unless($sender->host) { $self->log(6, "mail_handler: FQDN required"); $transaction->notes('unresolvable_fromhost', "FQDN required in the envelope sender"); return DECLINED; } unless (check_dns($sender->host)) { $self->log(6, "mail_handler: Could not resolve " . $sender->host); $transaction->notes('unresolvable_fromhost', "Could not resolve ". $sender->host); return DECLINED; } return DECLINED; } sub rcpt_handler { my ($self, $transaction, $rcpt) = @_; if ($self->qp->config("require_resolvable_fromhost", { rcpt => $rcpt })) { my $reason = $transaction->notes('unresolvable_fromhost'); $self->log(6, "rcpt_handler: reason " . ($reason ? $reason : '(undef)')); return (DENYSOFT, $reason) if ($reason); } return DECLINED; } sub check_dns { my $host = shift; # for stuff where we can't even parse a hostname out of the address return 0 unless $host; return 1 if $host =~ m/^\[(\d{1,3}\.){3}\d{1,3}\]$/; my $res = new Net::DNS::Resolver; return 1 if mx($res, $host); my $query = $res->search($host); if ($query) { foreach my $rr ($query->answer) { return 1 if $rr->type eq "A" or $rr->type eq "MX"; } } else { warn "$$ query for $host failed: ", $res->errorstring, "\n" unless $res->errorstring eq "NXDOMAIN"; } return 0; }