Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ lib/Zonemaster/Engine/TestMethods.pm
lib/Zonemaster/Engine/TestMethodsV2.pm
lib/Zonemaster/Engine/Translator.pm
lib/Zonemaster/Engine/Util.pm
lib/Zonemaster/Engine/Validation.pm
lib/Zonemaster/Engine/Zone.pm
LICENSE
Makefile.PL
Expand Down Expand Up @@ -291,6 +292,7 @@ t/translator.t
t/undelegated.data
t/undelegated.t
t/util.t
t/validation.t
t/zone.data
t/zone.t
t/zonemaster.data
Expand Down
5 changes: 1 addition & 4 deletions lib/Zonemaster/Engine/Constants.pm
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ our @EXPORT_OK = qw[
$SERIAL_BITS
$SERIAL_MAX_VARIATION
$MINIMUM_NUMBER_OF_NAMESERVERS
$RESOLVER_SOURCE_OS_DEFAULT
$UDP_PAYLOAD_LIMIT
$UDP_EDNS_QUERY_DEFAULT
$UDP_COMMON_EDNS_LIMIT
Expand All @@ -101,7 +100,7 @@ our %EXPORT_TAGS = (
soa => [
qw($DURATION_5_MINUTES_IN_SECONDS $DURATION_1_HOUR_IN_SECONDS $DURATION_4_HOURS_IN_SECONDS $DURATION_12_HOURS_IN_SECONDS $DURATION_1_DAY_IN_SECONDS $DURATION_1_WEEK_IN_SECONDS $DURATION_180_DAYS_IN_SECONDS $SERIAL_BITS $SERIAL_MAX_VARIATION)
],
misc => [qw($UDP_PAYLOAD_LIMIT $UDP_EDNS_QUERY_DEFAULT $UDP_COMMON_EDNS_LIMIT $MINIMUM_NUMBER_OF_NAMESERVERS $RESOLVER_SOURCE_OS_DEFAULT $BLACKLISTING_ENABLED)]
misc => [qw($UDP_PAYLOAD_LIMIT $UDP_EDNS_QUERY_DEFAULT $UDP_COMMON_EDNS_LIMIT $MINIMUM_NUMBER_OF_NAMESERVERS $BLACKLISTING_ENABLED)]
, # everyting in %EXPORT_OK that isn't included in any of the other tags
addresses => [qw(@IPV4_SPECIAL_ADDRESSES @IPV6_SPECIAL_ADDRESSES)],
);
Expand Down Expand Up @@ -197,8 +196,6 @@ Readonly our $IP_VERSION_6 => 6;

Readonly our $MINIMUM_NUMBER_OF_NAMESERVERS => 2;

Readonly our $RESOLVER_SOURCE_OS_DEFAULT => 'os_default';

Readonly our $SERIAL_BITS => 32;
Readonly our $SERIAL_MAX_VARIATION => 0;

Expand Down
94 changes: 23 additions & 71 deletions lib/Zonemaster/Engine/Nameserver.pm
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ has 'dns' => ( is => 'ro' );
has 'cache' => ( is => 'ro' );
has 'times' => ( is => 'ro' );

has 'source_address' => ( is => 'ro' );
has 'source_address4' => ( is => 'ro' );
has 'source_address6' => ( is => 'ro' );

has 'fake_delegations' => ( is => 'ro' );
has 'fake_ds' => ( is => 'ro' );

Expand All @@ -64,9 +60,6 @@ sub new {
my $attrs = shift;

my %lazy_attrs;
$lazy_attrs{source_address} = delete $attrs->{source_address} if exists $attrs->{source_address};
$lazy_attrs{source_address4} = delete $attrs->{source_address4} if exists $attrs->{source_address4};
$lazy_attrs{source_address6} = delete $attrs->{source_address6} if exists $attrs->{source_address6};
$lazy_attrs{dns} = delete $attrs->{dns} if exists $attrs->{dns};
$lazy_attrs{cache} = delete $attrs->{cache} if exists $attrs->{cache};

Expand Down Expand Up @@ -119,15 +112,6 @@ sub new {
confess "Argument must be a HASHREF: blacklisted"
if exists $attrs->{blacklisted}
&& ref $attrs->{blacklisted} ne 'HASH';
confess "Argument must be a string or undef: source_address"
if exists $lazy_attrs{source_address}
&& ref $lazy_attrs{source_address} ne '';
confess "Argument must be a string or undef: source_address4"
if exists $lazy_attrs{source_address4}
&& ref $lazy_attrs{source_address4} ne '';
confess "Argument must be a string or undef: source_address6"
if exists $lazy_attrs{source_address6}
&& ref $lazy_attrs{source_address6} ne '';
confess "Argument must be a Zonemaster::LDNS: dns"
if exists $lazy_attrs{dns}
&& ( !blessed $lazy_attrs{dns} || !$lazy_attrs{dns}->isa( 'Zonemaster::LDNS' ) );
Expand All @@ -142,9 +126,6 @@ sub new {
$attrs->{times} //= [];

my $obj = Class::Accessor::new( $class, $attrs );
$obj->{_source_address} = $lazy_attrs{source_address} if exists $lazy_attrs{source_address};
$obj->{_source_address4} = $lazy_attrs{source_address4} if exists $lazy_attrs{source_address4};
$obj->{_source_address6} = $lazy_attrs{source_address6} if exists $lazy_attrs{source_address6};
$obj->{_dns} = $lazy_attrs{dns} if exists $lazy_attrs{dns};
$obj->{_cache} = $lazy_attrs{cache} if exists $lazy_attrs{cache};

Expand All @@ -154,38 +135,6 @@ sub new {
return $obj;
}

sub source_address {
my ( $self, $ip_version ) = @_;

# Lazy default values
if ( !exists $self->{_source_address} ) {
my $value = Zonemaster::Engine::Profile->effective->get( q{resolver.source} );
if ( $value eq $RESOLVER_SOURCE_OS_DEFAULT ) {
$self->{_source_address} = undef;
}
else {
$self->{_source_address} = $value;
}
}
if ( !exists $self->{_source_address4} ) {
my $value = Zonemaster::Engine::Profile->effective->get( q{resolver.source4} );
$self->{_source_address4} = $value eq '' ? undef : $value;
}
if ( !exists $self->{_source_address6} ) {
my $value = Zonemaster::Engine::Profile->effective->get( q{resolver.source6} );
$self->{_source_address6} = $value eq '' ? undef : $value;
}

if ( $ip_version == $IP_VERSION_4 and $self->{_source_address4} ) {
return $self->{_source_address4};
}
if ( $ip_version == $IP_VERSION_6 and $self->{_source_address6} ) {
return $self->{_source_address6};
}

return $self->{_source_address};
}

sub dns {
my $self = shift;

Expand All @@ -212,7 +161,7 @@ sub _build_dns {
my ( $self ) = @_;

my $res = Zonemaster::LDNS->new( $self->address->ip );

$res->recurse( 0 );
$res->dnssec( 0 );
$res->edns_size( $UDP_EDNS_QUERY_DEFAULT );
Expand All @@ -225,10 +174,9 @@ sub _build_dns {
$res->debug( Zonemaster::Engine::Profile->effective->get( q{resolver.defaults.debug} ) );
$res->timeout( Zonemaster::Engine::Profile->effective->get( q{resolver.defaults.timeout} ) );

my $ip_version = Net::IP::XS::ip_get_version( $self->address->ip );
my $source_address = $self->source_address( $ip_version );
if ( $source_address ) {
$res->source( $source_address );
my $src_address = $self->source_address();
if ( defined( $src_address ) ) {
$res->source( $src_address );
}

return $res;
Expand Down Expand Up @@ -719,6 +667,14 @@ sub axfr {
return $self->dns->axfr( $domain, $callback, $class );
} ## end sub axfr

sub source_address {
my ( $self ) = @_;

my $src_address = Zonemaster::Engine::Profile->effective->get( "resolver.source" . Net::IP::XS::ip_get_version( $self->address->ip ) );

return $src_address eq '' ? undef : $src_address;
}

sub empty_cache {
%object_cache = ();
%address_object_cache = ();
Expand Down Expand Up @@ -773,21 +729,6 @@ The L<Zonemaster::LDNS> object used to actually send and recieve DNS queries.

A reference to a L<Zonemaster::Engine::Nameserver::Cache> object holding the cache of sent queries. Not meant for external use.

=item source_address

The source address all resolver objects should use when sending queries.
Depends on the IP version used to send the queries.

=item source_address4

The IPv4 source address all resolver objects should use when sending queries
over IPv4.

=item source_address6

The IPv6 source address all resolver objects should use when sending queries
over IPv6.

=item times

A reference to a list with elapsed time values for the queries made through this nameserver.
Expand Down Expand Up @@ -955,6 +896,17 @@ argument. To continue getting more RRs, the callback must return a true value.
If it returns a true value, the AXFR will be aborted. See L<Zonemaster::LDNS::axfr>
for more details.

=item source_address()

my $src_address = source_address();

Returns the configured IPv4 or IPv6 source address to be used by the underlying DNS resolver for sending queries,
or C<undef> if the source address is the empty string.

=item empty_cache()

Clears the caches of Zonemaster::Engine::Nameserver (name server names and IP addresses) and Zonemaster::Engine::Nameserver::Cache (query and response packets) objects.

=back

=cut
66 changes: 19 additions & 47 deletions lib/Zonemaster/Engine/Profile.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ use version; our $VERSION = version->declare( "v1.2.22" );

use File::ShareDir qw[dist_file];
use JSON::PP qw( encode_json decode_json );
use Scalar::Util qw(reftype);
use Scalar::Util qw(reftype looks_like_number);
use File::Slurp;
use Clone qw(clone);
use Data::Dumper;
use Net::IP::XS;
use Log::Any qw( $log );
use YAML::XS qw();
use Scalar::Util qw( looks_like_number );

$YAML::XS::Boolean = "JSON::PP";

use Zonemaster::Engine::Constants qw( $RESOLVER_SOURCE_OS_DEFAULT $DURATION_5_MINUTES_IN_SECONDS $DURATION_1_HOUR_IN_SECONDS $DURATION_4_HOURS_IN_SECONDS $DURATION_12_HOURS_IN_SECONDS $DURATION_1_DAY_IN_SECONDS $DURATION_1_WEEK_IN_SECONDS $DURATION_180_DAYS_IN_SECONDS );
use Zonemaster::Engine::Constants qw( $DURATION_5_MINUTES_IN_SECONDS $DURATION_1_HOUR_IN_SECONDS $DURATION_4_HOURS_IN_SECONDS $DURATION_12_HOURS_IN_SECONDS $DURATION_1_DAY_IN_SECONDS $DURATION_1_WEEK_IN_SECONDS $DURATION_180_DAYS_IN_SECONDS );
use Zonemaster::Engine::Validation qw( validate_ipv4 validate_ipv6 );

my %profile_properties_details = (
q{cache} => {
Expand Down Expand Up @@ -81,30 +81,20 @@ my %profile_properties_details = (
q{resolver.defaults.timeout} => {
type => q{Num}
},
q{resolver.source} => {
type => q{Str},
test => sub {
if ( $_[0] ne $RESOLVER_SOURCE_OS_DEFAULT ) {
Net::IP::XS->new( $_[0] ) || $log->warning( "Property resolver.source must be an IP address or the exact string $RESOLVER_SOURCE_OS_DEFAULT" );
}
}
},
q{resolver.source4} => {
type => q{Str},
test => sub {
if ( $_[0] and $_[0] ne '' and not Net::IP::XS::ip_is_ipv4( $_[0] ) ) {
$log->warning( "Property resolver.source4 must be an IPv4 address, the empty string or undefined" );
unless ( $_[0] eq '' or validate_ipv4( $_[0] ) ) {
die "Property resolver.source4 must be a valid IPv4 address";
}
Net::IP::XS->new( $_[0] );
}
},
q{resolver.source6} => {
type => q{Str},
test => sub {
if ( $_[0] and $_[0] ne '' and not Net::IP::XS::ip_is_ipv6( $_[0] ) ) {
$log->warning( "Property resolver.source6 must be an IPv6 address, the empty string or undefined" );
unless ( $_[0] eq '' or validate_ipv6( $_[0] ) ) {
die "Property resolver.source6 must be a valid IPv6 address";
}
Net::IP::XS->new( $_[0] );
}
},
q{net.ipv4} => {
Expand Down Expand Up @@ -304,16 +294,8 @@ sub default {
$new->set( $property_name, $profile_properties_details{$property_name}{default} );
}
}
$new->check_validity;
return $new;
}

sub check_validity {
my ( $self ) = @_;
my $resolver = $self->{profile}{resolver};
if ( exists $resolver->{source} and ( exists $resolver->{source4} or exists $resolver->{source6} ) ) {
$log->warning( "Error in profile: 'resolver.source' (deprecated) can't be used in combination with 'resolver.source4' or 'resolver.source6'." );
}
return $new;
}

sub get {
Expand Down Expand Up @@ -415,7 +397,7 @@ sub merge {
$self->_set( q{JSON}, $property_name, _get_value_from_nested_hash( $other_profile->{q{profile}}, split /[.]/, $property_name ) );
}
}
$self->check_validity;

return $other_profile->{q{profile}};
}

Expand All @@ -431,7 +413,6 @@ sub from_json {
}
}

$new->check_validity;
return $new;
}

Expand Down Expand Up @@ -578,10 +559,6 @@ PROPERTIES> section.

=head1 INSTANCE METHODS

=head2 check_validity

Verify that the profile does not allow confusing combinations.

=head2 get

Get the value of a property.
Expand Down Expand Up @@ -709,28 +686,23 @@ the same query is resent with EDNS0 and TCP (if needed). If you
want the original answer (with TC bit set) and avoid this kind of
replay, set this flag to false.

=head2 resolver.source

Deprecated (planned removal: v2024.1).
Use L</resolver.source4> and L</resolver.source6>.
A string that is either an IP address or the exact string C<"os_default">.
The source address all resolver objects should use when sending queries.
If C<"os_default">, the OS default address is used.
Default C<"os_default">.

=head2 resolver.source4

A string that is an IPv4 address or the empty string or undefined.
A string representation of an IPv4 address or the empty string.
The source address all resolver objects should use when sending queries over IPv4.
If the empty string or undefined, use the OS default IPv4 address if available.
Default "" (empty string).

If set to "" (empty string), the OS default IPv4 address is used.

Default: "" (empty string).

=head2 resolver.source6

A string that is an IPv6 address or the empty string or undefined.
A string representation of an IPv6 address or the empty string.
The source address all resolver objects should use when sending queries over IPv6.
If the empty string or undefined, use the OS default IPv6 address if available.
Default "" (empty string).

If set to "" (empty string), the OS default IPv6 address is used.

Default: "" (empty string).

=head2 net.ipv4

Expand Down
Loading