The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

use strict;
our $VERSION = '1.20230216'; # VERSION
my $die_on = {};
{
my @_debug_output;
sub enable_debug {
my ( $self ) = @_;
$self->{_mock_debug} = 1;
$self->_add_debug( "Net::DNS::Resolver::Mock Debugging enabled" );
return;
}
sub disable_debug {
my ( $self ) = @_;
$self->clear_debug();
delete $self->{_mock_debug};
return;
}
sub _add_debug {
my ( $self, $debug ) = @_;
push @_debug_output, $debug;
warn $debug;
return;
}
sub clear_debug {
my ( $self ) = @_;
@_debug_output = ();
return;
}
sub get_debug {
my ( $self ) = @_;
return @_debug_output;
}
}
sub die_on {
my ( $self, $name, $type, $error ) = @_;
$die_on->{ "$name $type" } = $error;
return;
}
sub build_cache {
my ( $self ) = @_;
my $cache = {};
my $FakeZone = $self->{ 'zonefile' };
foreach my $Item ( @$FakeZone ) {
my $itemname = lc $Item->name();
my $itemtype = lc $Item->type();
my $key = join( ':', $itemname, $itemtype );
if ( ! exists $cache->{$key} ) {
$cache->{$key} = [];
}
push @{ $cache->{$key} }, $Item;
}
$self->{ 'zonefile_cache' } = $cache;
return;
}
sub zonefile_read {
my ( $self, $zonefile ) = @_;
$self->{ 'zonefile' } = Net::DNS::ZoneFile->read( $zonefile );
$self->build_cache();
return;
}
sub zonefile_parse {
my ( $self, $zonefile ) = @_;
$self->{ 'zonefile' } = Net::DNS::ZoneFile->parse( $zonefile );
$self->build_cache();
return;
}
sub send {
my ( $self, $name, $type ) = @_;
$self->_add_debug( "DNS Lookup '$name' '$type'" ) if $self->{_mock_debug};
if ( exists ( $die_on->{ "$name $type" } ) ) {
die $die_on->{ "$name $type" };
}
$name =~ s/\.$// unless $name eq '.';
my $origname = $name;
if ( lc $type eq 'ptr' ) {
if ( index( lc $name, '.in-addr.arpa' ) == -1 ) {
if ( $name =~ /^\d+\.\d+\.\d+\.\d+$/ ) {
$name = join( '.', reverse( split( /\./, $name ) ) );
$name .= '.in-addr.arpa';
}
}
}
my $Packet = Net::DNS::Packet->new();
$Packet->push( 'question' => Net::DNS::Question->new( $origname, $type, 'IN' ) );
my $key = join( ':', lc $name, lc $type );
my $cname_key = join( ':', lc $name, 'cname' );
if ( exists( $self->{ 'zonefile_cache' }->{ $cname_key } ) ) {
$Packet->push( 'answer' => @{ $self->{ 'zonefile_cache' }->{ $cname_key } } );
} elsif ( exists( $self->{ 'zonefile_cache' }->{ $key } ) ) {
$Packet->push( 'answer' => @{ $self->{ 'zonefile_cache' }->{ $key } } );
}
$Packet->{ 'answerfrom' } = '127.0.0.1';
$Packet->{ 'status' } = 33152;
return $Packet;
}
1;
__END__
=head1 NAME
Net::DNS::Resolver::Mock - Mock a DNS Resolver object for testing
=head1 DESCRIPTION
A subclass of Net::DNS::Resolver which parses a zonefile for it's data source. Primarily for use in testing.
=head1 SYNOPSIS
use Net::DNS::Resolver::Mock;
my $Resolver = Net::DNS::Resolver::Mock-new();
$Resolver->zonefile_read( $FileName );
# or
$Resolver->zonefile_parse( $String );
=head1 PUBLIC METHODS
=over
=item zonefile_read ( $FileName )
Reads specified file for zone data
=item zonefile_parse ( $String )
Reads the zone data from the supplied string
=item die_on ( $Name, $Type, $Error )
Die with $Error for a query of $Name and $Type
=item enable_debug ()
Once set, the resolver will write any lookups received to STDERR
and will be available via the following methods
=item disble_debug ()
Disable debugging
=item clear_debug ()
Clear the debugging list
=item get_debug ()
Returns a list of debugging entries
=back
=head1 DEPENDENCIES
Net::DNS::Resolver
Net::DNS::Packet
Net::DNS::Question
Net::DNS::ZoneFile
=head1 BUGS
Please report bugs via the github tracker.
=head1 AUTHORS
Marc Bradshaw, E<lt>marc@marcbradshaw.netE<gt>
=head1 COPYRIGHT
Copyright (c) 2017, Marc Bradshaw.
=head1 LICENCE
This library is free software; you may redistribute it and/or modify it
under the same terms as Perl itself.
=cut