1package App::Netdisco::Util::FastResolver; 2 3use strict; 4use warnings; 5use Dancer ':script'; 6 7use AnyEvent::DNS; 8use App::Netdisco::Util::Permission 'check_acl_no'; 9 10use base 'Exporter'; 11our @EXPORT = (); 12our @EXPORT_OK = qw/hostnames_resolve_async/; 13our %EXPORT_TAGS = (all => \@EXPORT_OK); 14 15=head1 NAME 16 17App::Netdisco::Util::FastResolver 18 19=head1 DESCRIPTION 20 21A set of helper subroutines to support parts of the Netdisco application. 22 23There are no default exports, however the C<:all> tag will export all 24subroutines. 25 26=head1 EXPORT_OK 27 28=head2 hostnames_resolve_async( \@ips, \@timeouts? ) 29 30This method uses a fully asynchronous and high-performance pure-perl stub 31resolver C<AnyEvent::DNS>. 32 33Given a reference to an array of hashes will resolve the C<IPv4> or C<IPv6> 34address in the C<ip>, C<alias>, or C<device> key of each hash into its 35hostname which will be inserted in the C<dns> key of the hash. 36 37Optionally provide a set of timeout values in seconds which is also the 38number of resolver attempts. The default is C<< [2,5,5] >>. 39 40Returns the supplied reference to an array of hashes with dns values for 41addresses which resolved. 42 43=cut 44 45sub hostnames_resolve_async { 46 my ($ips, $timeouts) = @_; 47 return [] unless $ips and ref [] eq ref $ips; 48 $timeouts ||= [2,5,5]; 49 50 my $skip = setting('dns')->{'no'}; 51 my $ETCHOSTS = setting('dns')->{'ETCHOSTS'}; 52 AnyEvent::DNS::resolver->timeout(@$timeouts); 53 54 # Set up the condvar 55 my $done = AE::cv; 56 $done->begin( sub { shift->send } ); 57 58 IP: foreach my $hash_ref (@$ips) { 59 my $ip = $hash_ref->{'ip'} || $hash_ref->{'alias'} || $hash_ref->{'device'}; 60 next IP if check_acl_no($ip, $skip); 61 62 # check /etc/hosts file and short-circuit if found 63 foreach my $name (reverse sort keys %$ETCHOSTS) { 64 if ($ETCHOSTS->{$name}->[0]->[0] eq $ip) { 65 $hash_ref->{'dns'} = $name; 66 next IP; 67 } 68 } 69 70 $done->begin; 71 AnyEvent::DNS::reverse_lookup $ip, 72 sub { $hash_ref->{'dns'} = shift; $done->end; }; 73 } 74 75 # Decrement the cv counter to cancel out the send declaration 76 $done->end; 77 78 # Wait for the resolver to perform all resolutions 79 $done->recv; 80 81 # Remove reference to resolver so that we close sockets 82 # and allow return to any instance defaults we have changed 83 undef $AnyEvent::DNS::RESOLVER if $AnyEvent::DNS::RESOLVER; 84 85 return $ips; 86} 87 881; 89