Net-DNS-Resolver-Unbound-1.28/0000755000175000017500000000000014653430422014204 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.28/Unbound.xs0000644000175000017500000001650014647720643016206 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 #ifdef UNBOUND_VERSION_MAJOR #define UB_VERSION (UNBOUND_VERSION_MAJOR*100 + UNBOUND_VERSION_MINOR)*100 + UNBOUND_VERSION_MICRO #else #define UB_VERSION 10400 #define ub_version() "1.4.0 ?" #endif #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)) ); 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) ); #if !(UB_VERSION < 10900) void set_tls(struct ub_ctx* ctx, int tls) CODE: checkerr( ub_ctx_set_tls(ctx, tls) ); #endif #if !(UB_VERSION < 10508) 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) ); #endif void resolvconf(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) ); #if !(UB_VERSION < 10500) void add_ta_autr(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_add_ta_autr(ctx, fname) ); #endif void trustedkeys(struct ub_ctx* ctx, const char* fname) CODE: checkerr( ub_ctx_trustedkeys(ctx, fname) ); void debugout(struct ub_ctx* ctx, const char* out) CODE: checkerr( ub_ctx_debugout(ctx, (void*) out) ); void debuglevel(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) ); ######################## ## 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 void checkerr(int ret) #ifdef croak_memory_wrap void croak_memory_wrap() #endif ######################## Net-DNS-Resolver-Unbound-1.28/lib/0000755000175000017500000000000014653430422014752 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.28/lib/Net/0000755000175000017500000000000014653430422015500 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.28/lib/Net/DNS/0000755000175000017500000000000014653430422016124 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.28/lib/Net/DNS/Resolver/0000755000175000017500000000000014653430422017725 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.28/lib/Net/DNS/Resolver/Unbound.pm0000644000175000017500000003757014653427615021723 0ustar rwfrwfpackage Net::DNS::Resolver::Unbound; use strict; use warnings; use integer; use Net::DNS; use constant OS_SPEC => defined eval "require Net::DNS::Resolver::$^O"; ## no critic use constant OS_CONF => join '::', 'Net::DNS::Resolver', OS_SPEC ? $^O : 'UNIX'; use base qw(Net::DNS::Resolver::Base DynaLoader), OS_CONF; our $VERSION; BEGIN { $VERSION = '1.28'; eval { __PACKAGE__->bootstrap($VERSION) }; } use constant UB_VERSION => scalar eval { my $version = Net::DNS::Resolver::libunbound->VERSION(); my ( $major, $minor, $minimus ) = split /\D/, $version; ( $major * 100 + $minor ) * 100 + $minimus; }; use constant UB_CONTEXT => 'Net::DNS::Resolver::Unbound::Context'; use constant IRRELEVENT => qw(igntc nameserver4 nameserver6 nameservers persistent_tcp persistent_udp port retrans retry srcaddr4 srcaddr6 srcport tcp_timeout udp_timeout usevc); use constant IP_PREF => UB_VERSION > 11100; use constant ADD_TA_AUTR => UB_CONTEXT->can('add_ta_autr'); use constant SET_STUB => UB_CONTEXT->can('set_stub'); use constant SET_TLS => UB_CONTEXT->can('set_tls'); =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 almost 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. =item * Result packet is synthesised in libunbound and not the "real thing". In particular, the queryID returned by Unbound is always zero. =back =head1 METHODS =head2 new my $resolver = Net::DNS::Resolver::Unbound->new( debug_level => 2, defnames => 1, dnsrch, => 1, domain => 'domain', ndots => 1, option => [ 'tls-cert-bundle', '/etc/ssl/cert.pem' ], nameservers => [ ... ], searchlist => ['domain' ... ], ); Returns a new Net::DNS::Resolver::Unbound resolver object. =cut sub new { my ( $class, @args ) = @_; my $self = $class->SUPER::new(); $self->nameservers( $self->SUPER::nameservers ); delete $self->{$_} for IRRELEVENT; $self->_finalise_config; # default configuration $self->{update} = {} if @args; # force context rebuild while ( my $attr = shift @args ) { my $value = shift @args; $self->$attr( ref($value) ? @$value : $value ); } return $self; } =head2 nameservers my $stub_resolver = Net::DNS::Resolver::Unbound->new( nameserver => '127.0.0.53' ); my $fully_recursive = Net::DNS::Resolver::Unbound->new( nameservers => [], # override /etc/resolv.conf add_ta_file => '/var/lib/unbound/root.key' ); my $DoT_resolver = Net::DNS::Resolver->new( nameserver => '2606:4700:4700::1111@853#cloudflare-dns.com', nameserver => '2001:4860:4860::8888@853#dns.google', nameserver => '8.8.8.8@853#dns.google', nameserver => '9.9.9.9@853#dns.quad9.net', option => [qw(tls-cert-bundle /etc/ssl/cert.pem)], set_tls => 1 ); $resolver->nameservers( '::1', '127.0.0.1', ... ); @nameservers = $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, @nameservers ) = @_; if ( defined wantarray ) { my $config = $self->{config}; my $update = $self->{update}; my @setfwd = ( $update->{set_fwd}, $config->{set_fwd}, [] ); my ($setfwd) = grep { defined $_ } @setfwd; my @value = map { ref($_) ? @$_ : $_ } $setfwd; return @value; } $self->set_fwd() unless @nameservers; $self->set_fwd($_) foreach @nameservers; return; } sub nameserver { &nameservers; } =head2 search, query, send, bgsend, bgbusy, bgread See L. =cut use constant UB_SEND => UB_CONTEXT->can('ub_send'); sub send { my ( $self, @argument ) = @_; my ($packet) = @argument; if ( ref $packet ) { # resolve packets asynchronously my $handle = $self->bgsend(@argument); return $self->bgread($handle); } $self->_finalise_config; $self->_reset_errorstring; my $query = $self->_make_query_packet(@argument); my ($q) = $query->question; my $result = $self->{ub_ctx}->ub_resolve( $q->name, $q->{qtype}, $q->{qclass} ); return $self->_decode_result($result); } sub bgsend { my ( $self, @argument ) = @_; $self->_finalise_config; $self->_reset_errorstring; my $query = $self->_make_query_packet(@argument); my $image = $query->encode; 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; $self->errorstring( $handle->err ); my $reply = $self->_decode_result( $handle->result ) || return; $reply->header->id( $handle->query_id ); # lying toad!; return $reply; } =head2 option $resolver->option( 'tls-cert-bundle', '/etc/ssl/cert.pem' ); Set Unbound resolver (name,value) context option. =cut sub option { my ( $self, $name, @value ) = @_; return $self->_option( $name, @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->_config( '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->_config( '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, $tls ) = @_; return SET_TLS ? $self->_config( 'set_tls', $tls ) : undef; } =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 SET_STUB ? $self->_config( 'set_stub', $zone, $address, $prime ) : undef; } =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->_config( 'resolvconf', $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->_config( '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 ) = @_; my $ta = Net::DNS::RR->new(@argument)->plain; return $self->_config( 'add_ta', $ta ); } =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->_config( '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 ADD_TA_AUTR ? $self->_config( 'add_ta_autr', $filename ) : undef; } =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->_config( 'trustedkeys', $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, $stream ) = @_; return $self->_config( 'debugout', $stream ); } =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->_config( 'debuglevel', $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, $threaded ) = @_; return $self->_config( 'async', $threaded ); } =head2 print, string $resolver->print; print $resolver->string; Prints the resolver state on the standard output. =cut sub string { my $self = shift; $self = $self->new() unless ref($self); my ($force) = ( grep( { $self->{$_} } qw(force_v6 force_v4) ), 'force_v4' ); my ($prefer) = ( grep( { $self->{$_} } qw(prefer_v6 prefer_v4) ), 'prefer_v4' ); my $image = <{searchlist}} ;; defnames $self->{defnames} dnsrch $self->{dnsrch} ;; ${prefer} $self->{$prefer} ndots $self->{ndots} ;; ${force} $self->{$force} debug $self->{debug} END $self->{update} ||= {}; # force config rebuild $self->_finalise_config; my %config = %{$self->{config}}; my $optref = $config{set_option} || []; my @option = @$optref; # pre-sorted option list my @expand; while ( my $name = shift @option ) { # expand option list foreach my $value ( map { ref($_) ? @$_ : $_ } shift @option ) { push @expand, [$name, $value]; } } my $format = ";; %s\t%s\n"; local $config{set_option} = \@expand; foreach my $name ( sort keys %config ) { my $value = $config{$name}; if ( ref $value ) { foreach my $arg (@$value) { my @arg = map { ref($_) ? @$_ : $_ } $arg; $image .= sprintf( $format, $name, join ' ', @arg ); } } else { $image .= sprintf( $format, $name, $value ); } } return $image; } ######################################## 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 _config { my ( $self, $name, @arg ) = @_; my $entry = ( scalar(@arg) == 1 ) ? $arg[0] : [@arg]; my $ctx = $self->{test_ctx}; $self->{test_ctx} = $ctx = Net::DNS::Resolver::Unbound::Context->new() unless $ctx; $ctx->$name(@arg) if @arg; # error check only my $state = $self->{update}->{$name}; if ( defined $state ) { # second and subsequent entries $state = $self->{update}->{$name} = [$state] unless ref $state; push @$state, $entry; } else { # initial entry $self->{update}->{$name} = ( scalar(@arg) > 1 ) ? [$entry] : $entry; } return; } sub _option { my ( $self, $name, @arg ) = @_; my ($entry) = @arg; my $opt = "${name}:"; my $ctx = $self->{test_ctx}; $self->{test_ctx} = $ctx = Net::DNS::Resolver::Unbound::Context->new() unless $ctx; $ctx->set_option( $opt, @arg ) if defined $entry; # error check only my $updopt = $self->{update}->{set_option}; my %option = map {$_} @$updopt; unless (@arg) { my $setopt = $self->{config}->{set_option}; my %config = map {$_} @$setopt, @$updopt; my $value = $config{$opt}; return ref($value) ? @$value : $value; } my $state = $option{$opt}; if ( defined $state ) { # second and subsequent entries $option{$opt} = $state = [$state] unless ref $state; push @$state, $entry; } else { # initial entry $option{$opt} = $entry; } $option{$opt} = [] unless defined $entry; # delete entire option my @option = map { ( $_, $option{$_} ) } keys %option; $self->{update}->{set_option} = \@option; return; } my %IP_conf = ( force_v4 => ['do-ip6:' => 'no'], force_v6 => ['do-ip4:' => 'no'], prefer_v4 => ['prefer-ip4:' => 'yes'], prefer_v6 => ['prefer-ip6:' => 'yes'] ); my @IPpref = map {@$_} values %IP_conf; delete @IP_conf{qw(prefer_v4 prefer_v6)} unless IP_PREF; my @IPconf = sort keys %IP_conf; sub _finalise_config { my $self = shift; my $update = delete $self->{update}; return unless $update; delete $self->{test_ctx}; delete $self->{ub_ctx}; my $config = $self->{config}; my $cfgopt = delete $config->{set_option}; # extract option lists my $updopt = delete $update->{set_option}; my %config = ( %$config, %$update ); # merge config updates my %option = map {$_} @$cfgopt, @$updopt; # merge option updates delete @option{@IPpref}; # expunge IP preference foreach my $key ( grep { $self->$_ } @IPconf ) { # insert IP preference my ( $key, $value ) = @{$IP_conf{$key}}; $option{$key} = $value; last; } my @option = map { ( $_, $option{$_} ) } sort keys %option; # rebuild option list my $ctx = $self->{ub_ctx} = Net::DNS::Resolver::Unbound::Context->new(); foreach my $name ( keys %option ) { # set unbound options foreach my $value ( map { ref($_) ? @$_ : $_ } $option{$name} ) { $ctx->set_option( $name, $value ); } } foreach my $name ( keys %config ) { # rebuild unbound context foreach my $value ( map { ref($_) ? @$_ : $_ } $config{$name} ) { my @arg = map { ref($_) ? @$_ : $_ } $value; $ctx->$name(@arg); } } $config{set_option} = \@option if @option; $self->{config} = \%config; return; } 1; __END__ =head1 COPYRIGHT Copyright (c)2022,2024 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.28/META.yml0000644000175000017500000000143314653430422015456 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: Config: '0' 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' base: '2.13' constant: '1.17' integer: '1' perl: '5.008009' strict: '1.03' warnings: '1.0501' version: '1.28' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Net-DNS-Resolver-Unbound-1.28/typemap0000644000175000017500000000033714217346602015613 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.28/Changes0000644000175000017500000000476514653430346015520 0ustar rwfrwfRevision history for Perl extension Net::DNS::Resolver::Unbound. **** 1.28 Aug 3, 2024 Unbound 1.9.0 ub_ctx_create() can fail with SEGV. Test fixed to avoid failure, but UB bug remains. **** 1.27 Jul 23, 2024 Work around features absent in early libunbound. **** 1.26 Jul 20, 2024 Rewrite code to allow option deletion. Simplify context option internal representation. **** 1.25 Jul 14, 2024 Improve robustness of Unbound context management. Fix SEGV and core dump in make disttest. **** 1.24 Jul 9, 2024 Avoid test failure when using 1.9.0 or earlier. **** 1.23 Jul 6, 2024 Implement support for DNS over TLS. Remove restriction on Unbound context updates. **** 1.22 Jun 11, 2024 Restructure resolver method inheritance tree. **** 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.28/t/0000755000175000017500000000000014653430422014447 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.28/t/00-pod.t0000644000175000017500000000067614217346602015646 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.28/t/25-decode.t0000644000175000017500000000213514642337621016311 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use IO::File; use Test::More tests => 4; use Net::DNS::Resolver::Unbound; my $resolver = Net::DNS::Resolver::Unbound->new(); 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.28/t/00-install.t0000644000175000017500000000215114217346602016520 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.28/t/00-load.t0000644000175000017500000000443614643721373016006 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::checkerr(1) }; eval { Net::DNS::Resolver::libunbound::croak_memory_wrap() } # paper over crack in Devel::Cover } __END__ Net-DNS-Resolver-Unbound-1.28/t/20-synchronous.t0000644000175000017500000000140314642337137017452 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->nameserver; plan tests => 4; 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 )' ); exit; Net-DNS-Resolver-Unbound-1.28/t/10-context.t0000644000175000017500000000417514653370105016546 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use IO::File; use Test::More tests => 10; use Net::DNS::Resolver::Unbound; ok( Net::DNS::Resolver::Unbound->string(), 'default configuration' ); my $recursive = Net::DNS::Resolver::Unbound->new( nameservers => [] ); ok( $recursive, 'create fully recursive resolver instance' ); is( scalar( $recursive->nameservers ), 0, 'empty nameserver list' ); my $resolver = Net::DNS::Resolver::Unbound->new( debug_level => 0, prefer_v4 => 1 ); ok( $resolver, 'create stub resolver instance' ); $resolver->nameservers(qw(::1 127.0.0.1 127.0.0.53)); is( scalar( $resolver->nameservers ), 3, 'replace nameserver list' ); $resolver->set_stub( 'zone', '10.1.2.3', 0 ); my $option = 'outgoing-port-avoid'; my $value = '3200-3201'; my $return = $resolver->option( $option, $value ); is( $return, undef, "resolver->option( $option, $value )" ); my $single = $resolver->option($option); is( $single, $value, 'single-valued resolver option' ); $resolver->option( $option, '3202-3203' ); $resolver->option( $option, '3204-3205' ); my @multi = $resolver->option($option); is( scalar(@multi), 3, 'multi-valued resolver option' ); my $bogus = $resolver->option('bogus'); is( $bogus, undef, 'nonexistent resolver option' ); ok( $resolver->string(), '$resolver->string' ); my $index = $$ % 10000; my @filename; sub filename { my $filename = join '', 'file', $index++; close( IO::File->new( $filename, '>' ) or die $! ); push @filename, $filename; return $filename; } END { unlink $_ foreach @filename; } ## exercise context methods, some of which may fail eval { $resolver->option( 'outgoing-port-avoid', undef ) }; eval { $resolver->config(filename) }; eval { $resolver->set_tls(0) }; eval { $resolver->resolv_conf(filename) }; eval { $resolver->hosts(filename) }; eval { $resolver->add_ta('zone DS 12345 7 2 d93738479adb6546776932f60790e87bc79c20db85972b4b341347335a8e9f98') }; eval { $resolver->add_ta_file(filename) }; eval { $resolver->add_ta_autr(filename) }; eval { $resolver->trusted_keys(filename) }; eval { $resolver->debug_out(filename) }; eval { $resolver->debug_level(1) }; eval { $resolver->async_thread(0) }; exit; Net-DNS-Resolver-Unbound-1.28/t/35-bgread.t0000644000175000017500000000204314440650747016314 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.28/t/30-asynchronous.t0000644000175000017500000000156314642337724017625 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->nameserver; 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.28/LICENSE0000644000175000017500000000165214217346602015217 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.28/MANIFEST0000644000175000017500000000062514653430422015340 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.28/README0000644000175000017500000000303414217346602015066 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.28/Makefile.PL0000644000175000017500000001137614642613527016175 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 => { 'Config' => 0, '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, 'base' => 2.13, 'constant' => 1.17, 'integer' => 1.00, 'strict' => 1.03, 'warnings' => 1.0501, ); 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 @cppflags = grep /^-I/, split /\s+(?=\-)/, $Config{cppflags} || ''; $inc = join ' ', $inc, @cppflags; my @header = qw(unbound.h); # library headers if ( my $cpp = $Config{cppstdin} ) { my $last = $Config{cppminus}; my $echo = $Config{echo} || 'echo'; foreach my $header (@header) { my $scriptlet = qq[$echo "#include <$header>" | $cpp $inc -o - $last]; $scriptlet = qq[$echo | $cpp $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.28/META.json0000644000175000017500000000265714653430422015637 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" : { "Config" : "0", "ExtUtils::MakeMaker" : "6.48" } }, "runtime" : { "requires" : { "Carp" : "1.1", "DynaLoader" : "1.09", "Net::DNS" : "1.19", "base" : "2.13", "constant" : "1.17", "integer" : "1", "perl" : "5.008009", "strict" : "1.03", "warnings" : "1.0501" } }, "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.28", "x_serialization_backend" : "JSON::PP version 2.27200" }