#!/usr/bin/perl # Copyright (c) 2008, 2010, 2011 Christoph Berg # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # 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. use strict; use warnings; use Net::DNS; use Getopt::Std; # q no RRSIG output # s full RRSIG output my %opt; getopts ('sS', \%opt); my %cache; my $res; my $rrsigs = 0; my ($c1, $c2, $c3, $c0) = ("", "", ""); ($c1, $c2, $c3, $c0) = map { "\033[${_}m" } qw(32 33 31 0) if (-t 1); sub dns ($$); sub dns ($$) { my ($q, $depth) = @_; return if $cache{$q}; $cache{$q} = 1; my $query = $res->search($q, 'ANY'); if (! $query) { warn " " x $depth, "$c1$q$c0 query failed: $c3", $res->errorstring, "$c0\n"; return; } foreach my $rr ($query->answer) { my $t = $rr->type; my $a = $rr->rdatastr; my $q2 = $a; if ($t =~ /^(AFSDB|MX)$/) { $q2 =~ s/\d+ //; } elsif ($t =~ /^(SOA)$/) { $q2 =~ s/ .*//s; } elsif ($t =~ /^(RP)$/) { # , resolve latter $q2 =~ s/.* //s; } elsif ($t =~ /^(DNSKEY|DS|HINFO|NSEC|NSEC3PARAM|SSHFP|TXT)$/) { $q2 = ""; # no recursion here } elsif ($t =~ /^(RRSIG)$/) { $rrsigs++; next unless ($opt{s} or $opt{S}); $q2 = ""; # no recursion here $a =~ s/ (?:\(.*|[0-9a-f]{32,}$)//s unless ($opt{S}); } my ($cq, $cq0) = ("", ""); ($cq, $cq0) = ($c2, $c0) if ($cache{$q2} and -t 1); print " " x $depth, "$c1$q$c0 $t $cq$a$cq0\n"; next if ($q2 eq '' or $q2 eq '.'); dns ($q2, $depth + 1); } } if (@ARGV and $ARGV[0] =~ /^@(.*)/) { $res = Net::DNS::Resolver->new (nameservers => [$1]); shift; } else { $res = Net::DNS::Resolver->new; } for my $host (@ARGV) { dns ($host, 0); } if ($rrsigs and not $opt{s} and not $opt{S}) { print "$rrsigs RRSIG records omitted\n"; }