IO-Socket-DNS

 view release on metacpan or  search on metacpan

lib/IO/Socket/DNS.pm  view on Meta::CPAN

package IO::Socket::DNS;

use strict;
use warnings;
use Carp qw(croak);
use base qw(Tie::Handle);

our $VERSION = '0.021';

our $count = 0;
# DNS Encoding is simply Base32 encoding using the following alphabet:
our $a32 = [0..9, "a".."w"];

# Max number of bytes to send in each DNS query
our $MAX_WRITE = 100;

# Sentinel value meaning "Incorrect Password"
our $INVALID_PASS = 999;

# new
# This just returns the tie'd file handle
sub new {
    my $class = shift;
    require IO::Handle;
    my $fh = IO::Handle->new;
    my $obj = eval {tie *$fh, $class, @_} or return undef;
    bless $fh, $class;
    return $fh;
}

sub _obj {
    my $self = shift;
    if (my $how = eval {tied *$self}) {
        $self = $how;
    }
    return $self;
}

sub suffix {
    my $self = _obj(shift);
    $self->{Suffix} ||= $ENV{DNS_SUFFIX} || "";
    $self->{Suffix} = lc $self->{Suffix};
    return $self->{Suffix};
}

sub TXT_resolver {
    my $self = shift;
    return $self->{resolver_txt} ||= eval {
        require Net::DNS::Resolver;
    } ? sub {
        my $name = shift;
        # Faster method, but Net::DNS must be installed for this to work.
        return eval { [$self->resolver->query($name, "TXT")->answer]->[0]->txtdata };
    } : do {
        my %args = $self->resolver_args;
        my $nameservers = $args{nameservers};
        if ($nameservers) {
            $nameservers = [split m/ /, $nameservers] if !ref $nameservers;
        }
        $nameservers ||= [""];
        warn "WARNING: Unable to find Net::DNS so reverting to nslookup (slow spawn) method ...\n";
        # Return a closure containing the lexically scoped $nameservers variable.
        sub {
            my $name = shift;
            # Make sure it is rooted to reduce unnecessary search scanning.
            $name =~ s/\.*$/./;
            # Try each resolver (if specified) until one works.
            foreach my $server (@$nameservers) {
                # Yes, it's slower, but is likely to work even if Net::DNS is gone.
                if (`nslookup -type=TXT $name $server 2>&1`=~/"(.+)"/) {
                    return $1;
                }
            }
            return undef;
        };
    };
};

sub resolver_args {
    my $self = _obj(shift);
    my @args = !$self->{Resolver} ? ()
        : !ref($self->{Resolver}) ? (nameservers => $self->{Resolver})
        : "ARRAY" eq ref($self->{Resolver}) ? (@{ $self->{Resolver} })
        : "HASH"  eq ref($self->{Resolver}) ? (@{ %{ $self->{Resolver} } })
        : ();
    return @args;
}

sub resolver {
    my $self = _obj(shift);
    return ($self->{net_dns} ||= eval {
        require Net::DNS::Resolver;
        return Net::DNS::Resolver->new($self->resolver_args);
    } || eval {
        # Try emergency "nslookup"
        my $suffix = $self->suffix;
        my $try = `nslookup -type=TXT nslookup.$suffix 2>&1`;
        if ($try =~ /"(.+)"/) {
            my $shell = $1;
            $shell =~ s/\bperl\b/$^X/g;
            system $shell;
            warn "Reloading Net::DNS ...\n";
            delete $INC{"Net/DNS.pm"};
            delete $INC{"Net/DNS/Resolver.pm"};
            require Net::DNS::Resolver;
            return $self->resolver;
        }
        return undef;
    } or do {
        warn  "Unable to obtain resolver. Please pass in your own net_dns setting: $@";
        exit 1;
    });
}

sub dnsencode {
    my $self = shift;
    my $decode = shift;
    my $x = unpack "B*", $decode;



( run in 0.737 second using v1.01-cache-2.11-cpan-71847e10f99 )