📄 dnswalk
字号:
#!/usr/local/bin/perl# dnswalk Walk through a DNS tree, pulling out zone data and# dumping it in a directory tree## $Id: dnswalk,v 1.4 1993/07/18 00:46:05 barr Exp $## check data collected for legality using standard resolver## invoke as dnswalk domain > logfile# Options:# -r Recursively descend subdomains of domain# -f Force a zone transfer, ignore existing axfr file# -a turn on warning of duplicate A records.# -d Debugging# -m Check only if the domain has been modified. (Useful only if# dnswalk has been run previously.)# -F Enable "facist" checking. (See README)# -l Check lame delegationsrequire "getopts.pl";do Getopts(":rfcadmFl");$basedir = ".";($domain = $ARGV[0]) =~ tr/A-Z/a-z/;if ($domain !~ /\.$/) { die "Usage: dnswalk domain\ndomain MUST end with a '.'\n";}mkdir($basedir,0777);&dowalk($domain);exit;sub dowalk { local (@subdoms); local (@sortdoms); local ($domain)=$_[0]; $modified=0;# ($file,@subdoms)=&doaxfr($domain); /* perl bug */ @subdoms=&doaxfr($domain); $file=shift(@subdoms); if (!($opt_m && !$modified)) { &checkfile($file,$domain); } else { print STDERR "skipping...\n"; } @sortdoms = sort byhostname @subdoms; local ($subdom); if ($opt_r) { foreach $subdom (@sortdoms) { &dowalk($subdom); } }}# try to get a zone transfer, trying each listed authoratative server if# if fails.sub doaxfr { local ($domain)=@_[0]; local (%subdoms)=(); local ($serial); local ($foundsoa)=0; # attempt to make up for dig's poor # error handling ($path=&host2path($domain)) =~ tr/A-Z/a-z/; local(@servers) = &getauthservers($domain); print "warning: $domain has only one authoratative nameserver\n" if (scalar(@servers) == 1); if ((-f "$basedir/$path/axfr") && (!$main'opt_f)) { open(DIG,"<$basedir/$path/axfr"); while (<DIG>) { chop; if (/(\d+)\s*; ?serial/) { $serial=$1; } if (/(\S+)\s*\d+\s+NS/) { $1 =~ tr/A-Z/a-z/; if ((!&equal($1,$domain)) && ( !$subdoms{$1})) { $subdoms{$1}=1; } } } # if there's no serial number in file, assume it is corrupt if ($serial) { foreach $server (@servers) { $authserno=&getserno($domain,$server); last if ($authserno); } if ($authserno <= $serial) { print STDERR "Using existing zone transfer info for $domain\n"; return ("$basedir/$path/axfr", keys %subdoms); } } } &mkdirpath($path); SERVER: foreach $server (@servers) { $SIG{'INT'}="nop;"; print STDERR "Getting zone transfer of $domain from $server..."; open(DIG,"dig axfr $domain \@$server 2>/dev/null |"); open(DIGOUT,">$basedir/$path/axfr"); @subdoms=undef; while (<DIG>) { if (/(\S+)\s*\d+\s+NS/) { $1 =~ tr/A-Z/a-z/; if ((!&equal($1,$domain)) && ( !$subdoms{$1})) { $subdoms{$1}=1; } } elsif (/\S+\s*\d+\s+SOA/) { $foundsoa=1; } print DIGOUT $_; } if ($? || !$foundsoa) { print STDERR "failed.\n"; close(DIGOUT); next SERVER; } print STDERR "done.\n"; close(DIGOUT); close(DIG); last SERVER; } # foreach # $SIG{'INT'}=undef; if ($? || !$foundsoa) { print STDERR "All zone transfer attempts of $domain failed\n"; unlink("$basedir/$path/axfr"); return undef; } $modified=1; return ("$basedir/$path/axfr", keys %subdoms);}# returns "edu/psu/pop" given "pop.psu.edu"sub host2path { join('/',reverse(split(/\./,$_[0])));}# makes sure all directories exist in "foo/bar/baz"sub mkdirpath { local (@path)=split(/\//,$_[0]); local ($dir)=$basedir; foreach $p (@path) { mkdir(($dir .= "/".$p), 0777); }}sub getserno { local ($serno)=""; $SIG{'INT'}="nop;"; open(DIG,"dig soa $_[0] \@$_[1] 2>/dev/null|"); while (<DIG>) { if (/(\d+)\s*; ?serial/) { $serno=$1; } } close(DIG); $SIG{'INT'}=undef; return $serno;}sub getauthservers { local ($domain)=$_[0]; open(DIG,"dig +noau ns $_[0] 2>/dev/null|"); local(@servers); while (<DIG>) { chop; if (/\S+\s*\d+\s+NS\s+(\S+)/) { push(@servers,$1); } } close(DIG); return @servers;}# open result of zone tranfer and check lots of nasty things# here's where the fun beginssub checkfile { open(FILE,"<$_[0]"); print "Checking $domain\n"; local (%glues)=(); # look for duplicate glue (A) records local ($name, $aliases, $addrtype, $length, @addrs); local ($prio,$mx); local ($soa,$contact); local ($lastns); # last NS record we saw local (@keys); # temp variable $soa=undef; while (<FILE>) { chop; if (/^;/) { if (/(.*[Ee][Rr][Rr][Oo][Rr].*)/) { # print any dig errors print $1 ."\n"; next; } } next if /^$/; # skip blanks split(/\t/); # 0=key 2=rrtype 3=value (4=value if 2=MX) next if ($_[0] =~ /;/); if ($_[0] =~ /[^-A-Za-z0-9._]/) { # I know, underscores aren't kosher but .... print " $_[0]: invalid character(s) in name\n"; } if ($_[2] eq "SOA") { print STDERR 's' if $opt_d; if (! $soa) { # aviod duplicate SOA's. Argh. ($soa,$contact) = $_[3] =~ /(\S+)\s+(\S+)/; print "SOA=$soa contact=$contact\n"; } } elsif ($_[2] eq "PTR") { print STDERR 'p' if $opt_d; if (scalar((@keys=split(/\./,$_[0]))) == 6 ) { # check if forward name exists, but only if reverse is # a full IP addr # skip ".0" networks if ($keys[0] ne "0") { if (!(($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($_[3])) && $!) { print " gethostbyname($_[3]): $!\n"; } else { if (!$name) { print " $_[0] PTR $_[3]: unknown host\n"; } elsif (!&equal(($name.'.'),$_[3])) { print " $_[0] PTR $_[3]: CNAME (to $name)\n"; } elsif (!&matchaddrlist($_[0])) { print " $_[0] PTR $_[3]: A record not found\n"; } } } } } elsif (($_[2] eq "A") ) { print STDERR 'a' if $opt_d;# check to see that a reverse PTR record exists if (!(($name,$aliases,$addrtype,$length,@addrs)=gethostbyaddr(pack('C4', split(/\./,$_[3])),2)) && $!) { print " gethostbyaddr($_[3]): $!\n"; } else { if (!$name) { print " $_[0] A $_[3]: no PTR record\n"; } elsif ($opt_F && !&equal($name.".",$_[0])) { print " $_[0] A $_[3]: points to $name\n" if ((split(/\./,$name,1))[0] ne "localhost"); } if ($main'opt_a) { # keep list in %glues, report any duplicates if ($glues{$_[3]} eq "") { $glues{$_[3]}=$_[0]; } elsif (($glues{$_[3]} eq $_[0]) && (!&equal($lastns,$domain))) { print " $_[0]: possible duplicate A record (glue of $lastns?)\n"; } } } } elsif ($_[2] eq "NS") { $lastns=$_[0]; print STDERR 'n' if $opt_d; # check to see if object of NS is real &checklamer($_[0],$_[3]) if ($main'opt_l); if (!(($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($_[3])) && $!) { print " gethostbyname($_[3]): $!\n"; } else { if (!$name) { print " $_[0] NS $_[3]: unknown host\n"; } elsif (!&equal(($name.'.'),$_[3])) { print " $_[0] NS $_[3]: CNAME (to $name)\n"; } } } elsif ($_[2] eq "MX") { print STDERR 'm' if $opt_d; # check to see if object of mx is real ($prio,$mx)=split(/ /,$_[3]); if (!(($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($mx)) && $!) { print " gethostbyname($mx): $!\n"; } else { if (!$name) { print " $_[0] MX $_[3]: unknown host\n"; } elsif (!&equal(($name.'.'),$mx)) { print " $_[0] MX $_[3]: CNAME (to $name)\n"; } } } elsif ($_[2] eq "CNAME") { print STDERR 'c' if $opt_d; if (!(($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($_[3])) && $!) { print " gethostbyname($_[3]): $!\n"; } else { if (!$name) { print " $_[0] CNAME $_[3]: unknown host\n"; } elsif (!&equal(($name.'.'),$_[3])) { print " $_[0] CNAME $_[3]: CNAME (to $name)\n"; } } } } print STDERR "\n" if $opt_d; close(FILE);}sub equal { # Do case-insensitive string comparisons local ($one)= $_[0]; local ($two)= $_[1]; $one =~ tr/A-Z/a-z/; $two =~ tr/A-Z/a-z/; return ($one eq $two);}sub matchaddrlist { local($match)=pack('C4', reverse(split(/\./,$_[0],4))); local($found)=0; foreach $i (@addrs) { $found=1 if ($i eq $match); } return $found;}# there's a better way to do this, it just hasn't evolved from# my brain to this program yet.sub byhostname { @c = reverse(split(/\./,$a)); @d = reverse(split(/\./,$b)); for ($i=0;$i<=(($#c > $#d) ? $#c : $#d) ;$i++) { next if $c[$i] eq $d[$i]; return -1 if $c[$i] eq ""; return 1 if $d[$i] eq ""; if ($c[$i] eq int($c[$i])) { # numeric return $c[$i] <=> $d[$i]; } else { # string return $c[$i] cmp $d[$i]; } } return 0;}sub checklamer { local ($isauth)=0; local ($error)=0; # must check twice, since first query may be authoratative # trap stderr here and print if non-empty open(DIG,"dig soa +noaa $_[0] \@$_[1] 2>&1 1>/dev/null |"); while (<DIG>) { print " $_[0] NS $_[1]: nameserver error (lame?):\n" if !$error; print; $error=1; } close(DIG); return if $error; open(DIG,"dig soa +noaa $_[0] \@$_[1] 2>/dev/null|"); while (<DIG>) { if (/;; flags.*aa.*;/) { $isauth=1; } } if (!$isauth) { print " $_[0] NS $_[1]: lame NS delegation\n"; } close(DIG); return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -