Net-DNS-Resolver-Unbound-1.21/0000755000175000017500000000000014440656753014210 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.21/Unbound.xs0000644000175000017500000001654614440647513016204 0ustar rwfrwf =head1 NAME Unbound.xs - Perl binding for NLnetLabs libunbound =head1 DESCRIPTION Perl XS extension providing access to the libunbound resolver library. This implementation is intended to support Net::DNS::Resolver::Unbound. It is NOT, nor will it ever be, suitable for general use. =head1 COPYRIGHT Copyright (c)2022-2023 Dick Franks All Rights Reserved =head1 LICENSE Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the original copyright notices appear in all copies and that both copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =cut #ifdef __cplusplus extern "C" { #endif #define PERL_NO_GET_CONTEXT #define PERL_REENTRANT #include #include #include #include #ifdef __cplusplus } #endif #define UNBOUND_VERSION (UNBOUND_VERSION_MAJOR*100 + UNBOUND_VERSION_MINOR)*100 + UNBOUND_VERSION_MICRO #define checkerr(arg) checkret( (arg), __LINE__ ) static void checkret(const int err, int line) { if (err) croak( "%s (%d) %s line %d", ub_strerror(err), err, __FILE__, line ); } typedef struct ub_ctx* Net__DNS__Resolver__Unbound__Context; typedef struct ub_result* Net__DNS__Resolver__Unbound__Result; typedef struct av* Net__DNS__Resolver__Unbound__Handle; static void async_callback(void* mydata, int err, struct ub_result* result) { dTHX; /* fetch context */ SV* resobj = newSV(0); sv_setref_pv(resobj, "Net::DNS::Resolver::Unbound::Result", (void*)result); av_push( (AV*)mydata, newSViv(err) ); av_push( (AV*)mydata, resobj ); return; } MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::Unbound::Handle PROTOTYPES: ENABLE void DESTROY(struct av* handle) CODE: sv_2mortal( (SV*) handle ); int query_id(struct av* handle) INIT: SV** index = av_fetch(handle, 0, 0); int id = SvIVX(*index); CODE: RETVAL = id; OUTPUT: RETVAL SV* err(struct av* handle) INIT: SV** index = av_fetch(handle, 1, 0); int err = index ? SvIVX(*index) : 0; CODE: RETVAL = newSVpvf( err ? "%s (%d)" : "", ub_strerror(err), err ); OUTPUT: RETVAL SV* result(struct av* handle) INIT: SV** index = av_fetch(handle, 2, 0); CODE: RETVAL = index ? av_pop(handle) : newSVpv("", 0); OUTPUT: RETVAL int waiting(struct av* handle) INIT: SV** index = av_fetch(handle, 1, 0); CODE: RETVAL = index ? 0 : 1; OUTPUT: RETVAL MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::Unbound::Result void DESTROY(struct ub_result* result) CODE: ub_resolve_free(result); SV* answer_packet(struct ub_result* result) CODE: RETVAL = newSVpvn( result->answer_packet, result->answer_len ); OUTPUT: RETVAL int secure(struct ub_result* result) CODE: RETVAL = result->secure; OUTPUT: RETVAL int bogus(struct ub_result* result) CODE: RETVAL = result->bogus; OUTPUT: RETVAL SV* why_bogus(struct ub_result* result) CODE: RETVAL = newSVpv( result->why_bogus, 0 ); OUTPUT: RETVAL MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::Unbound::Context Net::DNS::Resolver::Unbound::Context new(void) CODE: RETVAL = ub_ctx_create(); OUTPUT: RETVAL void DESTROY(struct ub_ctx* context) CODE: ub_ctx_delete(context); void set_option(struct ub_ctx* ctx, SV* opt, SV* val) CODE: checkerr( ub_ctx_set_option(ctx, (const char*) SvPVX(opt), (const char*) SvPVX(val)) ); SV* get_option(struct ub_ctx* ctx, SV* opt) INIT: char* value; CODE: checkerr( ub_ctx_get_option(ctx, (const char*) SvPVX(opt), &value) ); RETVAL = newSVpv( value, 0 ); free(value); OUTPUT: RETVAL void config(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_config(ctx, fname) ); void set_fwd(struct ub_ctx* ctx, const char* addr) CODE: checkerr( ub_ctx_set_fwd(ctx, addr) ); void resolv_conf(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_resolvconf(ctx, fname) ); void hosts(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_hosts(ctx, fname) ); void add_ta(struct ub_ctx* ctx, const char* ta) CODE: checkerr( ub_ctx_add_ta(ctx, ta) ); void add_ta_file(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_add_ta_file(ctx, fname) ); void trusted_keys(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_trustedkeys(ctx, fname) ); void debug_out(struct ub_ctx* ctx, const char* out) CODE: checkerr( ub_ctx_debugout(ctx, (void*) out) ); void debug_level(struct ub_ctx* ctx, int d) CODE: checkerr( ub_ctx_debuglevel(ctx, d) ); void async(struct ub_ctx* ctx, int dothread) CODE: checkerr( ub_ctx_async(ctx, dothread) ); Net::DNS::Resolver::Unbound::Result ub_resolve(struct ub_ctx* ctx, SV* name, int rrtype, int rrclass) CODE: checkerr( ub_resolve(ctx, (const char*) SvPVX(name), rrtype, rrclass, &RETVAL) ); OUTPUT: RETVAL Net::DNS::Resolver::Unbound::Handle ub_resolve_async(struct ub_ctx* ctx, SV* name, int rrtype, int rrclass, int query_id=0) INIT: int async_id = 0; CODE: RETVAL = newAV(); checkerr( ub_resolve_async(ctx, (const char*) SvPVX(name), rrtype, rrclass, (void*) RETVAL, async_callback, &async_id) ); av_push(RETVAL, newSViv(query_id) ); OUTPUT: RETVAL void ub_process(struct ub_ctx* ctx) CODE: checkerr( ub_process(ctx) ); void ub_wait(struct ub_ctx* ctx) CODE: checkerr( ub_wait(ctx) ); #if !(UNBOUND_VERSION < 10900) void set_stub(struct ub_ctx* ctx, const char* zone, const char* addr, int isprime) CODE: checkerr( ub_ctx_set_stub(ctx, zone, addr, isprime) ); void add_ta_autr(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_add_ta_autr(ctx, fname) ); void set_tls(struct ub_ctx* ctx, int tls) CODE: checkerr( ub_ctx_set_tls(ctx, tls) ); #endif ######################## ## TEST PURPOSES ONLY ## ######################## Net::DNS::Resolver::Unbound::Result mock_resolve(struct ub_ctx* ctx, SV* name, int secure, int bogus) CODE: checkerr( ub_resolve(ctx, (const char*) SvPVX(name), 1, 1, &RETVAL) ); if (bogus) RETVAL->answer_packet = NULL; RETVAL->secure = secure; RETVAL->bogus = bogus; OUTPUT: RETVAL MODULE = Net::DNS::Resolver::Unbound PACKAGE = Net::DNS::Resolver::libunbound SV* VERSION(void) CODE: RETVAL = newSVpv( ub_version(), 0 ); OUTPUT: RETVAL Net::DNS::Resolver::Unbound::Handle emulate_callback(int async_id, int err, struct ub_result* result=NULL) CODE: RETVAL = newAV(); av_push(RETVAL, newSViv(async_id) ); async_callback( (void*) RETVAL, err, result ); OUTPUT: RETVAL Net::DNS::Resolver::Unbound::Handle emulate_wait(int async_id) CODE: RETVAL = newAV(); av_push(RETVAL, newSViv(async_id) ); OUTPUT: RETVAL #ifdef croak_memory_wrap void croak_memory_wrap() #endif ######################## Net-DNS-Resolver-Unbound-1.21/lib/0000755000175000017500000000000014440656753014756 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.21/lib/Net/0000755000175000017500000000000014440656753015504 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.21/lib/Net/DNS/0000755000175000017500000000000014440656753016130 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.21/lib/Net/DNS/Resolver/0000755000175000017500000000000014440656753017731 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.21/lib/Net/DNS/Resolver/Unbound.pm0000644000175000017500000002605414440656432021702 0ustar rwfrwfpackage Net::DNS::Resolver::Unbound; use strict; use warnings; use Net::DNS; use base qw(Net::DNS::Resolver DynaLoader); our $VERSION; BEGIN { $VERSION = '1.21'; eval { __PACKAGE__->bootstrap($VERSION) }; } use constant UB_SEND => Net::DNS::Resolver::Unbound::Context->can('ub_send'); =head1 NAME Net::DNS::Resolver::Unbound - Net::DNS resolver based on libunbound =head1 SYNOPSIS use Net::DNS; use Net::DNS::Resolver::Unbound; my $resolver = Net::DNS::Resolver::Unbound->new(...); my $response = $resolver->send(...); =head1 DESCRIPTION Net::DNS::Resolver::Unbound is designed as an extension to an existing Net::DNS installation which facilitates DNS(SEC) name resolution using the libunbound library developed by NLnet Labs. Net::DNS::Resolver::Unbound replaces the resolver send() and bgsend() functionality in the Net::DNS::Resolver::Base implementation. As of this writing, the implementation has some significant limitations: =over 3 =item * Selection of transport protocol and associated parameters is entirely at the discretion of Unbound. =item * There is no provision for specifying DNS header flags or EDNS options in outbound packets. =item * It is not possible to send a pre-constructed packet to a nameserver. A best-effort attempt is made instead using (qname,qtype,qclass) extracted from the presented packet. =back =head1 METHODS =head2 new my $resolver = Net::DNS::Resolver::Unbound->new( debug_level => 2, defnames => 1, dnsrch, => 1, domain => 'domain', ndots => 1, searchlist => ['domain' ... ], nameservers => [ ... ], option => ['logfile', 'mylog.txt'] ); Returns a new Net::DNS::Resolver::Unbound resolver object. =cut sub new { my ( $class, @argument ) = @_; my $self = $class->SUPER::new(); $self->{ub_ctx} = Net::DNS::Resolver::Unbound::Context->new(); while ( my $attr = shift @argument ) { my $value = shift @argument; $self->$attr( ref($value) ? @$value : $value ); } return $self; } =head2 nameservers my $stub_resolver = Net::DNS::Resolver::Unbound->new( nameservers => [ '127.0.0.53' ] ); my $fully_recursive = Net::DNS::Resolver::Unbound->new( nameservers => [] # override /etc/resolv.conf ); my $dnssec_resolver = Net::DNS::Resolver::Unbound->new( nameservers => [], add_ta_file => '/var/lib/unbound/root.key' ); my @nameservers = $stub_resolver->nameservers; By default, DNS queries are sent to the IP addresses listed in /etc/resolv.conf or similar platform-specific sources. =cut sub nameservers { my $self = shift; local $self->{debug}; ## "no nameservers" ok in this context return $self->SUPER::nameservers(@_); } =head2 search, query, send, bgsend, bgbusy, bgread See L. =cut sub send { my ( $self, @argument ) = @_; $self->_finalise_config; $self->_reset_errorstring; my ($packet) = @argument; my $query = $self->_make_query_packet(@argument); my $result; if ( UB_SEND && ref($packet) ) { $result = $self->{ub_ctx}->ub_send( $query->encode ); } else { my ($q) = $query->question; $result = $self->{ub_ctx}->ub_resolve( $q->name, $q->{qtype}, $q->{qclass} ); } my $reply = $self->_decode_result($result); $query->header->id( $reply->header->id ); return $reply; } sub bgsend { my ( $self, @argument ) = @_; $self->_finalise_config; $self->_reset_errorstring; my $query = $self->_make_query_packet(@argument); my $ident = $query->header->id; my ($q) = $query->question; return $self->{ub_ctx}->ub_resolve_async( $q->name, $q->{qtype}, $q->{qclass}, $ident ); } sub bgbusy { my ( $self, $handle ) = @_; return unless $handle; return unless $handle->waiting; $self->{ub_ctx}->ub_process; eval { select( undef, undef, undef, 0.200 ) }; # avoid tight loop on bgbusy() return $handle->waiting; } sub bgread { my ( $self, $handle ) = @_; return unless $handle; $self->{ub_ctx}->ub_wait if &bgbusy; $self->errorstring( $handle->err ); my $reply = $self->_decode_result( $handle->result ) || return; $reply->header->id( $handle->query_id ); return $reply; } =head2 option $filename = $resolver->option( 'logfile' ); $resolver->option( 'logfile', $filename ); Get or set Unbound resolver (name,value) context options. =cut sub option { my ( $self, $name, @value ) = @_; return $self->{ub_ctx}->set_option( "$name:", @value ) if @value; my $value = $self->{ub_ctx}->get_option($name); return wantarray ? split /\r*\n/, $value : $value; } =head2 config $resolver->config( 'Unbound.cfg' ); This is a power-users interface that lets you specify all sorts of Unbound configuration options. =cut sub config { my ( $self, $filename ) = @_; return $self->{ub_ctx}->config($filename); } =head2 set_fwd $resolver->set_fwd( 'IP address' ); Set IPv4 or IPv6 address to which DNS queries are to be directed. The destination machine is expected to run a recursive resolver. If the proxy is not DNSSEC-capable, validation may fail. Can be called several times, in that case the addresses are used as backup servers. =cut sub set_fwd { my ( $self, $fwd ) = @_; return $self->{ub_ctx}->set_fwd($fwd); } =head2 set_tls $resolver->set_tls( 0 ); $resolver->set_tls( 1 ); Use DNS over TLS for queries to nameservers specified using set_fwd(). =cut sub set_tls { my ( $self, $do_tls ) = @_; return $self->{ub_ctx}->set_tls($do_tls); } =head2 set_stub $resolver->set_stub( 'zone', '10.1.2.3', 0 ); Add a stub zone, with given address to send to. This is for custom root hints or pointing to a local authoritative DNS server. For DNS resolvers and the 'DHCP DNS' IP address, use set_fwd(). =cut sub set_stub { my ( $self, $zone, $address, $prime ) = @_; return $self->{ub_ctx}->set_stub( $zone, $address, $prime ); } =head2 resolv_conf $resolver->resolv_conf( 'filename' ); Extract nameserver list from resolv.conf(5) format configuration file. Any domain, searchlist, ndots or other settings are ignored. Note that Net::DNS builds its own nameserver list using /etc/resolv.conf or other platform-specific sources. =cut sub resolv_conf { my ( $self, $filename ) = @_; return $self->{ub_ctx}->resolv_conf($filename); } =head2 hosts $resolver->hosts( 'filename' ); Read list of hosts from the filename given, usually "/etc/hosts". These addresses are not flagged as DNSSEC secure when queried. =cut sub hosts { my ( $self, $filename ) = @_; return $self->{ub_ctx}->hosts($filename); } =head2 add_ta $resolver->add_ta( 'trust anchor' ); Add a trust anchor which is a string that holds a valid DNSKEY or DS RR in RFC1035 zonefile format. =cut sub add_ta { my ( $self, @argument ) = @_; return $self->{ub_ctx}->add_ta( Net::DNS::RR->new(@argument)->plain ); } =head2 add_ta_file $resolver->add_ta_file( 'filename' ); Pass the name of a file containing DS and DNSKEY records (as from dig or drill). =cut sub add_ta_file { my ( $self, $filename ) = @_; return $self->{ub_ctx}->add_ta_file($filename); } =head2 add_ta_autr $resolver->add_ta_autr( 'filename' ); Add trust anchor to the given context that is tracked with RFC5011 automated trust anchor maintenance. The file is written when the trust anchor is changed. =cut sub add_ta_autr { my ( $self, $filename ) = @_; return $self->{ub_ctx}->add_ta_autr($filename); } =head2 trusted_keys $resolver->trusted_keys( 'filename' ); Pass the name of a BIND-style config file containing trusted-keys{}. =cut sub trusted_keys { my ( $self, $filename ) = @_; return $self->{ub_ctx}->trusted_keys($filename); } =head2 debug_out $resolver->debug_out( out ); Send debug output (and error output) to the specified stream. Pass a null argument to disable. Default is stderr. =cut sub debug_out { my ( $self, $out ) = @_; return $self->{ub_ctx}->debug_out($out); } =head2 debug_level $resolver->debug_level(0); Set verbosity of the debug output directed to stderr. Level 0 is off, 1 minimal, 2 detailed, 3 lots, and 4 lots more. =cut sub debug_level { my ( $self, $verbosity ) = @_; $self->debug($verbosity); return $self->{ub_ctx}->debug_level($verbosity); } =head2 async_thread $resolver->async_thread(1); Set the context behaviour for asynchronous actions. Enable a call to resolve_async() to create a thread to handle work in the background. If false (by default), a process is forked to perform the work. =cut sub async_thread { my ( $self, $dothread ) = @_; return $self->{ub_ctx}->async($dothread); } =head2 print, string $resolver->print; print $resolver->string; Prints the resolver state on the standard output. =cut sub string { my $self = shift; $self = $self->_defaults unless ref($self); my @nslist = $self->nameservers(); my ($force) = ( grep( { $self->{$_} } qw(force_v6 force_v4) ), 'force_v4' ); my ($prefer) = ( grep( { $self->{$_} } qw(prefer_v6 prefer_v4) ), 'prefer_v4' ); return <{searchlist}} ;; defnames = $self->{defnames} dnsrch = $self->{dnsrch} ;; ${prefer} = $self->{$prefer} ${force} = $self->{$force} ;; debug = $self->{debug} ndots = $self->{ndots} END } ######################################## sub _decode_result { my ( $self, $result ) = @_; return unless $result; $self->errorstring('INSECURE') unless $result->secure; $self->errorstring( $result->why_bogus ) if $result->bogus; my $buffer = $result->answer_packet || return; my $packet = Net::DNS::Packet->decode( \$buffer ); $self->errorstring($@); $packet->print if $self->debug; return $packet; } sub _finalise_config { my $self = shift; return if $self->{ub_frozen}++; my %IP_conf = ( force_v4 => ['do-ip6' => 'no'], force_v6 => ['do-ip4' => 'no'], prefer_v4 => ['prefer-ip4' => 'yes'], prefer_v6 => ['prefer-ip6' => 'yes'] ); for ( grep { $self->{$_} } qw(prefer_v4 prefer_v6 force_v4 force_v6) ) { my $argref = $IP_conf{$_}; eval { $self->option(@$argref) }; # unimplemented in old versions } my $count = 3; foreach ( grep { $count-- > 0 } $self->nameservers ) { $self->set_fwd($_); } return; } 1; __END__ =head1 COPYRIGHT Copyright (c)2022,2023 Dick Franks All Rights Reserved =head1 LICENSE Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the original copyright notices appear in all copies and that both copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =head1 SEE ALSO L, L, L, L =cut Net-DNS-Resolver-Unbound-1.21/META.yml0000644000175000017500000000126614440656753015466 0ustar rwfrwf--- abstract: 'Net::DNS resolver based on libunbound' author: - 'Dick Franks' build_requires: ExtUtils::MakeMaker: '0' File::Find: '1.13' File::Spec: '3.29' IO::File: '1.14' Test::More: '0.8' configure_requires: ExtUtils::MakeMaker: '6.48' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010' license: mit meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Net-DNS-Resolver-Unbound no_index: directory: - t - inc requires: Carp: '1.1' DynaLoader: '1.09' Net::DNS: '1.19' perl: '5.008009' version: '1.21' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Net-DNS-Resolver-Unbound-1.21/typemap0000644000175000017500000000033714217346602015604 0ustar rwfrwf# # TYPEMAP Net::DNS::Resolver::Unbound::Context T_PTROBJ Net::DNS::Resolver::Unbound::Handle T_PTROBJ Net::DNS::Resolver::Unbound::Result T_PTROBJ struct av* T_PTRREF struct ub_ctx* T_PTRREF struct ub_result* T_PTRREF # Net-DNS-Resolver-Unbound-1.21/Changes0000644000175000017500000000347614440656446015514 0ustar rwfrwfRevision history for Perl extension Net::DNS::Resolver::Unbound. **** 1.21 Jun 9, 2023 Emulate Net::DNS::Resolver send($packet). **** 1.20 Nov 1, 2022 Include -I flags from Config{cppflags}. Make feature detection work for XS package. **** 1.19 Oct 3, 2022 Improve test coverage. Make Makefile.PL also work properly on MSWin32. **** 1.18 Aug 31, 2022 Rework Makefile.PL. **** 1.17 Aug 11, 2022 Abort Makefile.PL if library header not found. **** 1.16 Jul 18, 2022 Strip line terminator from configuration variables. **** 1.15 Jul 11, 2022 pkg-config --keep-system-libs flag non-portable. **** 1.14 Jul 10, 2022 Emulate Net::DNS resolver->send(packet) behaviour. **** 1.13 Jun 11, 2022 Add test for undefined ub_result->answer_packet. **** 1.12 Apr 16, 2022 Documentation nit-picking. **** 1.11 Mar 28, 2022 Ignore unimplemented prefer-ip* options in old Unbound. **** 1.10 Mar 24, 2022 Apply Net::DNS IPv4/IPv6 preference to Unbound context. Report adverse DNSSEC status via resolver->errorstring(). **** 1.09 Mar 17, 2022 Rework t/35-bgread.t **** 1.08 Feb 21, 2022 Avoid ub_result leak when async handle is abandoned unread. **** 1.07 Feb 16, 2022 Avoid potential ub_result double-free vulnerability. Circumvent failures emanating from ancient Unbound versions. **** 1.06 Feb 10, 2022 Refactor to improve test coverage and code robustness. **** 1.05 Jan 28, 2022 Add further Unbound configuration methods. **** 1.04 Jan 26, 2022 Integrate fully into Net::DNS as an alternative resolver. **** 1.03 Jan 22, 2022 Fix incorrect library reference. **** 1.02 Jan 20, 2022 Re-engineer storage management strategy. Avoid option syntax error when using 1.6.6 or earlier. **** 1.01 Jan 11, 2022 --------------------------------------------------------------------------- Net-DNS-Resolver-Unbound-1.21/t/0000755000175000017500000000000014440656753014453 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.21/t/00-pod.t0000644000175000017500000000067614217346602015637 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Test::More; my %prerequisite = ( 'Test::Pod' => 1.45 ); foreach my $package ( sort keys %prerequisite ) { my @revision = grep {$_} $prerequisite{$package}; next if eval "use $package @revision; 1;"; ## no critic plan skip_all => "missing prerequisite $package @revision"; exit; } my @poddirs = qw(blib); my @allpods = all_pod_files(@poddirs); all_pod_files_ok(@allpods); exit; __END__ Net-DNS-Resolver-Unbound-1.21/t/25-decode.t0000644000175000017500000000225614440656113016302 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use IO::File; use Test::More; use Net::DNS::Resolver::Unbound; my $resolver = Net::DNS::Resolver::Unbound->new(); plan skip_all => 'no local nameserver' unless $resolver->nameservers; plan tests => 4; my $qname = 'www.net-dns.org'; my $ub_ctx = $resolver->{ub_ctx}; my $secure = $ub_ctx->mock_resolve( $qname, 1, 0 ); $resolver->_reset_errorstring; $resolver->_decode_result($secure); is( $resolver->errorstring(), '', 'secure flag set' ); my $insecure = $ub_ctx->mock_resolve( $qname, 0, 0 ); $resolver->_reset_errorstring; $resolver->_decode_result($insecure); is( $resolver->errorstring(), 'INSECURE', 'secure flag not set' ); my $bogus = $ub_ctx->mock_resolve( $qname, 0, 1 ); $resolver->_reset_errorstring; $resolver->_decode_result($bogus); ok( $resolver->errorstring(), 'bogus flag set' ); is( $resolver->_decode_result(undef), undef, 'undefined result' ); my $file = "25-decode.tmp"; # discard debug output my $handle = IO::File->new( $file, '>' ) || die "Could not open $file for writing"; $resolver->debug(1); select( ( select($handle), $resolver->_decode_result($secure) )[0] ); close($handle); unlink($file); exit; Net-DNS-Resolver-Unbound-1.21/t/00-install.t0000644000175000017500000000215114217346602016511 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use ExtUtils::MakeMaker; use File::Find; use File::Spec; use IO::File; use Test::More; my %manifest; my $handle = IO::File->new( 'MANIFEST', '<' ) or BAIL_OUT("MANIFEST: $!"); while (<$handle>) { my ($filename) = split; $manifest{$filename}++; } close $handle; plan skip_all => 'No versions from git checkouts' if -e '.git'; plan skip_all => 'Not sure how to parse versions.' unless eval { MM->can('parse_version') }; plan tests => scalar keys %manifest; foreach ( sort keys %manifest ) { # reconcile files with MANIFEST next unless ok( -f $_, "file exists\t$_" ); next unless /\.pm$/; next unless /^lib/; my $module = File::Spec->catfile( 'blib', $_ ); # library component diag("Missing module: $module") unless -f $module; my $version = MM->parse_version($_); # module version diag("\$VERSION = $version\t$_") unless $version =~ /^\d/; } my @files; # flag MANIFEST omissions find( sub { push( @files, $File::Find::name ) if /\.pm$/ }, 'lib' ); foreach ( sort @files ) { diag("Filename not in MANIFEST: $_") unless $manifest{$_}; } exit; __END__ Net-DNS-Resolver-Unbound-1.21/t/00-load.t0000644000175000017500000000434714323033304015761 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use IO::File; use Test::More tests => 2; my @module = qw( Net::DNS Net::DNS::Resolver::Unbound Net::DNS::Resolver::libunbound ); my %metadata; my $handle = IO::File->new('MYMETA.json') || IO::File->new('META.json'); if ($handle) { my $json = join '', (<$handle>); for ($json) { s/\s:\s/ => /g; # Perl? en voilĂ ! my $hashref = eval $_; %metadata = %$hashref; } close $handle; } my %prerequisite; foreach ( values %{$metadata{prereqs}} ) { # build, runtime, etc. foreach ( values %$_ ) { # requires $prerequisite{$_}++ for keys %$_; } delete @prerequisite{@module}; delete $prerequisite{perl}; } my @diag; foreach my $module ( @module, sort keys %prerequisite ) { eval "require $module"; ## no critic for ( eval { $module->VERSION || () } ) { s/^(\d+\.\d)$/${1}0/; push @diag, sprintf "%-30s %s", $module, $_; } } diag join "\n\t", "\nThese tests were run using:", @diag; unless ( ok( eval { Net::DNS::Resolver::libunbound->VERSION }, 'XS component Unbound.xs loaded' ) ) { diag( "\n", <<'RIP', "\n" ); Unresolved library references can be identified by running ldd: [Example] $ ldd blib/arch/auto/Net/DNS/Resolver/Unbound/Unbound.so linux-vdso.so.1 (0x00007ffc26ba4000) libunbound.so.8 => /lib64/libunbound.so.8 (0x00007f171ead5000) libperl.so.5.34 => /lib64/libperl.so.5.34 (0x00007f171e740000) libc.so.6 => /lib64/libc.so.6 (0x00007f171e536000) libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007f171e488000) libprotobuf-c.so.1 => /lib64/libprotobuf-c.so.1 (0x00007f171e47d000) libevent-2.1.so.7 => /lib64/libevent-2.1.so.7 (0x00007f171e424000) libpython3.10.so.1.0 => /lib64/libpython3.10.so.1.0 (0x00007f171e0dd000) libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007f171ddef000) libnghttp2.so.14 => /lib64/libnghttp2.so.14 (0x00007f171ddc7000) libm.so.6 => /lib64/libm.so.6 (0x00007f171dceb000) libcrypt.so.2 => /lib64/libcrypt.so.2 (0x00007f171dcb1000) /lib64/ld-linux-x86-64.so.2 (0x00007f171ec31000) libz.so.1 => /lib64/libz.so.1 (0x00007f171dc97000) RIP BAIL_OUT("Unable to access libunbound\n"); } use_ok('Net::DNS::Resolver::Unbound'); exit; END { eval { Net::DNS::Resolver::libunbound::croak_memory_wrap() } # paper over crack in Devel::Cover } __END__ Net-DNS-Resolver-Unbound-1.21/t/20-synchronous.t0000644000175000017500000000152414440647652017451 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Test::More; use Net::DNS::Resolver::Unbound; my $resolver = Net::DNS::Resolver::Unbound->new( defnames => 1, dnsrch => 1, debug_level => 0 ); plan skip_all => 'no local nameserver' unless $resolver->nameservers; plan tests => 5; my ( $name, $domain ) = qw(www net-dns.org); ok( $resolver->send("$name.$domain"), "resolver->send('$name.$domain')" ); $resolver->domain($domain); ok( $resolver->query($name), "resolver->query('$name')" ); $resolver->searchlist( "nxd.$domain", $domain ); ok( $resolver->search($name), "resolver->search('$name')" ); my $packet = $resolver->_make_query_packet("$name.$domain"); my $reply = $resolver->send($packet); ok( $reply, 'resolver->send( $packet )' ); is( $reply->header->id, $packet->header->id, 'reply header ID matches query' ); exit; Net-DNS-Resolver-Unbound-1.21/t/10-context.t0000644000175000017500000000321514440647566016545 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Test::More; use Net::DNS::Resolver::Unbound; plan tests => 9; ok( Net::DNS::Resolver::Unbound->string(), 'default configuration' ); my $resolver = Net::DNS::Resolver::Unbound->new(); ok( $resolver, 'create stub resolver instance' ); ok( $resolver->string(), '$resolver->string' ); my $recursive = Net::DNS::Resolver::Unbound->new( nameservers => [] ); ok( $recursive, 'create fully recursive resolver instance' ); is( scalar( $recursive->nameservers ), 0, 'empty nameserver list' ); my $option = 'verbosity'; my $value = '0'; my $return = $resolver->option( $option, $value ); is( $return, undef, "resolver->option( $option, $value )" ); my $result = $resolver->option($option); is( $result, $value, 'single-valued resolver option' ); my @result = $resolver->option($option); is( pop(@result), $value, 'multi-valued resolver option' ); $resolver->prefer_v6(1); $resolver->send('localhost'); ## side effect: finalise config eval { my $value = $resolver->config('filename') }; my ($reject_option) = split /\n/, "$@\n"; ok( $reject_option, "reject Unbound option\t[$reject_option]" ); ## exercise special config options (all rejected) eval { $resolver->add_ta('zone DS') }; eval { $resolver->add_ta_autr('filename') }; eval { $resolver->add_ta_file('filename') }; eval { $resolver->async_thread(1) }; eval { $resolver->debug_out('filename') }; eval { $resolver->hosts('filename') }; eval { $resolver->resolv_conf('filename') }; eval { $resolver->set_fwd('127.0.0.1') }; eval { $resolver->set_stub( 'zone', '10.1.2.3', 0 ) }; eval { $resolver->set_tls(0) }; eval { $resolver->trusted_keys('filename') }; exit; Net-DNS-Resolver-Unbound-1.21/t/35-bgread.t0000644000175000017500000000204314440650747016305 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Test::More; use Net::DNS::Resolver::Unbound; plan tests => 12; my $resolver = Net::DNS::Resolver::Unbound->new(); for ( my $handle = undef ) { ok( !$resolver->bgbusy($handle), 'not bgbusy' ); is( $resolver->bgread($handle), undef, 'undefined bgread' ); } my $id = 123; my $err = -99; for ( my $handle = Net::DNS::Resolver::libunbound::emulate_wait($id) ) { ok( $handle->waiting(), 'handle->waiting' ); ok( $resolver->bgbusy($handle), 'bgbusy' ); ok( !$handle->err(), 'no handle->err' ); ok( !$handle->result(), 'no handle->result' ); } for ( my $handle = Net::DNS::Resolver::libunbound::emulate_callback( $id, $err ) ) { ok( !$handle->waiting(), 'not handle->waiting' ); ok( !$resolver->bgbusy($handle), 'not bgbusy' ); ok( $handle->err(), 'handle->err' ); ok( !$handle->result(), 'no handle->result' ); is( $resolver->bgread($handle), undef, 'undefined bgread' ); my $errorstring = $resolver->errorstring; like( $errorstring, "/$err/", "errorstring: [$errorstring]" ); } exit; Net-DNS-Resolver-Unbound-1.21/t/30-asynchronous.t0000644000175000017500000000156414440650707017612 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Test::More; use Net::DNS::Resolver::Unbound; my $resolver = Net::DNS::Resolver::Unbound->new( debug_level => 0 ); plan skip_all => 'no local nameserver' unless $resolver->nameservers; plan tests => 7; my $fqdn = 'www.net-dns.org.'; for ( my $handle = $resolver->bgsend($fqdn) ) { ok( $handle, "resolver->bgsend('$fqdn')" ); my $reply = $resolver->bgread($handle); ok( $reply, 'resolver->bgread(handle)' ); ok( !$handle->err, 'handle->err empty' ); } my $packet = $resolver->_make_query_packet($fqdn); for ( my $handle = $resolver->bgsend($packet) ) { ok( $handle, "resolver->bgsend(packet)" ); my $reply = $resolver->bgread($handle); ok( $reply, 'resolver->bgread(handle)' ); ok( !$handle->err, 'handle->err empty' ); is( $reply->header->id, $packet->header->id, 'reply ID matches query packet' ); } exit; Net-DNS-Resolver-Unbound-1.21/LICENSE0000644000175000017500000000165214217346602015210 0ustar rwfrwf LICENSE ======= Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the original copyright notices appear in all copies and that both copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Net-DNS-Resolver-Unbound-1.21/MANIFEST0000644000175000017500000000062514440656753015344 0ustar rwfrwfChanges LICENSE MANIFEST This list of files Makefile.PL README typemap Unbound.xs lib/Net/DNS/Resolver/Unbound.pm t/00-install.t t/00-load.t t/00-pod.t t/10-context.t t/20-synchronous.t t/25-decode.t t/30-asynchronous.t t/35-bgread.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Net-DNS-Resolver-Unbound-1.21/README0000644000175000017500000000303414217346602015057 0ustar rwfrwfNet::DNS::Resolver::Unbound =========================== This module is designed as an extension of the Net::DNS package (https://metacpan.org/release/Net-DNS). The module enables Net::DNS to be used in conjunction with the Unbound resolver library developed by NLnetLabs. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires the following module and its dependencies: libunbound.so COPYRIGHT Copyright (c)2022 Dick Franks. All rights reserved. LICENCE Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the original copyright notices appear in all copies and that both copyright notice and this permission notice appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ Net-DNS-Resolver-Unbound-1.21/Makefile.PL0000644000175000017500000001111714431744322016151 0ustar rwfrwf# # Generate Makefile # use 5.008009; use strict; use warnings; use Config; use ExtUtils::MakeMaker; use constant MSWin32 => $^O eq 'MSWin32'; my $distro = 'Net::DNS::Resolver::Unbound'; my $module = join '/', 'lib', split /::/, "$distro.pm"; my $author = ['Dick Franks']; $author = join ', ', @$author if $ExtUtils::MakeMaker::VERSION < 6.58; # See perldoc ExtUtils::MakeMaker for details of how to influence # the contents of the Makefile that is written. my %metadata = ( NAME => $distro, VERSION_FROM => $module, ABSTRACT_FROM => $module, AUTHOR => $author, LICENSE => 'mit', MIN_PERL_VERSION => 5.008009, CONFIGURE_REQUIRES => {'ExtUtils::MakeMaker' => 6.48}, TEST_REQUIRES => { 'ExtUtils::MakeMaker' => 0, 'File::Find' => 1.13, 'File::Spec' => 3.29, 'IO::File' => 1.14, 'Test::More' => 0.80, } ); my %prerequisite = ( 'Carp' => 1.10, 'DynaLoader' => 1.09, 'Net::DNS' => 1.19, ); my @debris = qw(*.gcov *.gcda *.gcno *.lock); my $inc = ''; my $lib = '-lunbound'; my $nul = MSWin32 ? 'nul' : '/dev/null'; if (`pkg-config --modversion libunbound 2>$nul`) { $inc = `pkg-config --cflags libunbound 2>$nul`; $lib = `pkg-config --libs libunbound 2>$nul`; } elsif (MSWin32) { $lib = '-llibunbound' if $Config{cc} =~ /cl/; $lib = '-lunbound' if $Config{cc} =~ /gcc/; } if ( my $dir = $ENV{UNBOUND_PREFIX} ) { chomp $dir; $inc = "-I$dir/include"; $lib = "-L$dir/lib $lib"; } $inc = $ENV{UNBOUND_INCLUDE} if $ENV{UNBOUND_INCLUDE}; $lib = $ENV{UNBOUND_LIB} if $ENV{UNBOUND_LIB}; chomp $_ for ( $inc, $lib ); my @header = qw(unbound.h); # library headers if ( my $cpp = $Config{cppstdin} ) { my @flag = grep /^-I/, split /\s+(?=\-)/, $Config{cppflags}; my $last = $Config{cppminus}; my $echo = $Config{echo} || 'echo'; foreach my $header (@header) { my $scriptlet = qq[$echo "#include <$header>" | $cpp @flag $inc -o - $last]; $scriptlet = qq[$echo | $cpp @flag $inc -include $header $last] if MSWin32; next unless scalar( my @text = `$scriptlet 2>$nul` ); die "$header file not found" unless grep /$header/i, @text; } } WriteMakefile( %metadata, PREREQ_PM => {%prerequisite}, INC => $inc, LIBS => [$lib], clean => {FILES => "@debris"}, ); exit; package MY; ## customise generated Makefile sub constants { return join "\n", shift->SUPER::constants(), <<'END' if $^O =~ /MSWin/i; # include test directory TEST_DIR = t FULLPERLRUN = $(FULLPERL) "-I$(TEST_DIR)" END return join "\n", shift->SUPER::constants(), <<'END'; # suppress parallel test execution include test directory TEST_DIR = t FULLPERLRUN = HARNESS_OPTIONS=j1:c $(FULLPERL) "-I$(TEST_DIR)" END } sub install { my $self = shift; my %install_type = qw(perl INSTALLARCHLIB site INSTALLSITEARCH vendor INSTALLVENDORARCH); my $install_site = join '', '$(DESTDIR)$(', $install_type{$self->{INSTALLDIRS}}, ')'; for ($install_site) { s/\$\(([A-Z_]+)\)/$self->{$1}/eg while /\$\(/; # expand Makefile macros s|([/])[/]+|$1|g; # remove gratuitous //s } eval "require $distro"; ## no critic my @version = ( 'version', eval { $distro->VERSION } ); my $nameregex = join '\W+', '', split /::/, "$distro.pm\$"; my @installed = grep { $_ && m/$nameregex/io } values %INC; my %occluded; foreach (@installed) { my $path = m/^(.+)$nameregex/io ? $1 : ''; my %seen; foreach (@INC) { $seen{$_}++; # find $path in @INC last if $_ eq $path; } foreach ( grep { !$seen{$_} } @INC ) { $occluded{$_}++; # suppress install } } return $self->SUPER::install(@_) unless $occluded{$install_site}; my $message; warn $message = <<"AMEN"; ## ## The install location for this version of $distro ## differs from the existing @version in your perl library at ## @installed ## ## The installation would be rendered ineffective because the ## existing @version occurs in the library search path before ## $install_site ## ## The generated Makefile supports build and test only. ## AMEN my $echo = ' $(NOECHO) $(ECHO) "##"'; $message =~ s/##/$echo/eg; return join '', <<"END"; install : $message \$(NOECHO) \$(FALSE) END } sub postamble { my $ldflags = "-fprofile-arcs -ftest-coverage"; my $ccflags = "-O0 $ldflags"; my $devnull = $^O eq 'MSWin32' ? 'nul' : '/dev/null'; return <<"PlanA" if `gcov -v 2>$devnull`; test_cover : cover -delete HARNESS_PERL_SWITCHES=-MDevel::Cover \$(MAKE) -W Unbound.xs test CCFLAGS="$ccflags" OTHERLDFLAGS="$ldflags" cover \$(NOECHO) \$(TOUCH) Unbound.c # force XS rebuild before install PlanA return <<'PlanB'; test_cover : cover -delete HARNESS_PERL_SWITCHES=-MDevel::Cover $(MAKE) test cover PlanB } __END__ Net-DNS-Resolver-Unbound-1.21/META.json0000644000175000017500000000236614440656753015640 0ustar rwfrwf{ "abstract" : "Net::DNS resolver based on libunbound", "author" : [ "Dick Franks" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010", "license" : [ "mit" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Net-DNS-Resolver-Unbound", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.48" } }, "runtime" : { "requires" : { "Carp" : "1.1", "DynaLoader" : "1.09", "Net::DNS" : "1.19", "perl" : "5.008009" } }, "test" : { "requires" : { "ExtUtils::MakeMaker" : "0", "File::Find" : "1.13", "File::Spec" : "3.29", "IO::File" : "1.14", "Test::More" : "0.8" } } }, "release_status" : "stable", "version" : "1.21", "x_serialization_backend" : "JSON::PP version 2.27200" }