dnswalk-2.0.2/0000755000175000017500000000000010721763620011616 5ustar pabspabsdnswalk-2.0.2/TODO0000644000175000017500000000110006401330265012271 0ustar pabspabsreplace remaining gethostby*() calls with Net::DNS calls. (better error reporting) compare serial number of zone transfer data and report differences Check RP records that they point to a TXT record. Check for CNAME and other data. (modern BIND versions disallow this, but not everyone sadly is up to date) Check parent delegation (a la doc) and check for lame delegations. Compare serial numbers of all NS servers and report differences. (a la doc) ./dnswalk non-existant.domain doesn't generate a very useful message complete RFC 1101 check.. A records in rev file dnswalk-2.0.2/dnswalk.10000644000175000017500000001701306371642475013357 0ustar pabspabs.TH DNSWALK 1 .SH NAME dnswalk \- A DNS database debugger .SH SYNOPSIS .B dnswalk [ .BR \- adilrfFm ] .I domain. .SH "DESCRIPTION" .B dnswalk is a DNS debugger. It performs zone transfers of specified domains, and checks the database in numerous ways for internal consistency, as well as for correctness according to accepted practices with the Domain Name System. .PP The .I domain name specified on the command line MUST end with a '.'. You can specify a forward domain, such as .B dnswalk podunk.edu. or a reverse domain, such as .B dnswalk 3.2.1.in-addr.arpa. .SH OPTIONS .PD 0 .TP .BI \-r Recursively descend sub-domains of the specified domain. Use with care. .TP .BI \-a Turn on warning of duplicate A records. (see below) .TP .BI \-d Print debugging and 'status' information to stderr. (Use only if redirecting stdout) See DIAGNOSTICS section. .TP .BI \-m Perform checks only if the zone has been modified since the previous run. .TP .BI \-F perform "fascist" checking. When checking an A record, compare the PTR name for each IP address with the forward name and report mismatches. (see below) I recommend you try this option at least once to see what sorts of errors pop up - you might be surprised!. .TP .BI \-i Suppress check for invalid characters in a domain name. (see below) .TP .BI \-l Perform "lame delegation" checking. For every NS record, check to see that the listed host is indeed returning authoritative answers for this domain. .TP .SH ERRORS The following the list of error messages that .B dnswalk will return if it sees a potential problem with the database. Duplicate messages will be suppressed automatically for each zone. Error messages are prefixed by a keyword indiciating the message type: "WARN" (possible data problem), "FAIL" (failure to access data), or "BAD" (invalid data). .B dnswalk exits with a return code equal to the number of "BAD" errors. .TP .PD 0 .BI "X PTR Y: unknown host" X is a PTR record to Y, but Y is not a valid host (no A record). These are often left over from when someone deleted a host from the DNS and forgot to delete the PTR record. .TP .BI "X PTR Y: A record not found" X is a PTR record to Y, but the IP address associated with the PTR record is not listed as an address for Y. There should be an A record for every valid IP address for a host. Many Internet services will not talk to you if you have mismatched PTR records. .TP .BI "X PTR Y: CNAME (to Z)" X is a PTR record to Y, but Y is a CNAME to Z. PTR records MUST point to the canonical name of a host, not an alias. .TP .BI "X CNAME Y: unknown host" X is aliased to Y, but Y is not a valid host (no A record). .TP .BI "X CNAME Y: CNAME (to Z)" X is aliased to Y, but Y is aliased to Z. CNAMEs should not be chained. .TP .BI "X MX Y: unknown host" X is an MX to Y, but Y is not a valid host (no A record). .TP .BI "X MX Y: CNAME (to Z)" X is an MX to Y, but Y is an alias for Z. MX records must point to the canonical name, not an alias. .TP .BI "X A Y: no PTR record" X has an IP address Y, but there is no PTR record to map the IP address Y back to a hostname (usually X). Many Internet servers (such as anonymous FTP servers) will not talk to addresses that don't have PTR records. .TP .BI "warning: X has only one authoritative nameserver" Zones must have at least one authoritative nameserver, in case one is down or unreachable. Make sure the parent and child domains list all authoritative nameservers for a zone. .TP .BI "Cannot check X: no available nameservers!" The X zone was delegated with NS records but all the nameservers for the zone are either unavailable or say that they have no data for the zone (are lame). Verify that the X zone isn't a typo, and if so make sure that all the listed nameservers are configured to answer with data for the zone. .TP .BI "X: invalid character(s) in name" Allowable characters in a domain name are the ASCII letters a through Z the digits 0 through 9, and the "-" character. A "." may be used only as a domain separator. (checking can be suppressed with .B \-i ) .TP .BI "X: domain occurred twice, forgot trailing '.'?" A sanity check which looks for "dom.ain.dom.ain." in a name. This is often caused by forgetting to put a trailing '.' on the end of a name. .TP (with -a switch) .TP .BI "X: possible duplicate A record (glue of Z?)" A duplicate A records is listed for X. NOTE: this is most often caused by the practice of always putting A records for all secondaries after NS glue records. While this is not an error, it is usually redundant and makes changing IP addresses later more difficult, since they occur more than one time in the file (and in multiple files). You may get spurious errors, mostly because of a quirk in BIND releases before 4.9.x that reports cached glue A records in a zone transfer even though they don't exist in the original zone file. .TP (with -F switch) .TP .BI "X A Y: points to Z" X has Y for an IP address, but the PTR record associated with Y returns "Z" as the name associated with that host. This is not necessarily an error (for example if you have an A record for your domain name), but can be useful to check for A records which point to the wrong host, or PTR records that point to the wrong host. .TP .BI "Cannot find address for nameserver X" This error is generated if the address for a delegated nameserver X cannot be resolved. This could be a lame delegation (due to a typo in delegation), or a temporary DNS error. .TP (with -l switch) .TP .BI "X NS Y: lame NS delegation" Y is a listed nameserver for zone X, but Y is not returning authoritative data for zone X. This is usually the result of a lack of communication on the part of the respective hostmasters. Lame delegations are not fatal problems except in severe cases, they just tend to create significant increases in DNS traffic. NS records for the parent and child domains should be consistent, and each server listed in the NS record MUST be able to answer with authoritative data, either by being a primary or secondary for the zone. .TP .BI "Cannot get SOA record for X from Y (lame?)" This error is generated if dnswalk cannot get the SOA record for zone X from the nameserver Y. This could mean a lame delegation, or simply that the host is temporarily unreachable. .SH "SEE ALSO" .nf RFC 1034 - "DOMAIN NAMES - CONCEPTS AND FACILITIES" RFC 1035 - "DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION" RFC 1123 - "Requirements for Internet Hosts -- Application and Support" Paul Albitz, Cricket Liu: "DNS and BIND" O'Reilly & Associates. .SH DIAGNOSTICS When invoked with the .B \-d option, .B dnswalk will print status information to stderr. It consists of information about what zone is being checked, and a single letter corresponding to the resource record checked, and any errors. .TP .BI a A record .TP .BI c CNAME record .TP .BI p PTR record .TP .BI m MX record .TP .BI s SOA record .TP .BI ! An error occurred .TP .BI . A previous error in the zone was repeated, but suppressed. .PP .SH BUGS dnswalk will make the directory tree before it has a chance to find out that you gave it a bogus domain name. .PP When checking lots of hosts and lots of options, it is very slow. Running dnswalk on a machine with a local nameserver helps considerably. .PP Perl's gethostby{name,addr}() routine doesn't seem to consistently return an error whenever it is unable to resolve an address. Argh. This will mean lots of "no PTR record" and "host unknown" errors if a server is unavailable, or for some reason the lookup fails. You may get strange error messages if your perl was compiled without support for herror(). .PP .SH AUTHOR David Barr dnswalk-2.0.2/README0000644000175000017500000001026506371424362012505 0ustar pabspabs dnswalk 2.0 - August 4, 1997 Author: David Barr $Id: README,v 1.6 1997/08/04 19:09:34 barr Exp barr $ INTRO dnswalk is a DNS debugger. It performs zone transfers of specified domains, and checks the database in numerous ways for internal consistency, as well as accuracy. dnswalk requires perl and the Net::DNS Perl package. If you do not have these, get them. (perl is assumed to be in /usr/local/bin, edit the first line of dnswalk if it is not) They can be found by at: http://www.perl.com/perl/ dnswalk used to require 'dig' (part of the BIND distribution). However, different versions of dig gave output which was ever so slightly different, causing dnswalk to break. (This is usually easy to fix, even in a backward-compatible fashion, but it was annoying nonetheless) Also, using an external program made error checking more difficult and not very reliable. Since error checking is the heart of what dnswalk is about, this wasn't good. I finally got off my duff and ported dnswalk to Michael Fuhr's Net::DNS package, something I've been wanting to do for a while. (actually another reason I waited so long was the Net::DNS package wasn't complete enough initially for for a complete port.) dnswalk is not for the faint of heart. It should NOT be used without a firm knowledge of the DNS RFC's. The warnings and errors must be interpreted within the context they are being used. Something may be flagged as a warning, but in reality it is a really bad error. Conversely dnswalk will flag things as warnings and possibly even errors, but they may actually be perfectly "legal" or normal in your specific situation. dnswalk is not an AI engine. It just provides useful information which you need to interpret. If you use this tool for cracking or otherwise evil purposes, the author hereby considers you a slime-ball. See the end of this README file for a list of good reading material. dnswalk is not a replacement for doc, although dnswalk is starting to incorporate some of the things doc checks for. dnswalk was written to check individual database entries, while 'doc' ensures that the overall database structure and authority records are consistent. dnswalk may not even function correctly (or find real problems) if authority records are missing or incorrect. This program may be freely distributed, as long as this notice and documentation are distributed with the program. This program is released as-is, with no warranty expressed or implied. Some assembly required, contents may settle during shipment. This program can be found at http://www.cis.ohio-state.edu/~barr/dnswalk/ dnswalk tends to produce lots of output, so I'd suggest redirecting this into a file of your choice. I debated using doc's strategy of automatically putting it in a logfile, but decided not to. (The author reserves the right to change his mind) For small, mostly-correct domains it is pretty manageable, however. For larger domains, use the included 'do-dnswalk' script as a guide. Please refer to the man page on what dnswalk checks for, and the format of the output. *** NOTICE *** I fully realize that while some of the rules are not in violation of an RFC, it might be wise to reconsider their usage anyway. dnswalk was written to be a tool to let the hostmaster decide what are troublesome areas, not as a program that has all the answers. *** NOTICE *** This program was originally tested with data from the psu.edu domain. If your site does things differently than the way we do things, then you may see it report things as errors, when in fact they are "okay". If you notice something not being reported, or something reported that is not an error, please send me output! I fully admit that I'm not an expert in DNS and the requirements. My rules tend to be skewed to my personal feelings about what "nice" DNS databases look like. Others are free to differ. (and tell me so) Author: David Barr Lead System Administrator The Ohio State University, Department of Computer and Information Science Thanks: Bill Fenner - tips with perl Michael Fuhr - for writing Net::DNS! Dave Crocker - for providing the spark necessary for me to pick up developement of dnswalk-2.0 again. dnswalk-2.0.2/dnswalk0000755000175000017500000003176306416163160013220 0ustar pabspabs#!/usr/contrib/bin/perl # # dnswalk Walk through a DNS tree, pulling out zone data and # dumping it in a directory tree # # $Id: dnswalk,v 1.18 1997/10/06 13:23:58 barr Exp barr $ # # check data collected for legality using standard resolver # # invoke as dnswalk domain > logfile # Options: # -r Recursively descend subdomains of domain # -i Suppress check for invalid characters in a domain name. # -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 man page) # -l Check lame delegations use Getopt::Std; use IO::Socket; use Net::DNS; getopts("D:rfiadmFl"); $num_error{'FAIL'}=0; # failures to access data $num_error{'WARN'}=0; # questionable data $num_error{'BAD'}=0; # bad data # Where all zone transfer information is saved. You can change this to # something like /tmp/dnswalk if you don't want to clutter up the current # directory if ($opt_D) { $basedir = $opt_D; } else { $basedir = "."; } ($domain = $ARGV[0]) =~ tr/A-Z/a-z/; if ($domain !~ /\.$/) { die "Usage: dnswalk domain\ndomain MUST end with a '.'\n"; } if (! -d $basedir) { mkdir($basedir,0777) || die "FAIL: Cannot create $basedir: $!\n"; } &dowalk($domain); print STDERR "$num_error{'FAIL'} failures, $num_error{'WARN'} warnings, $num_error{'BAD'} errors.\n"; exit $num_error{'BAD'}; sub dowalk { my (@subdoms); my (@sortdoms); my ($domain)=$_[0]; $modified=0; return unless $domain; print "Checking $domain\n"; @subdoms=&doaxfr($domain); &check_zone($domain) if (defined(@zone) && @zone); undef @zone; return if (!(defined(@subdoms) && @subdoms)); @sortdoms = sort byhostname @subdoms; local ($subdom); if ($opt_r) { foreach $subdom (@sortdoms) { &dowalk($subdom); } } } # try to get a zone transfer, trying each listed authoritative server if # if fails. sub doaxfr { local ($domain)=@_[0]; local (%subdoms)=(); local ($subdom); local(@servers) = &getauthservers($domain); &printerr("BAD", "$domain has only one authoritative nameserver\n") if (scalar(@servers) == 1); &printerr("BAD", "$domain has NO authoritative nameservers!\n") if (scalar(@servers) == 0); SERVER: foreach $server (@servers) { print STDERR "Getting zone transfer of $domain from $server..."; my $res = new Net::DNS::Resolver; $res->nameservers($server); @zone=$res->axfr($domain); unless (defined(@zone) && @zone) { print STDERR "failed\n"; &printerr("FAIL", "Zone transfer of $domain from $server failed: ". $res->errorstring. "\n"); next SERVER; } @subdoms=undef; foreach $rr (@zone) { if ($rr->type eq "NS") { $subdom = $rr->name; $subdom =~ tr/A-Z/a-z/; if ((!&equal($subdom,$domain)) && ( !$subdoms{$subdom})) { $subdoms{$subdom}=1; } } } print STDERR "done.\n"; last SERVER; } # foreach # unless (defined(@zone) && @zone) { &printerr("BAD","All zone transfer attempts of $domain failed!\n"); return undef; } return (keys %subdoms); } sub getauthservers { my ($domain)=$_[0]; my ($master)=&getmaster($domain); my ($foundmaster)=0; my ($ns); my ($ns_tmp); my ($res); my ($ns_req); my (@servers); my (%servhash); return if (!$master); # this is null if there is no SOA or not found return if (!$domain); $res = new Net::DNS::Resolver; $ns_req = $res->query($domain, "NS"); &printerr("FAIL", "No nameservers found for $domain: ". $res->errorstring ."\n") unless (defined($ns_req) and ($ns_req->header->ancount > 0)); foreach $ns ($ns_req->answer) { $ns_tmp = $ns->nsdname; $ns_tmp =~ tr/A-Z/a-z/; if (&equal($ns_tmp,$master)) { $foundmaster=1; # make sure the master is at the top } else { push(@servers,$ns_tmp) if ($servhash{$ns_tmp}++<1); } } if ($foundmaster) { unshift(@servers,$master); } return @servers; } # return 'master' server for zone sub getmaster { my ($zone)=$_[0]; my ($res) = new Net::DNS::Resolver; my ($packet) = new Net::DNS::Packet($zone, "SOA", "IN"); my ($soa_req) = $res->send($packet); unless (defined($soa_req)) { &printerr("FAIL", "Cannot get SOA record for $zone:". $res->errorstring ."\n"); return ""; } unless (($soa_req->header->ancount >= 1) && (($soa_req->answer)[0]->type eq "SOA")) { &printerr("BAD", "SOA record not found for $zone\n"); return ""; } return ($soa_req->answer)[0]->mname; } # open result of zone tranfer and check lots of nasty things # here's where the fun begins sub check_zone { my ($domain)=$_[0]; 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 foreach $rr (@zone) { # complain about invalid chars only for mail names if ((($rr->type eq "A") || ($rr->type eq "MX")) && (!$opt_i) && ($rr->name =~ /[^\*][^-A-Za-z0-9.]/)) { &printerr("WARN", $rr->name .": invalid character(s) in name\n"); } if ($rr->type eq "SOA") { print STDERR 's' if $opt_d; print "SOA=". $rr->mname ." contact=". $rr->rname ."\n"; # basic address check. No "@", and user.dom.ain (two or more dots) if (($rr->rname =~ /@/)||!($rr->rname =~ /\..*\./)) { &printerr("WARN", "SOA contact name (". $rr->rname .") is invalid\n"); } } elsif ($rr->type eq "PTR") { print STDERR 'p' if $opt_d; if (scalar((@keys=split(/\./,$rr->name))) == 6 ) { # check if forward name exists, but only if reverse is # a full IP addr # skip ".0" networks if ($keys[0] ne "0") { ($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($rr->ptrdname); # if (!(($name, $aliases, $addrtype, $length, # @addrs)=gethostbyname($rr->ptrdname))) { # &printerr("FAIL", "gethostbyname(". # $rr->ptrdname ."): $!\n"); # } # else { if (!$name) { &printerr("WARN", $rr->name ." PTR ". $rr->ptrdname .": unknown host\n"); } elsif (!&equal($name,$rr->ptrdname)) { &printerr("WARN", $rr->name ." PTR ". $rr->ptrdname .": CNAME (to $name)\n"); } elsif (!&matchaddrlist($rr->name)) { &printerr("WARN", $rr->name ." PTR ". $rr->ptrdname .": A record not found\n"); } # } } } } elsif (($rr->type eq "A") ) { print STDERR 'a' if $opt_d; # check to see that a reverse PTR record exists ($name,$aliases,$addrtype,$length,@addrs)=gethostbyaddr(pack('C4', split(/\./,$rr->address)),2); if (!$name) { # hack - allow RFC 1101 netmasks encoding if ($rr->address !=~ /^255/) { &printerr("WARN", $rr->name ." A ". $rr->address .": no PTR record\n"); } } elsif ($opt_F && !&equal($name,$rr->name)) { # Filter out "hostname-something" (like "neptune-le0") if (index(split (/\./, $rr->name, 2) . "-", split (/\./, $name, 2)) == -1 ) { &printerr("WARN", $rr->name ." A ". $rr->address .": points to $name\n") if ((split(/\./,$name))[0] ne "localhost"); } } if ($main'opt_a) { # keep list in %glues, report any duplicates if ($glues{$rr->address} eq "") { $glues{$rr->address}=$rr->name; } elsif (($glues{$rr->address} eq $rr->name) && (!&equal($lastns,$domain))) { &printerr("WARN", $rr->name .": possible duplicate A record (glue of $lastns?)\n"); } } } elsif ($rr->type eq "NS") { $lastns=$rr->name; print STDERR 'n' if $opt_d; # check to see if object of NS is real &checklamer($rr->name,$rr->nsdname) if ($main'opt_l); # check for bogusnesses like NS->IP addr if (&isipv4addr($rr->nsdname)) { &printerr("BAD", $rr->name ." NS ". $rr->nsdname .": Nameserver must be a hostname\n"); } ($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($rr->nsdname); # if (!(($name, $aliases, $addrtype, $length, # @addrs)=gethostbyname($rr->nsdname))) { # &printerr("FAIL", "gethostbyname(". $rr->nsdname ."): $!\n"); # } # else { if (!$name) { &printerr("BAD", $rr->name ." NS ". $rr->nsdname .": unknown host\n"); } elsif (!&equal($name,$rr->nsdname)) { &printerr("BAD", $rr->name ." NS ". $rr->nsdname .": CNAME (to $name)\n"); } # } } elsif ($rr->type eq "MX") { print STDERR 'm' if $opt_d; # check to see if object of mx is real if (&isipv4addr($rr->exchange)) { &printerr("BAD", $rr->name ." MX ". $rr->exchange .": Mail exchange must be a hostname\n"); } ($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($rr->exchange); # if (!(($name, $aliases, $addrtype, $length, # @addrs)=gethostbyname($rr->exchange))) { # &printerr("FAIL", "gethostbyname(". $rr->exchange ."): $!\n"); # } # else { if (!$name) { &printerr("WARN", $rr->name ." MX ". $rr->exchange .": unknown host\n"); } elsif (!&equal($name,$rr->exchange)) { &printerr("WARN", $rr->name ." MX ". $rr->exchange .": CNAME (to $name)\n"); } # } } elsif ($rr->type eq "CNAME") { print STDERR 'c' if $opt_d; ($name, $aliases, $addrtype, $length, @addrs)=gethostbyname($rr->cname); if (&isipv4addr($rr->cname)) { &printerr("BAD", $rr->name ." CNAME ". $rr->cname .": alias must be a hostname\n"); } # if (!(($name, $aliases, $addrtype, $length, # @addrs)=gethostbyname($rr->cname))) { # &printerr("FAIL", "gethostbyname(". $rr->cname ."): $!\n"); # } # else { if (!$name) { &printerr("WARN", $rr->name ." CNAME ". $rr->cname .": unknown host\n"); } elsif (!&equal($name,$rr->cname)) { &printerr("WARN", $rr->name ." CNAME ". $rr->cname .": CNAME (to $name)\n"); } # } } } print STDERR "\n" if $opt_d; close(FILE); } # prints an error message, suppressing duplicates sub printerr { my ($type, $err)=@_; if ($errlist{$err}==undef) { print "$type: $err"; $num_error{$type}++; print STDERR "!" if $opt_d; $errlist{$err}=1; } else { print STDERR "." if $opt_d; } } sub equal { # Do case-insensitive string comparisons local ($one)= $_[0]; local ($two)= $_[1]; $stripone=$one; if (chop($stripone) eq '.') { $one=$stripone; } $striptwo=$two; if (chop($striptwo) eq '.') { $two=$striptwo; } $one =~ tr/A-Z/a-z/; $two =~ tr/A-Z/a-z/; return ($one eq $two); } # check if argument looks like an IPv4 address sub isipv4addr { my ($host)=$_[0]; my ($one,$two,$three,$four); ($one,$two,$three,$four)=split(/\./,$host); my $whole="$one$two$three$four"; # strings evaluated as numbers are zero return (($whole+0) eq $whole); } 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 { my ($zone,$nameserver)=@_; my ($packet) = new Net::DNS::Packet($zone, "SOA", "IN"); my ($soa_req); my ($res) = new Net::DNS::Resolver; unless ($res->nameservers($nameserver)) { &printerr("FAIL", "Cannot find address for nameserver: ". $res->errorstring. "\n"); } $soa_req = $res->send($packet); unless (defined($soa_req)) { &printerr("FAIL", "Cannot get SOA record for $zone from $nameserver (lame?): ". $res->errorstring ."\n"); return; } &printerr("BAD", "$zone NS $nameserver: lame NS delegation\n") unless ($soa_req->header->aa); return; } dnswalk-2.0.2/do-dnswalk0000755000175000017500000000114706371377724013626 0ustar pabspabs#!/bin/sh # Here's an example script for a hostmaster of a large site # to automate the process # You can also run "./makereports ${logfile} ./dnswalk ${flags} $* podunk.edu. ./dnswalk ${flags} $* 1.1.in-addr.arpa. ./dnswalk ${flags} $* 2.1.in-addr.arpa. ./dnswalk ${flags} $* 1.2.1.in-addr.arpa. ./dnswalk ${flags} $* 2.2.1.in-addr.arpa. dnswalk-2.0.2/makereports0000755000175000017500000000124606373614445014113 0ustar pabspabs#!/usr/contrib/bin/perl # This takes output from dnswalk and makes a "rep.orts" directory # with one file per contact. Great for sending mail to all the admins. mkdir("rep.orts",0777); while (<>) { if (/^Checking (.*).$/) { $zone=$1; next; } if (/^warning: .* has /) { # ugly $warning=$_; next; } if (/^SOA.*contact=(.*)$/) { close(REPORT); $contact=$1; $contact=~ tr/A-Z/a-z/; print "writing report for $contact\n"; open(REPORT,">>rep.orts/$contact") || die "cannot write to rep.orts/$1: $!\n"; print REPORT "Potential errors for zone: $zone\n"; if ($warning) { print REPORT $warning; undef $warning; } } print REPORT; } close(REPORT); dnswalk-2.0.2/CHANGES0000644000175000017500000001427206416163514012621 0ustar pabspabs$Id: CHANGES,v 1.11 1997/10/06 13:27:37 barr Exp barr $ Version 2.0.2 Silly bug in output, SOA= was listing the domain, not the master. Reported by Jeff Miller . dnswalk now checks to see that target of MX, CNAME and NS are a hostname, not an IP addr. Version 2.0.1 Regexp bug in 'makereports' script. (chopped off last charcter of contact address). Version 2.0.0 (beta) Ported to Net::DNS. Now no longer relies on 'dig'. Some less-used error messages removed, such as the 'double domain' check. dnswalk now no longer saves zone transferrs to local files, due to the fact that dnswalk no longer uses 'dig'. The zone transfer itself doesn't take that long -- mostly it's CPU time churning on what comes in. I may add it back if there's enough demand (using the "Storage" perl package, like what is used by the Net::DNS package's examples) Added 'WARN', 'FAIL', and 'BAD' prefixes to error messages, to indicate some level of 'badness' associated with a particular message. Makes machine parsing easier, as well as human interpreting. ('FAIL' was called 'ERROR' before beta release). dnswalk now exits with a return code equal to the number of 'BAD' things found. (from an request by Dave Crocker) dnswalk (with -F fascist checking) no longer gives A record warnings with hosts like "neptune" and "neptune-le0" (it treats them as the same host). Formerly it would warn that A record for neptune-le0 "points to" neptune. (this is a common situation with multi-homed hosts, where A records pointing just to individual interfaces are used). Anything "host-something" is treated the same as "host". (request from David Nelson ) perform some rudimentary checks on SOA contact field. (99% of the time the error is someone forgetting you have to replace the "@" sign in the email address with a ".".) Reformatted the code to be a bit more readable. Version 1.8.3 Miscellaneous fixes, getautservers(). Condensed code. Hack added to ignore RFC 1101 netmasks encoding. Assigning $1 wasn't working, use local variable. Patch from Mark Andrews . New Perl script "makereports" included to take output and generate reports for each hostmaster for the problems within his/her zone. Suggestion by marka@syd.dms.CSIRO.AU (Mark Andrews) to only check for invalid characters on A or MX records. I could probably do two-level checking, one for 1033 compliance on all records and 1035 compliance on mail-able names (A and MX). However this is a reasonable compromise for now. Version 1.8.2 Fixed spelling errors and shoddy syntax in getauthservers(), from Jost Krieger Accounted for Solaris's broken gethostbyname() which includes trailing dots in retuned name. Minor fixes in lame delegation checking, and getauthservers(). Version 1.8.1 One-line fix to remove reference to non-existent parameter to getmaster(). Reported by petri@ibr.cs.tu-bs.de (Stefan Petri). Version 1.8 Typos, documentation corrections, additions to TIPS as well as stuff for TODO from Piete Brooks . Patch from Thorsten Lockert : remove directory if zone transfer fails. Fixed getauthservers() routine. Sometimes had list of servers which contained each server listed twice. Also fixed it to use the 'master server' field of the SOA record as a 'hint' to which server to check first. Fixed typo in dot-death checking. Error message forgot \n. Added -D flag to set base directory for saved axfr files. Version 1.7 Added "_" to list of invalid characters in a hostname. (Painful because we have hundreds of PCs and Macs here with one.) Can now be supressed with '-i' option (whew). Fixed wildcard RR's being marked as having invalid characters. (Thanks to Paul Turner for reporting it) Changed how the return codes for gethostby*() routines were being checked. Added caveat in README about herror(). Thanks to Bill Fenner Suppresses duplicate error message per zone. Idea from Paul Turner. Checks for dom.ain.dom.ain. in data, in case someone forgot the trailing '.'. Finally added a man page. Trimmed out redundant information from the README file. Version 1.6 removed -c switch, since I thought it would work a long time ago, but later found out it could never be made to work. Well, it could, just not very nicely. (nor efficiently) Fixed bug with parsing of dig output. Newer dig has slightly different output, causing serial numbers to not be pulled out. Changed the do-dnswalk script to use exec > logfile instead of redirecting every invocation to a logfile. Idea from Dan Ehrlich. Fixed problem with dnswalk using old list of subdomains in axfr file, ignoring the new zone transfer if it was needed. Accounted for annoying behavior of new dig to print duplicate SOA's. Documented nameserver error reporting. Version 1.5 added -F switch. This performs "fascist" checking. For every A record, it checks to see that it actually points to the canonical name listed for the PTR and reports mismatches. Try this switch at least once to see what kind of things pop up. (You may be surprised) added -m switch. Performs check on zone only if it has been modified (serial number changed) since the previous run. changed format of messages to be shorter and more precise. (and hopefully easier to read) Read the README section for a full description. warns if a zone has only one authoratative nameserver *** in later versions of 1.3, not posted here, but available for ftp, there was a bad bug which caused erroneous warnings about having only one nameserver. (was using the wrong variable) reports any errors listed in dig zone transfer output. (usually caused by a corrupted zone file, or invalid syntax in data; for example only one field in an HINFO record.) now reports any resolver errors from gethostbyname and gethostbyaddr. (for example, a server timeout, connection refused, etc) sorts output by zone (correctly -- some versions of 1.3 didn't quite do this right) displays server of authority and zone contact for each zone it checks. I've now included a 'do-dnswalk' script that is an example wrapper that I use around dnswalk to turn on status debugging and put the results in a log file. Salt to taste. dnswalk-2.0.2/dnswalk.errors0000644000175000017500000001225106371376233014526 0ustar pabspabs The following the list of error messages that dnswalk will return if it sees a potential problem with the database. Duplicate messages will be suppressed automatically for each zone. X PTR Y: unknown host X is a PTR record to Y, but Y is not a valid host (no A record). These are often left over from when someone deleted a host from the DNS and forgot to delete the PTR record. These records should be removed. X PTR Y: A record not found X is a PTR record to Y, but the IP address associated with the PTR record is not listed as an address for Y. There should be an A record for every valid IP address for a host. Many Internet services will not talk to you if you have mismatched PTR records. X PTR Y: CNAME (to Z) X is a PTR record to Y, but Y is a CNAME to Z. PTR records should point to the real name of a host, not an alias. X CNAME Y: unknown host X is aliased to Y, but Y is not a valid host (no A record). This is a stale entry and should be removed. X CNAME Y: CNAME (to Z) X is aliased to Y, but Y is aliased to Z. CNAMEs should not be chained together. It has been known to cause problems with some software. X MX Y: unknown host X is an MX to Y, but Y is not a valid host (no A record). This is a stale entry and should be removed. X MX Y: CNAME (to Z) X is an MX to Y, but Y is an alias for Z. MX records must point to the canonical name, not an alias. X A Y: no PTR record X has an IP address Y, but there is no PTR record to map the IP address Y back to a hostname (usually X). Many Internet servers (such as anonymous FTP servers) will not talk to addresses that don't have PTR records. warning: X has only one authoritative nameserver Zones should have more than one authoritative name- server, in case one is down or unreachable. Preferably one should be off-site. Make sure the parent and child nameservers list all authoritative nameservers for a zone in the NS list. X: invalid character(s) in name Allowable characters in a domain name are the ASCII letters a through Z the digits 0 through 9, and the "-" character. A "." may be used only as a domain separa- tor. Using non-standard characters can cause unexpected software problems. X: domain occurred twice, forgot trailing '.'? A sanity check which looks for "dom.ain.dom.ain." in a name. This is often caused by forgetting to put a trailing '.' on the end of a name. X A Y: points to Z X has Y for an IP address, but the PTR record associ- ated with Y returns "Z" as the name associated with that host. This is not necessarily an error (for exam- ple if you have an A record for your domain name), but may be an indication of an A record which points to the wrong host, or a PTR record that points to the wrong host. You will get this error if you are trying to alias one host to another with an A record. You should use a CNAME instead. X NS Y: lame NS delegation Y is a listed nameserver for zone X, but Y is not returning authoritative data for zone X. This is usu- ally the result of a lack of communication on the part of the respective hostmasters. Lame delegations are not fatal problems except in severe cases, they just tend to create significant increases in DNS traffic. NS records for the parent and child domains should be consistent, and each server listed in the NS record MUST be able to answer with authoritative data, by being explicitly configured as a primary or secondary for the zone. X NS Y: nameserver error (lame?) These are any errors returned while contacting other nameservers (like connection refused or timeout) This could mean a lame delegation (the host is not running a nameserver or is misconfigured), or simply that the nameserver is temporarily unreachable. Cannot check X: no available nameservers! The X zone was delegated with NS records but all the nameservers for the zone are either unavailable or say that they have no data for the zone (are lame). Verify that the X zone isn't a typo, and if not make sure that all the listed nameservers are configured to answer with data for the zone. SEE ALSO RFC 1034 - "DOMAIN NAMES - CONCEPTS AND FACILITIES" RFC 1035 - "DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION" RFC 1123 - "Requirements for Internet Hosts -- Application and Support" Paul Albitz, Cricket Liu: "DNS and BIND" O'Reilly & Associates. RFC 1912 - "Common DNS Operational and Configuration Errors" http://www.dns.net/dnsrd/ - DNS Resources Directory dnswalk-2.0.2/sendreports0000755000175000017500000000161506371400005014106 0ustar pabspabs#!/bin/sh DATE=`date +%m/%y` for file in *; do hostmaster=`echo $file | sed 's/\./@/'` echo Sending report to "$hostmaster" ( cat </tmp/reports/$file sleep 1 done