Net-DNS-Resolver-Unbound-1.32/0000755000175000017500000000000014750646750014212 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.32/Unbound.xs0000644000175000017500000001642314745754073016210 0ustar rwfrwf =head1 NAME Unbound.xs - Perl bindings for NLnetLabs libunbound =head1 DESCRIPTION Perl XS extension providing bindings for 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-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. =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, const char* qname, int qtype, int qclass) CODE: checkerr( ub_resolve(ctx, qname, qtype, qclass, &RETVAL) ); OUTPUT: RETVAL Net::DNS::Resolver::Unbound::Handle ub_resolve_async(struct ub_ctx* ctx, const char* qname, int qtype, int qclass, int query_id) INIT: int async_id = 0; CODE: RETVAL = newAV(); checkerr( ub_resolve_async(ctx, qname, qtype, qclass, (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, const char* qname, int secure, int bogus) CODE: checkerr( ub_resolve(ctx, qname, 1, 1, &RETVAL) ); RETVAL->secure = secure; RETVAL->bogus = bogus; if (bogus) RETVAL->answer_packet = NULL; 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.32/lib/0000755000175000017500000000000014750646750014760 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.32/lib/Net/0000755000175000017500000000000014750646750015506 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.32/lib/Net/DNS/0000755000175000017500000000000014750646750016132 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.32/lib/Net/DNS/Resolver/0000755000175000017500000000000014750646750017733 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.32/lib/Net/DNS/Resolver/Unbound.pm0000644000175000017500000004305614750644010021676 0ustar rwfrwfpackage Net::DNS::Resolver::Unbound; use strict; use warnings; use integer; use Net::DNS; use base qw(Net::DNS::Resolver::Base DynaLoader); use constant OS_SPEC => "Net::DNS::Resolver::$^O"; use constant OS_UNIX => "Net::DNS::Resolver::UNIX"; use constant OS_CONF => grep eval "require $_", OS_SPEC, OS_UNIX; ## no critic use base (OS_CONF)[0]; ## backward compatibility only our $VERSION; BEGIN { $VERSION = '1.32'; 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 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 =head2 Replacing Net::DNS::Resolver Base Class Placing C<-register> in the L import list, will cause it to register itself with L as the resolver base class. use Net::DNS; use Net::DNS::Resolver::Unbound -register; my $resolver = Net::DNS::Resolver->new(...); my $response = $resolver->send(...); Note that "-register" is a global setting that applies to the entire program; it cannot be applied only for certain callers, removed, or limited by lexical scope. =cut sub import { my ( $class, @argument ) = @_; my $register = grep {/^-register$/i} @argument; @Net::DNS::Resolver::ISA = $class if $register; return; } =head1 METHODS =head2 new # Use the default configuration my $resolver = Net::DNS::Resolver::Unbound->new(); # Set options in the constructor my $resolver = Net::DNS::Resolver::Unbound->new( debug_level => 2, defnames => 1, dnsrch, => 1, domain => 'domain', nameservers => [ '2001:DB8::1', ... ], ndots => 1, searchlist => ['domain' ... ] ); Returns a new Net::DNS::Resolver::Unbound resolver object. If no arguments are supplied, C returns an object having the default configuration. On Unix and Linux systems, the default values are read from the following files, in the order indicated: =over F, F<$HOME/.resolv.conf>, F<./.resolv.conf> =back The following keywords are recognised in resolver configuration files: =over =item B IP address of a name server that the resolver should query. =item B The domain suffix to be appended to a short non-absolute name. =item B A space-separated list of domains in the desired search path. =back Except for F, files will only be read if owned by the effective userid running the program. Note that the domain and searchlist keywords are mutually exclusive. If both are present, the resulting behaviour is unspecified. If neither is present, the domain is determined from the local hostname. =cut sub new { my ( $class, @args ) = @_; my $self = __PACKAGE__->SUPER::new(); $self->nameservers( $self->SUPER::nameservers ); delete $self->{$_} for IRRELEVENT; $self->_finalise_config; # default configuration return $self unless @args; while ( my $attr = shift @args ) { my $value = shift @args; $self->$attr( ref($value) ? @$value : $value ); } $self->_finalise_config; # force context rebuild return $self; } =head2 nameservers my $dnssec_resolver = Net::DNS::Resolver::Unbound->new( nameservers => [], # override /etc/resolv.conf add_ta_file => '/var/lib/unbound/root.key' ); my $DoT_resolver = Net::DNS::Resolver::Unbound->new( nameserver => '2606:4700:4700::1111@853#cloudflare-dns.com', nameserver => '1.1.1.1@853#cloudflare-dns.com', nameserver => '2001:4860:4860::8888@853#dns.google', nameserver => '8.8.8.8@853#dns.google', option => ['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 F or similar platform-specific sources. =cut sub nameservers { my ( $self, @nameservers ) = @_; if ( defined wantarray ) { my $config = $self->{ub_cfg}; my $update = $self->{ub_upd}; 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 { return &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 F 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 F. 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( '/var/lib/unbound/root.key' ); 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. The 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. The default 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 @search = grep { defined($_) } @{$self->{searchlist}}; my @image = <{defnames} dnsrch $self->{dnsrch} ;; ${prefer} $self->{$prefer} ndots $self->{ndots} ;; ${force} $self->{$force} debug $self->{debug} END $self->_finalise_config; # force config rebuild my %config = %{$self->{ub_cfg}}; 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; push @image, sprintf( $format, $name, join ' ', @arg ); } } else { push @image, sprintf( $format, $name, $value ); } } return join '', @image, "\n"; } ######################################## 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->{ub_upd}->{$name}; if ( defined $state ) { # second and subsequent entries $state = $self->{ub_upd}->{$name} = [$state] unless ref $state; push @$state, $entry; } else { # initial entry $self->{ub_upd}->{$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->{ub_upd}->{set_option}; my %option = map {$_} @$updopt; unless (@arg) { my $setopt = $self->{ub_cfg}->{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->{ub_upd}->{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 @IPconf = map {@$_} values %IP_conf; my @IPoptn = sort keys %IP_conf; sub _finalise_config { my $self = shift; my @IPpref = grep { $self->{$_} } @IPoptn; # from Net::DNS config delete $self->{ub_upd}->{any} if @IPpref; # force context rebuild my $update = delete $self->{ub_upd}; return unless $update; delete $self->{test_ctx}; delete $self->{ub_ctx}; my $config = $self->{ub_cfg}; 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{@IPconf}; # expunge IP preference foreach (@IPpref) { # insert IP preference my ( $key, $value ) = @{$IP_conf{$_}}; $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} ) { eval { $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->{ub_cfg} = \%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.32/META.yml0000644000175000017500000000143314750646750015464 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.32' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Net-DNS-Resolver-Unbound-1.32/typemap0000644000175000017500000000033714217346602015606 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.32/Changes0000644000175000017500000000542014750646516015506 0ustar rwfrwfRevision history for Perl extension Net::DNS::Resolver::Unbound. **** 1.32 Feb 5, 2025 Fix base class selection for Net::DNS pre-1.46. **** 1.31 Jan 27, 2025 Force context rebuild for options in new(). **** 1.30 Jan 7, 2025 Reformat documentation. **** 1.29 Aug 16, 2024 Add import list -register option to replace resolver base. **** 1.28 Aug 3, 2024 Unbound 1.9.0 ub_ctx_create() can fail with SEGV. Tests fixed to avoid failure, but the risk 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.32/ex/0000755000175000017500000000000014750646750014626 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.32/ex/TLSexample.pl0000644000175000017500000000105214745461555017201 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Net::DNS 1.19; use Net::DNS::Resolver::Unbound 1.29 -register; my $resolver = Net::DNS::Resolver->new( debug_level => 2, prefer_v4 => 1, nameserver => '1.1.1.1@853#cloudflare-dns.com', nameserver => '8.8.8.8@853#dns.google', add_ta_file => '/var/lib/unbound/root.key', option => ['tls-cert-bundle' => '/etc/ssl/cert.pem'], set_tls => 1 ); $resolver->print; my @request = qw(example.net IN NS); my $reply = $resolver->send(@request); $reply->print unless $resolver->debug; exit; Net-DNS-Resolver-Unbound-1.32/t/0000755000175000017500000000000014750646750014455 5ustar rwfrwfNet-DNS-Resolver-Unbound-1.32/t/00-pod.t0000644000175000017500000000103614747237720015640 0ustar rwfrwf#!/usr/bin/perl # $Id: 00-pod.t 1856 2021-12-02 14:36:25Z willem $ -*-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 => "$package @revision not installed"; exit; } my @poddirs = qw( . ); my @allpods = grep !m#^[/.]*(blib/|[A-Z]+[-])#i, all_pod_files(@poddirs); all_pod_files_ok( sort @allpods ); exit; __END__ Net-DNS-Resolver-Unbound-1.32/t/25-decode.t0000644000175000017500000000224114747176324016311 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 => 'resolver not loaded' unless $resolver; 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.32/t/00-install.t0000644000175000017500000000215114217346602016513 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.32/t/00-load.t0000644000175000017500000000443614643721373016001 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.32/t/20-synchronous.t0000644000175000017500000000147414747176305017461 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 => 'resolver not loaded' unless $resolver; 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.32/t/10-context.t0000644000175000017500000000422414747176253016550 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use IO::File; use Test::More tests => 10; use Net::DNS; use Net::DNS::Resolver::Unbound -register; 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, force_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.32/t/35-bgread.t0000644000175000017500000000213714747176401016313 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Test::More; use Net::DNS::Resolver::Unbound; my $resolver = Net::DNS::Resolver::Unbound->new(); plan skip_all => 'resolver not loaded' unless $resolver; plan tests => 12; 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.32/t/30-asynchronous.t0000644000175000017500000000163214747176344017622 0ustar rwfrwf#!/usr/bin/perl # use strict; use warnings; use Test::More; use Net::DNS::Resolver::Unbound; my $resolver = Net::DNS::Resolver::Unbound->new(); plan skip_all => 'resolver not loaded' unless $resolver; 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.32/LICENSE0000644000175000017500000000165214217346602015212 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.32/MANIFEST0000644000175000017500000000064614750646750015351 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 ex/TLSexample.pl META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Net-DNS-Resolver-Unbound-1.32/README0000644000175000017500000000303414217346602015061 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.32/Makefile.PL0000644000175000017500000001132114747204326016155 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 cover -test PlanB } __END__ Net-DNS-Resolver-Unbound-1.32/META.json0000644000175000017500000000265714750646750015645 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.32", "x_serialization_backend" : "JSON::PP version 2.27200" }