Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New "resolver.source4" and "resolver.source6" properties #1203

Merged
6 commits merged into from Mar 13, 2023
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ jobs:
build-essential \
gettext \
libidn2-dev \
liblog-any-perl \
libssl-dev \
libtool \
m4 \
Expand Down
1 change: 1 addition & 0 deletions Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ requires 'File::Slurp' => 0;
requires 'IO::Socket::INET6' => 2.69;
requires 'List::MoreUtils' => 0;
requires 'Locale::TextDomain' => 1.20;
requires 'Log::Any' => 0,
requires 'Module::Find' => 0.10;
requires 'Moose' => 2.0401;
requires 'MooseX::Singleton' => 0.30;
Expand Down
8 changes: 4 additions & 4 deletions docs/Installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Zonemaster::Engine, see the [declaration of prerequisites].
3) Install binary packages:

```sh
sudo dnf --assumeyes install cpanminus gcc libidn2-devel openssl-devel perl-Class-Accessor perl-Clone perl-core perl-Devel-CheckLib perl-Email-Valid perl-File-ShareDir perl-File-Slurp perl-libintl perl-IO-Socket-INET6 perl-List-MoreUtils perl-Locale-PO perl-Module-Find perl-Module-Install perl-Moose perl-Net-DNS perl-Pod-Coverage perl-Readonly perl-Test-Differences perl-Test-Exception perl-Test-Fatal perl-Test-NoWarnings perl-Test-Pod perl-Text-CSV perl-Test-Simple perl-YAML
sudo dnf --assumeyes install cpanminus gcc libidn2-devel openssl-devel perl-Class-Accessor perl-Clone perl-core perl-Devel-CheckLib perl-Email-Valid perl-File-ShareDir perl-File-Slurp perl-libintl perl-IO-Socket-INET6 perl-List-MoreUtils perl-Locale-PO perl-Log-Any perl-Module-Find perl-Module-Install perl-Moose perl-Net-DNS perl-Pod-Coverage perl-Readonly perl-Test-Differences perl-Test-Exception perl-Test-Fatal perl-Test-NoWarnings perl-Test-Pod perl-Text-CSV perl-Test-Simple perl-YAML
```

4) Install packages from CPAN:
Expand Down Expand Up @@ -108,7 +108,7 @@ Using pre-built packages is the preferred method for Debian and Ubuntu.
2) Install dependencies from binary packages:

```sh
sudo apt install autoconf automake build-essential cpanminus libclass-accessor-perl libclone-perl libdevel-checklib-perl libemail-valid-perl libfile-sharedir-perl libfile-slurp-perl libidn2-dev libintl-perl libio-socket-inet6-perl liblist-moreutils-perl liblocale-po-perl libmodule-find-perl libmodule-install-perl libmodule-install-xsutil-perl libmoose-perl libmoosex-singleton-perl libnet-dns-perl libnet-ip-xs-perl libpod-coverage-perl libreadonly-perl libssl-dev libtest-differences-perl libtest-exception-perl libtest-fatal-perl libtest-nowarnings-perl libtest-pod-perl libtext-csv-perl libtool m4
sudo apt install autoconf automake build-essential cpanminus libclass-accessor-perl libclone-perl libdevel-checklib-perl libemail-valid-perl libfile-sharedir-perl libfile-slurp-perl libidn2-dev libintl-perl libio-socket-inet6-perl liblist-moreutils-perl liblocale-po-perl liblog-any-perl libmodule-find-perl libmodule-install-perl libmodule-install-xsutil-perl libmoose-perl libmoosex-singleton-perl libnet-dns-perl libnet-ip-xs-perl libpod-coverage-perl libreadonly-perl libssl-dev libtest-differences-perl libtest-exception-perl libtest-fatal-perl libtest-nowarnings-perl libtest-pod-perl libtext-csv-perl libtool m4
```

3) Install Zonemaster::LDNS and Zonemaster::Engine.
Expand Down Expand Up @@ -154,7 +154,7 @@ Using pre-built packages is the preferred method for Debian and Ubuntu.
5) Install dependencies from binary packages:

```sh
pkg install devel/gmake libidn2 p5-App-cpanminus p5-Class-Accessor p5-Clone p5-Devel-CheckLib p5-Email-Valid p5-File-ShareDir p5-File-Slurp p5-IO-Socket-INET6 p5-List-MoreUtils p5-Locale-libintl p5-Module-Find p5-Module-Install p5-Module-Install-XSUtil p5-Moose p5-MooseX-Singleton p5-Net-DNS p5-Net-IP-XS p5-Pod-Coverage p5-Readonly p5-Test-Differences p5-Test-Exception p5-Test-Fatal p5-Test-NoWarnings p5-Test-Pod p5-Text-CSV dns/ldns
pkg install devel/gmake libidn2 p5-App-cpanminus p5-Class-Accessor p5-Clone p5-Devel-CheckLib p5-Email-Valid p5-File-ShareDir p5-File-Slurp p5-IO-Socket-INET6 p5-List-MoreUtils p5-Locale-libintl p5-Log-Any p5-Module-Find p5-Module-Install p5-Module-Install-XSUtil p5-Moose p5-MooseX-Singleton p5-Net-DNS p5-Net-IP-XS p5-Pod-Coverage p5-Readonly p5-Test-Differences p5-Test-Exception p5-Test-Fatal p5-Test-NoWarnings p5-Test-Pod p5-Text-CSV dns/ldns
```

6) Install Zonemaster::LDNS:
Expand Down Expand Up @@ -187,7 +187,7 @@ Using pre-built packages is the preferred method for Debian and Ubuntu.
2) Install binary packages:

```sh
sudo yum --assumeyes install cpanminus gcc libidn2-devel openssl-devel openssl11-devel perl-Class-Accessor perl-Clone perl-core perl-Devel-CheckLib perl-Email-Valid perl-File-ShareDir perl-File-Slurp perl-libintl perl-IO-Socket-INET6 perl-List-MoreUtils perl-Locale-PO perl-Module-Find perl-Module-Install perl-Moose perl-Net-DNS perl-Pod-Coverage perl-Readonly perl-Test-Differences perl-Test-Exception perl-Test-Fatal perl-Test-NoWarnings perl-Test-Pod perl-Text-CSV perl-Test-Simple perl-YAML
sudo yum --assumeyes install cpanminus gcc libidn2-devel openssl-devel openssl11-devel perl-Class-Accessor perl-Clone perl-core perl-Devel-CheckLib perl-Email-Valid perl-File-ShareDir perl-File-Slurp perl-libintl perl-IO-Socket-INET6 perl-List-MoreUtils perl-Locale-PO perl-Log-Any perl-Module-Find perl-Module-Install perl-Moose perl-Net-DNS perl-Pod-Coverage perl-Readonly perl-Test-Differences perl-Test-Exception perl-Test-Fatal perl-Test-NoWarnings perl-Test-Pod perl-Text-CSV perl-Test-Simple perl-YAML
```

3) Install packages from CPAN:
Expand Down
64 changes: 52 additions & 12 deletions lib/Zonemaster/Engine/Nameserver.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use Zonemaster::Engine;
use Zonemaster::Engine::Packet;
use Zonemaster::Engine::Nameserver::Cache;
use Zonemaster::Engine::Recursor;
use Zonemaster::Engine::Constants ':misc';
use Zonemaster::Engine::Constants qw( :ip :misc );
use Zonemaster::LDNS;

use Net::IP::XS;
Expand All @@ -37,7 +37,9 @@ has 'dns' => ( is => 'ro' );
has 'cache' => ( is => 'ro' );
has 'times' => ( is => 'ro' );

has 'source_address' => ( 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 @@ -62,9 +64,11 @@ sub new {
my $attrs = shift;

my %lazy_attrs;
$lazy_attrs{source_address} = delete $attrs->{source_address} if exists $attrs->{source_address};
$lazy_attrs{dns} = delete $attrs->{dns} if exists $attrs->{dns};
$lazy_attrs{cache} = delete $attrs->{cache} if exists $attrs->{cache};
$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};

# Required arguments
confess "Attribute \(address\) is required"
Expand Down Expand Up @@ -118,6 +122,12 @@ sub new {
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 @@ -132,9 +142,11 @@ 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->{_dns} = $lazy_attrs{dns} if exists $lazy_attrs{dns};
$obj->{_cache} = $lazy_attrs{cache} if exists $lazy_attrs{cache};
$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};

Zonemaster::Engine->logger->add( NS_CREATED => { name => $name, ip => $obj->address->ip } );
$object_cache{$name}{$address} = $obj;
Expand All @@ -143,9 +155,9 @@ sub new {
}

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

# Lazy default value
# 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 ) {
Expand All @@ -155,6 +167,21 @@ sub source_address {
$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};
}
Expand Down Expand Up @@ -197,8 +224,10 @@ sub _build_dns {
$res->edns_size( Zonemaster::Engine::Profile->effective->get( q{resolver.defaults.edns_size} ) );
$res->timeout( Zonemaster::Engine::Profile->effective->get( q{resolver.defaults.timeout} ) );

if ( $self->source_address ) {
$res->source( $self->source_address );
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 );
}

return $res;
Expand Down Expand Up @@ -752,6 +781,17 @@ A reference to a L<Zonemaster::Engine::Nameserver::Cache> object holding the cac
=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

Expand Down
52 changes: 51 additions & 1 deletion lib/Zonemaster/Engine/Profile.pm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use File::Slurp;
use Clone qw(clone);
use Data::Dumper;
use Net::IP::XS;
use Log::Any qw( $log );

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 );

Expand Down Expand Up @@ -56,10 +57,28 @@ my %profile_properties_details = (
type => q{Str},
test => sub {
if ( $_[0] ne $RESOLVER_SOURCE_OS_DEFAULT ) {
Net::IP::XS->new( $_[0] ) || die "Property resolver.source must be an IP address or the exact string $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" );
}
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" );
}
Net::IP::XS->new( $_[0] );
}
},
q{net.ipv4} => {
type => q{Bool}
},
Expand Down Expand Up @@ -257,9 +276,18 @@ 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'." );
}
}

sub get {
my ( $self, $property_name ) = @_;

Expand Down Expand Up @@ -359,6 +387,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 @@ -374,6 +403,7 @@ sub from_json {
}
}

$new->check_validity;
return $new;
}

Expand Down Expand Up @@ -494,6 +524,10 @@ 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 @@ -622,11 +656,27 @@ 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.
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).

=head2 resolver.source6

A string that is an IPv6 address or the empty string or undefined.
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).

=head2 net.ipv4

A boolean. If true, resolver objects are allowed to send queries over
Expand Down
3 changes: 1 addition & 2 deletions share/profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
"retry" : 2,
"usevc" : false,
"timeout": 5
},
"source": "os_default"
}
},
"test_levels" : {
"ADDRESS" : {
Expand Down
4 changes: 4 additions & 0 deletions share/profile_additional_properties.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"resolver" : {
"source4": "192.0.2.53",
"source6": "2001:db8::42"
},
"logfilter" : {
"BASIC" : {
"IPV6_ENABLED" : [
Expand Down
Loading