Base: consistent DNS handling
This commit is contained in:
parent
cd79bff78e
commit
38d5523b35
@ -13,8 +13,8 @@ WriteMakefile(
|
|||||||
'File::Temp' => 0,
|
'File::Temp' => 0,
|
||||||
'Mail::Header' => 0,
|
'Mail::Header' => 0,
|
||||||
'MIME::Base64' => 0,
|
'MIME::Base64' => 0,
|
||||||
'Net::DNS' => 0.39,
|
'Net::DNS' => 0.79,
|
||||||
'Net::IP' => 0,
|
'Net::IP' => 1.26,
|
||||||
'Time::HiRes' => 0,
|
'Time::HiRes' => 0,
|
||||||
'IO::Socket::SSL' => 0,
|
'IO::Socket::SSL' => 0,
|
||||||
'ClamAV::Client' => 0, # virus/clamdscan
|
'ClamAV::Client' => 0, # virus/clamdscan
|
||||||
@ -22,7 +22,7 @@ WriteMakefile(
|
|||||||
'Test::More' => 0,
|
'Test::More' => 0,
|
||||||
'Test::Output' => 0,
|
'Test::Output' => 0,
|
||||||
# modules for specific features
|
# modules for specific features
|
||||||
'Mail::DKIM' => 0,
|
'Mail::DKIM' => 0.40,
|
||||||
'File::Tail' => 0, # log/summarize, log/watch
|
'File::Tail' => 0, # log/summarize, log/watch
|
||||||
'Time::TAI64' => 0, # log2sql
|
'Time::TAI64' => 0, # log2sql
|
||||||
# 'DBI' => 0, # auth_vpopmail_sql and
|
# 'DBI' => 0, # auth_vpopmail_sql and
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package Qpsmtpd::Base;
|
package Qpsmtpd::Base;
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
|
use Net::DNS;
|
||||||
use Net::IP;
|
use Net::IP;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
@ -45,4 +46,67 @@ sub is_ipv6 {
|
|||||||
return Net::IP::ip_is_ipv6($ip);
|
return Net::IP::ip_is_ipv6($ip);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sub get_resolver {
|
||||||
|
my ($self, %args) = @_;
|
||||||
|
return $self->{_resolver} if $self->{_resolver};
|
||||||
|
my $timeout = 5;
|
||||||
|
if (defined $args{timeout}) {
|
||||||
|
$timeout = delete $args{timeout};
|
||||||
|
}
|
||||||
|
$self->{_resolver} = Net::DNS::Resolver->new(dnsrch => 0);
|
||||||
|
$self->{_resolver}->tcp_timeout($timeout);
|
||||||
|
$self->{_resolver}->udp_timeout($timeout);
|
||||||
|
return $self->{_resolver};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_async_resolver {
|
||||||
|
my ( $self, %args ) = @_;
|
||||||
|
return $self->{_async_resolver} if $self->{_async_resolver};
|
||||||
|
|
||||||
|
my $res = Net::DNS::Resolver->new(dnsrch => 0);
|
||||||
|
$res->tcp_timeout(0); # Net::DNS::Async handles its own timeouts
|
||||||
|
$res->tcp_timeout(0);
|
||||||
|
|
||||||
|
my $async_res;
|
||||||
|
eval 'use Net::DNS::Async';
|
||||||
|
if ($@) {
|
||||||
|
warn "Net::DNS::Async failed to load";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{_async_resolver} = Net::DNS::Async->new( %args );
|
||||||
|
$self->{_async_resolver}{Resolver} = $res;
|
||||||
|
return $self->{_async_resolver};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub resolve_a {
|
||||||
|
my ($self, $name) = @_;
|
||||||
|
my $q = $self->get_resolver->query($name, 'A') or return;
|
||||||
|
return map { $_->address } grep { $_->type eq 'A' } $q->answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub resolve_aaaa {
|
||||||
|
my ($self, $name) = @_;
|
||||||
|
my $q = $self->get_resolver->query($name, 'AAAA') or return;
|
||||||
|
return map { $_->address } grep { $_->type eq 'AAAA' } $q->answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub resolve_mx {
|
||||||
|
my ($self, $name) = @_;
|
||||||
|
my $q = $self->get_resolver->query($name, 'MX') or return;
|
||||||
|
return map { $_->exchange } grep { $_->type eq 'MX' } $q->answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub resolve_ns {
|
||||||
|
my ($self, $name) = @_;
|
||||||
|
my $q = $self->get_resolver->query($name, 'NS') or return;
|
||||||
|
return map { $_->nsdname } grep { $_->type eq 'NS' } $q->answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub resolve_ptr {
|
||||||
|
my ($self, $name) = @_;
|
||||||
|
my $q = $self->get_resolver->query($name, 'PTR') or return;
|
||||||
|
return map { $_->ptrdname } grep { $_->type eq 'PTR' } $q->answer;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -2,8 +2,8 @@ package Qpsmtpd::Plugin;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Net::DNS;
|
use lib 'lib';
|
||||||
|
use parent 'Qpsmtpd::Base';
|
||||||
use Qpsmtpd::Constants;
|
use Qpsmtpd::Constants;
|
||||||
|
|
||||||
# more or less in the order they will fire
|
# more or less in the order they will fire
|
||||||
@ -278,17 +278,6 @@ sub store_auth_results {
|
|||||||
$self->qp->connection->notes('authentication_results', $ar );
|
$self->qp->connection->notes('authentication_results', $ar );
|
||||||
};
|
};
|
||||||
|
|
||||||
sub init_resolver {
|
|
||||||
my $self = shift;
|
|
||||||
my $timeout = $self->{_args}{dns_timeout} || shift || 5;
|
|
||||||
return $self->{_resolver} if $self->{_resolver};
|
|
||||||
$self->log(LOGDEBUG, "initializing Net::DNS::Resolver");
|
|
||||||
$self->{_resolver} = Net::DNS::Resolver->new(dnsrch => 0);
|
|
||||||
$self->{_resolver}->tcp_timeout($timeout);
|
|
||||||
$self->{_resolver}->udp_timeout($timeout);
|
|
||||||
return $self->{_resolver};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub is_immune {
|
sub is_immune {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ use Carp;
|
|||||||
#use Data::Dumper;
|
#use Data::Dumper;
|
||||||
use POSIX qw(strftime);
|
use POSIX qw(strftime);
|
||||||
use Mail::Header;
|
use Mail::Header;
|
||||||
use Net::DNS;
|
|
||||||
|
|
||||||
use Qpsmtpd;
|
use Qpsmtpd;
|
||||||
use Qpsmtpd::Connection;
|
use Qpsmtpd::Connection;
|
||||||
|
@ -68,10 +68,10 @@ sub hook_connect {
|
|||||||
|
|
||||||
my $reversed_ip = join('.', reverse(split(/\./, $remote_ip)));
|
my $reversed_ip = join('.', reverse(split(/\./, $remote_ip)));
|
||||||
|
|
||||||
# we queue these lookups in the background and just fetch the
|
# queue lookups in the background and fetch the
|
||||||
# results in the first rcpt handler
|
# results in the first rcpt handler
|
||||||
|
|
||||||
my $res = new Net::DNS::Resolver;
|
my $res = $self->get_resolver();
|
||||||
my $sel = IO::Select->new();
|
my $sel = IO::Select->new();
|
||||||
|
|
||||||
for my $dnsbl (keys %whitelist_zones) {
|
for my $dnsbl (keys %whitelist_zones) {
|
||||||
@ -90,7 +90,7 @@ sub process_sockets {
|
|||||||
|
|
||||||
return $conn->notes('whitelisthost') if $conn->notes('whitelisthost');
|
return $conn->notes('whitelisthost') if $conn->notes('whitelisthost');
|
||||||
|
|
||||||
my $res = new Net::DNS::Resolver;
|
my $res = $self->get_resolver();
|
||||||
my $sel = $conn->notes('whitelist_sockets') or return '';
|
my $sel = $conn->notes('whitelist_sockets') or return '';
|
||||||
|
|
||||||
$self->log(LOGDEBUG, "waiting for whitelist dns");
|
$self->log(LOGDEBUG, "waiting for whitelist dns");
|
||||||
|
@ -166,7 +166,9 @@ sub hook_connect {
|
|||||||
return DECLINED if $self->ip_whitelisted();
|
return DECLINED if $self->ip_whitelisted();
|
||||||
|
|
||||||
my $dnsbl_zones = $self->get_dnsbl_zones() or return DECLINED;
|
my $dnsbl_zones = $self->get_dnsbl_zones() or return DECLINED;
|
||||||
my $resolv = $self->get_resolver() or return DECLINED;
|
my $timeout = $self->{_args}{timeout} || 30;
|
||||||
|
my $resolv = $self->{_resolver} = $self->get_resolver(timeout=>$timeout)
|
||||||
|
or return DECLINED;
|
||||||
|
|
||||||
for my $dnsbl (keys %$dnsbl_zones) {
|
for my $dnsbl (keys %$dnsbl_zones) {
|
||||||
|
|
||||||
@ -299,15 +301,3 @@ sub hook_rcpt {
|
|||||||
|
|
||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_resolver {
|
|
||||||
my $self = shift;
|
|
||||||
return $self->{_resolver} if $self->{_resolver};
|
|
||||||
$self->log(LOGDEBUG, "initializing Net::DNS::Resolver");
|
|
||||||
$self->{_resolver} = Net::DNS::Resolver->new(dnsrch => 0);
|
|
||||||
my $timeout = $self->{_args}{timeout} || 30;
|
|
||||||
$self->{_resolver}->tcp_timeout($timeout);
|
|
||||||
$self->{_resolver}->udp_timeout($timeout);
|
|
||||||
return $self->{_resolver};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -141,8 +141,6 @@ sub register {
|
|||||||
$self->{_args}{reject} = 0;
|
$self->{_args}{reject} = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->init_resolver() or return;
|
|
||||||
|
|
||||||
$self->register_hook('connect', 'connect_handler');
|
$self->register_hook('connect', 'connect_handler');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +203,7 @@ sub is_not_fqdn {
|
|||||||
sub has_reverse_dns {
|
sub has_reverse_dns {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
my $res = $self->init_resolver();
|
my $res = $self->get_resolver();
|
||||||
my $ip = $self->qp->connection->remote_ip;
|
my $ip = $self->qp->connection->remote_ip;
|
||||||
|
|
||||||
my $query = $res->query($ip, 'PTR') or do {
|
my $query = $res->query($ip, 'PTR') or do {
|
||||||
@ -252,7 +250,7 @@ sub has_reverse_dns {
|
|||||||
sub has_forward_dns {
|
sub has_forward_dns {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
my $res = $self->init_resolver();
|
my $res = $self->get_resolver();
|
||||||
|
|
||||||
foreach my $host (keys %{$self->{_args}{ptr_hosts}}) {
|
foreach my $host (keys %{$self->{_args}{ptr_hosts}}) {
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ sub register {
|
|||||||
$self->{_args}{reject} = 1;
|
$self->{_args}{reject} = 1;
|
||||||
}
|
}
|
||||||
$self->populate_tests();
|
$self->populate_tests();
|
||||||
$self->init_resolver() or return;
|
$self->get_resolver() or return;
|
||||||
|
|
||||||
$self->register_hook('helo', 'helo_handler');
|
$self->register_hook('helo', 'helo_handler');
|
||||||
$self->register_hook('ehlo', 'helo_handler');
|
$self->register_hook('ehlo', 'helo_handler');
|
||||||
@ -402,7 +402,7 @@ sub no_forward_dns {
|
|||||||
|
|
||||||
return if $self->is_address_literal($host);
|
return if $self->is_address_literal($host);
|
||||||
|
|
||||||
my $res = $self->init_resolver();
|
my $res = $self->get_resolver();
|
||||||
|
|
||||||
$host = "$host." if $host !~ /\.$/; # fully qualify name
|
$host = "$host." if $host !~ /\.$/; # fully qualify name
|
||||||
my $query = $res->query($host);
|
my $query = $res->query($host);
|
||||||
@ -431,7 +431,7 @@ sub no_forward_dns {
|
|||||||
sub no_reverse_dns {
|
sub no_reverse_dns {
|
||||||
my ($self, $host, $ip) = @_;
|
my ($self, $host, $ip) = @_;
|
||||||
|
|
||||||
my $res = $self->init_resolver();
|
my $res = $self->get_resolver();
|
||||||
$ip ||= $self->qp->connection->remote_ip;
|
$ip ||= $self->qp->connection->remote_ip;
|
||||||
|
|
||||||
my $query = $res->query($ip) or do {
|
my $query = $res->query($ip) or do {
|
||||||
|
@ -92,6 +92,8 @@ sub register {
|
|||||||
$self->{_args}{reject} = 1;
|
$self->{_args}{reject} = 1;
|
||||||
}
|
}
|
||||||
$self->{_args}{reject_type} ||= 'soft';
|
$self->{_args}{reject_type} ||= 'soft';
|
||||||
|
|
||||||
|
$self->{resolver} = $self->get_resolver(timeout => 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub hook_mail {
|
sub hook_mail {
|
||||||
@ -158,16 +160,14 @@ sub check_dns {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $res = new Net::DNS::Resolver(dnsrch => 0);
|
my $res = $self->get_resolver(timeout => 30);
|
||||||
$res->tcp_timeout(30);
|
|
||||||
$res->udp_timeout(30);
|
|
||||||
|
|
||||||
my $has_mx = $self->get_and_validate_mx($res, $host, $transaction);
|
my $has_mx = $self->get_and_validate_mx($host, $transaction);
|
||||||
return 1 if $has_mx == 1; # success, has MX!
|
return 1 if $has_mx == 1; # success, has MX!
|
||||||
return if $has_mx == -1; # has invalid MX records
|
return if $has_mx == -1; # has invalid MX records
|
||||||
# at this point, no MX for fh is resolvable
|
# at this point, no MX for fh is resolvable
|
||||||
|
|
||||||
my @host_answers = $self->get_host_records($res, $host, $transaction);
|
my @host_answers = $self->get_host_records($host, $transaction);
|
||||||
foreach my $rr (@host_answers) {
|
foreach my $rr (@host_answers) {
|
||||||
if ($rr->type eq 'A' || $rr->type eq 'AAAA') {
|
if ($rr->type eq 'A' || $rr->type eq 'AAAA') {
|
||||||
$self->log(LOGINFO, "pass, found A for $host");
|
$self->log(LOGINFO, "pass, found A for $host");
|
||||||
@ -198,9 +198,9 @@ sub ip_is_valid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub get_and_validate_mx {
|
sub get_and_validate_mx {
|
||||||
my ($self, $res, $host, $transaction) = @_;
|
my ($self, $host, $transaction) = @_;
|
||||||
|
|
||||||
my @mx = mx($res, $host);
|
my @mx = mx($self->{resolver}, $host);
|
||||||
if (!scalar @mx) { # no mx records
|
if (!scalar @mx) { # no mx records
|
||||||
$self->adjust_karma(-1);
|
$self->adjust_karma(-1);
|
||||||
$self->log(LOGINFO, "$host has no MX");
|
$self->log(LOGINFO, "$host has no MX");
|
||||||
@ -225,9 +225,10 @@ sub get_and_validate_mx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub get_host_records {
|
sub get_host_records {
|
||||||
my ($self, $res, $host, $transaction) = @_;
|
my ($self, $host, $transaction) = @_;
|
||||||
|
|
||||||
my @answers;
|
my @answers;
|
||||||
|
my $res = $self->{resolver};
|
||||||
my $query = $res->search($host);
|
my $query = $res->search($host);
|
||||||
|
|
||||||
if ($query) {
|
if ($query) {
|
||||||
@ -259,38 +260,26 @@ sub mx_address_resolves {
|
|||||||
my ($self, $name, $fromhost) = @_;
|
my ($self, $name, $fromhost) = @_;
|
||||||
|
|
||||||
# IP in MX
|
# IP in MX
|
||||||
return $self->ip_is_valid($name) if ip_is_ipv4($name) || ip_is_ipv6($name);
|
if (ip_is_ipv4($name) || ip_is_ipv6($name)) {
|
||||||
|
return $self->ip_is_valid($name);
|
||||||
|
};
|
||||||
|
|
||||||
|
my $res = $self->get_resolver();
|
||||||
|
my @mx_answers = $self->resolve_a($name);
|
||||||
|
|
||||||
my $res = new Net::DNS::Resolver(dnsrch => 0);
|
|
||||||
my @mx_answers;
|
|
||||||
my $query = $res->search($name, 'A');
|
|
||||||
if ($query) {
|
|
||||||
foreach my $rrA ($query->answer) {
|
|
||||||
push(@mx_answers, $rrA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($has_ipv6) {
|
if ($has_ipv6) {
|
||||||
my $query = $res->search($name, 'AAAA');
|
push @mx_answers, $self->resolve_aaaa($name);
|
||||||
if ($query) {
|
|
||||||
foreach my $rrAAAA ($query->answer) {
|
|
||||||
push(@mx_answers, $rrAAAA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!@mx_answers) {
|
if (!@mx_answers) {
|
||||||
if ($res->errorstring eq 'NXDOMAIN') {
|
if ($res->errorstring eq 'NXDOMAIN') {
|
||||||
$self->log(LOGWARN, "fail, query for $fromhost, ",
|
$self->log(LOGWARN, "fail, query for $fromhost, ", $res->errorstring);
|
||||||
$res->errorstring);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $rr (@mx_answers) {
|
return if ! scalar @mx_answers;
|
||||||
next if ($rr->type ne 'A' && $rr->type ne 'AAAA');
|
return $self->ip_is_valid($mx_answers[0]);
|
||||||
return $self->ip_is_valid($rr->address);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub populate_invalid_networks {
|
sub populate_invalid_networks {
|
||||||
|
@ -67,7 +67,7 @@ sub hook_mail {
|
|||||||
|
|
||||||
my %rhsbl_zones = $self->populate_zones() or return DECLINED;
|
my %rhsbl_zones = $self->populate_zones() or return DECLINED;
|
||||||
|
|
||||||
my $res = $self->init_resolver();
|
my $res = $self->get_resolver();
|
||||||
|
|
||||||
my @hosts = $sender->host;
|
my @hosts = $sender->host;
|
||||||
for my $host (@hosts) {
|
for my $host (@hosts) {
|
||||||
|
@ -61,13 +61,8 @@ sub stunnel {
|
|||||||
$self->log(LOGINFO, "stunnel : $2:$4");
|
$self->log(LOGINFO, "stunnel : $2:$4");
|
||||||
|
|
||||||
# DNS reverse
|
# DNS reverse
|
||||||
my $res = $self->init_resolver();
|
my @ptrs = $self->resolve_ptr($self->connection->remote_ip);
|
||||||
if (my $query = $res->query($self->connection->remote_ip, 'PTR')) {
|
$self->connection->remote_host($ptrs[0]);
|
||||||
foreach my $rr ($query->answer) {
|
|
||||||
next if $rr->type ne 'PTR';
|
|
||||||
$self->connection->remote_host($rr->ptrdname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DONE;
|
return DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +92,9 @@ may be used and redistributed under the same terms as qpsmtpd itself.
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use lib 'lib';
|
||||||
use Qpsmtpd::Constants;
|
use Qpsmtpd::Constants;
|
||||||
|
|
||||||
use Net::DNS::Resolver;
|
|
||||||
use Time::HiRes qw(time);
|
use Time::HiRes qw(time);
|
||||||
use IO::Select;
|
use IO::Select;
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ sub init {
|
|||||||
my @whitelist = $self->qp->config('uribl_whitelist_domains');
|
my @whitelist = $self->qp->config('uribl_whitelist_domains');
|
||||||
$self->{whitelist_zones} = {(map { ($_ => 1) } @whitelist)};
|
$self->{whitelist_zones} = {(map { ($_ => 1) } @whitelist)};
|
||||||
|
|
||||||
$self->init_resolver;
|
$self->{resolver} = $self->get_resolver(timeout => $self->{timeout});
|
||||||
}
|
}
|
||||||
|
|
||||||
sub send_query {
|
sub send_query {
|
||||||
@ -533,8 +533,3 @@ sub hook_data {
|
|||||||
return DECLINED;
|
return DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub init_resolver {
|
|
||||||
my $self = shift;
|
|
||||||
$self->{resolver} = new Net::DNS::Resolver or return;
|
|
||||||
$self->{resolver}->udp_timeout($self->{timeout});
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,6 @@ use Qpsmtpd::Constants;
|
|||||||
sub register_tests {
|
sub register_tests {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
$self->register_test('test_init_resolver');
|
|
||||||
$self->register_test('test_is_in_badhelo');
|
$self->register_test('test_is_in_badhelo');
|
||||||
$self->register_test('test_is_regex_match');
|
$self->register_test('test_is_regex_match');
|
||||||
$self->register_test('test_invalid_localhost');
|
$self->register_test('test_invalid_localhost');
|
||||||
@ -24,17 +23,9 @@ sub register_tests {
|
|||||||
|
|
||||||
sub test_helo_handler {
|
sub test_helo_handler {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
cmp_ok( $self->helo_handler(undef, undef), '==', DECLINED, "empty host");
|
cmp_ok( $self->helo_handler(undef, undef), '==', DECLINED, "empty host");
|
||||||
};
|
};
|
||||||
|
|
||||||
sub test_init_resolver {
|
|
||||||
my $self = shift;
|
|
||||||
my $net_dns = $self->init_resolver();
|
|
||||||
ok( $net_dns, "net::dns" );
|
|
||||||
cmp_ok( ref $net_dns, 'eq', 'Net::DNS::Resolver', "ref ok");
|
|
||||||
};
|
|
||||||
|
|
||||||
sub test_is_in_badhelo {
|
sub test_is_in_badhelo {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
@ -3,11 +3,9 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Net::DNS;
|
|
||||||
use Qpsmtpd::Address;
|
use Qpsmtpd::Address;
|
||||||
use Qpsmtpd::Constants;
|
use Qpsmtpd::Constants;
|
||||||
|
|
||||||
my $res = new Net::DNS::Resolver(dnsrch => 0);
|
|
||||||
my $test_email = 'user@example.com';
|
my $test_email = 'user@example.com';
|
||||||
|
|
||||||
sub register_tests {
|
sub register_tests {
|
||||||
@ -60,17 +58,17 @@ sub test_get_and_validate_mx {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $transaction = $self->qp->transaction;
|
my $transaction = $self->qp->transaction;
|
||||||
|
|
||||||
ok( scalar $self->get_and_validate_mx( $res, 'perl.com', $transaction ) );
|
ok( scalar $self->get_and_validate_mx( 'perl.com', $transaction ) );
|
||||||
|
|
||||||
ok( ! scalar $self->get_host_records( $res, 'fake-domain-name-for-test.com', $transaction ) );
|
ok( ! scalar $self->get_host_records( 'fake-domain-name-for-test.com', $transaction ) );
|
||||||
};
|
};
|
||||||
|
|
||||||
sub test_get_host_records {
|
sub test_get_host_records {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $transaction = $self->qp->transaction;
|
my $transaction = $self->qp->transaction;
|
||||||
|
|
||||||
ok( scalar $self->get_host_records( $res, 'perl.com', $transaction ) );
|
ok( scalar $self->get_host_records( 'perl.com', $transaction ) );
|
||||||
ok( ! scalar $self->get_host_records( $res, 'fake-domain-name-for-test.com', $transaction ) );
|
ok( ! scalar $self->get_host_records( 'fake-domain-name-for-test.com', $transaction ) );
|
||||||
};
|
};
|
||||||
|
|
||||||
sub test_mx_address_resolves {
|
sub test_mx_address_resolves {
|
||||||
|
@ -16,6 +16,13 @@ my $base = Qpsmtpd::Base->new();
|
|||||||
__tildeexp();
|
__tildeexp();
|
||||||
__is_localhost();
|
__is_localhost();
|
||||||
__is_valid_ip();
|
__is_valid_ip();
|
||||||
|
__get_resolver();
|
||||||
|
__get_async_resolver();
|
||||||
|
__resolve_a();
|
||||||
|
__resolve_aaaa();
|
||||||
|
__resolve_mx();
|
||||||
|
__resolve_ns();
|
||||||
|
__resolve_ptr();
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|
||||||
@ -49,3 +56,43 @@ sub __tildeexp {
|
|||||||
$path = $base->tildeexp('no/tilde/in/path');
|
$path = $base->tildeexp('no/tilde/in/path');
|
||||||
cmp_ok( $path, 'eq', 'no/tilde/in/path', 'tildeexp, no expansion');
|
cmp_ok( $path, 'eq', 'no/tilde/in/path', 'tildeexp, no expansion');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sub __get_resolver {
|
||||||
|
my $res = $base->get_resolver();
|
||||||
|
isa_ok( $res, 'Net::DNS::Resolver', "get_resolver returns a Net::DNS::Resolver");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub __get_async_resolver {
|
||||||
|
my $res = $base->get_async_resolver() or return;
|
||||||
|
isa_ok( $res, 'Net::DNS::Async', "resolver object, $res");
|
||||||
|
isa_ok( $res->{Resolver}, 'Net::DNS::Resolver', "resolver object, $res");
|
||||||
|
}
|
||||||
|
|
||||||
|
sub __resolve_a {
|
||||||
|
my @r = $base->resolve_a('simerson.net');
|
||||||
|
ok(@r, "resolve_a: " . join(',', @r));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub __resolve_aaaa {
|
||||||
|
my @r = $base->resolve_aaaa('ns2.cadillac.net');
|
||||||
|
ok(@r, "resolve_aaaa: " . join(',', @r));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub __resolve_mx {
|
||||||
|
my @r = $base->resolve_mx('simerson.net');
|
||||||
|
ok(@r, "resolve_mx: " . join(',', @r));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub __resolve_ns {
|
||||||
|
my @r = $base->resolve_ns('simerson.net');
|
||||||
|
ok(@r, "resolve_ns: " . join(', ', @r));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub __resolve_ptr {
|
||||||
|
my @r = $base->resolve_ptr('163.51.128.66.in-addr.arpa.');
|
||||||
|
ok(@r, "resolve_ptr: FQDN: " . join(', ', @r));
|
||||||
|
|
||||||
|
@r = $base->resolve_ptr('66.128.51.163');
|
||||||
|
ok(@r, "resolve_ptr, IP: " . join(', ', @r));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user