home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / bind / bind-4.001 / bind-4~ / bind-4.9.3-BETA9 / contrib / dnsparse / dns2hosts < prev    next >
Text File  |  1990-09-11  |  9KB  |  256 lines

  1. #!/usr/bin/perl
  2. #
  3. # $Id: dns2hosts,v 2.0 90/09/11 11:07:27 hakanson Rel $
  4. #
  5. # Convert DNS master (RFC-1035) files to /etc/hosts format.
  6. #   Marion Hakanson (hakanson@cse.ogi.edu)
  7. #   Oregon Graduate Institute of Science and Technology
  8. #
  9. # Copyright (c) 1990, Marion Hakanson.
  10. #
  11. # You may distribute under the terms of the GNU General Public License
  12. # as specified in the README file that comes with the dnsparse kit.
  13. #
  14. # Other than "-d defdom" (to specify a default domain different from that
  15. # found in /etc/resolv.conf), command line args are DNS master file names,
  16. # as described for the dns_init() subroutine in dnsparse.pl.  The output
  17. # is printed to the standard output stream.
  18. #
  19. # This Perl program looks at the A and CNAME records encountered in the
  20. # DNS master files, and produces an /etc/hosts file which includes the
  21. # same host-to-address, address-to-host, and alias-to-host mappings.
  22. # Note that some such mappings are necessarily dependent on the order in
  23. # which they are encountered in the DNS master files.  The DNS system
  24. # is not sensitive to the order, but /etc/hosts files are, thus one
  25. # should take care that the command line arguments are presented in
  26. # the same order from one invocation to the next, if one expects the
  27. # two resulting output files to be comparable.
  28. #
  29. # A large part of the complication of this program is due to the notion
  30. # of the "default domain" that the BIND implementation of a DNS resolver
  31. # provides.  Namely, this allows a user to type a short alias and have
  32. # it match to a fully qualified domain name (FQDN) somewhere in the
  33. # machine's default domain.  E.g. given "admin" and a default domain
  34. # of "cse.ogi.edu", the resolver will try "admin.cse.ogi.edu" -- if no
  35. # match is found, it will try "admin.ogi.edu" (but it will not try
  36. # just the first-level domain, "admin.edu").
  37. #
  38. # Thus, the aliases and canonical names are set up in the output file
  39. # to mimic the behavior of a system using the BIND resolver.  Among
  40. # other things, this means that host numbers will always be resolved
  41. # to the FQDN of the host.  Instead of using PTR records to provide
  42. # the number-to-name mappings, this program assumes that the PTR records
  43. # would be automatically generated from the A records.  It further assumes
  44. # that a host is considered to have a single, unique FQDN, and that all
  45. # of its addresses (interfaces) will resolve back to that FQDN.  To my
  46. # knowledge, this is the only area where the output hosts file may not
  47. # quite mimic the behavior of the BIND resolver.  I would be willing to
  48. # consider a design change if demand warrants it.
  49.  
  50. do 'getopts.pl'; die "$@, aborted" if $@;
  51. do 'dnsparse.pl'; die "$@, aborted" if $@;
  52.  
  53. do Getopts('d:');
  54.  
  55. # Get default domain
  56. if ( defined($opt_d) ) {
  57.   $defdom = $opt_d;
  58. } elsif ( open(F, '</etc/resolv.conf') ) {
  59.   while ( <F> ) {
  60.     $defdom = $1 if ( /\s*domain\s+([^\s]+)/ );
  61.   }
  62.   close(F);
  63. }
  64.  
  65. # Set up domains the resolver would try
  66. if ( defined($defdom) ) {
  67.   $defdom =~ s/^\.//;    # strip leading dot
  68.   $defdom = do dns_makefqdn($defdom,'');
  69.  
  70.   @domparts = split(/\./,$defdom);    # escaped dots?
  71.   while ( $#domparts > 0 ) {
  72.     push(@defdoms, join('.',@domparts));
  73.     shift(@domparts);
  74.   }
  75. }
  76.  
  77. # Parse the dns db file, collecting names & addrs.
  78. do dns_init(@ARGV);
  79.  
  80. open(OFILE, ">&STDOUT") || die "Cannot dupe 'STDOUT', aborted";
  81.  
  82. # Treat loopback address specially, since the DNS is usually set
  83. # up to resolve loopback to "localhost".
  84. $hostsbyaddr{'127.0.0.1'} = 'localhost';
  85. push(@addrs,'127.0.0.1');
  86.  
  87. rr: while ( (@rr = do dns_getrr()) && @rr ) {
  88.   ($domain, $ttl, $class, $type, @data) = @rr;
  89.  
  90.   next rr if ( $class ne 'IN' );
  91.  
  92.   case: {
  93.     if ( $type eq 'A' ) {
  94.       $list = '';
  95.       if ( defined($hostsbyaddr{$data[0]}) ) {
  96.         $list = $hostsbyaddr{$data[0]} . $dns'delim;
  97.       } else {
  98.         push(@addrs,$data[0]);
  99.       }
  100.       $list .= $domain;
  101.       $hostsbyaddr{$data[0]} = $list;
  102.       $fqdnseen{$domain}++;
  103.       last case;
  104.     } elsif ( $type eq 'CNAME' ) {
  105.       $list = '';
  106.       if ( defined($cnamesbyhost{$data[0]}) ) {
  107.         $list = $cnamesbyhost{$data[0]} . $dns'delim;
  108.       }
  109.       $list .= $domain;
  110.       $cnamesbyhost{$data[0]} = $list;
  111.       $fqdnseen{$domain}++;
  112.       last case;
  113.     }
  114.   }
  115. }
  116.  
  117. # Go through the names encountered, building abbreviations,
  118. # and attaching them to their fully-qualified forms.
  119. while ( ($fqdn,$cnt) = each %fqdnseen ) {
  120.   #print STDERR "$fqdn seen $cnt times\n";
  121.   foreach $truncdom (@defdoms) {
  122.     $abbrev = $fqdn;
  123.     # don't generate abbrev's which wouldn't resolve
  124.     if ( $abbrev =~ s/\.$truncdom// ) {
  125.       # now we mimic what the resolver would do
  126.       foreach $dom (@defdoms) {
  127.         if ( defined($fqdnseen{"$abbrev.$dom"}) ) {
  128.           $abbrevsbyhost{"$abbrev.$dom"} .= $abbrev . $dns'delim;
  129.           #print STDERR "$abbrev -> $abbrev.$dom\n";
  130.           # stop with the first one
  131.           last;
  132.         }
  133.       }
  134.     }
  135.   }
  136. }
  137.  
  138. # for debugging
  139. #while ( ($key,$val) = each(%abbrevsbyhost) ) {
  140. #  print STDERR "|$key";
  141. #  @vals = split(/$dns'delim/,$val);
  142. #  foreach $val (@vals) {
  143. #    print STDERR "|$val";
  144. #  }
  145. #  print STDERR "|\n";
  146. #}
  147.  
  148. # Write out the hosts file.
  149. # First write out some commentary about the input source, etc.
  150. $datefmt = '%02d/%02d/%02d %02d:%02d:%02d';
  151. ($sec,$min,$hour,$mday,$mon,$year,@rest) = localtime();
  152. $mon++;    # 0 == January
  153. $date = sprintf($datefmt, $year, $mon, $mday, $hour, $min, $sec);
  154.  
  155. chop($host = `hostname`);
  156. print OFILE "#\n";
  157. print OFILE "# Host table (/etc/hosts)\n";
  158. print OFILE "#\n";
  159. print OFILE "# Created on host '$host' at $date\n";
  160. print OFILE "#\n";
  161. print OFILE "# Abbreviations set up for default domain '$defdom'\n";
  162. print OFILE "#\n";
  163. print OFILE "#   THIS TABLE WAS GENERATED AUTOMATICALLY.\n";
  164. print OFILE "#   ANY CHANGES OR ADDITIONS TO IT WILL BE\n";
  165. print OFILE "#   LOST WHEN THE NEXT UPDATE TAKES PLACE.\n";
  166. print OFILE "#\n";
  167. print OFILE "# Built from the following DNS master files:\n";
  168. print OFILE "#\n";
  169. print OFILE "# ModTime\t\tFile\n";
  170. print OFILE "#\tOrigin\n";
  171.  
  172. while ( $#ARGV >= $[ ) {
  173.     ($file,$origin) = do dns_commasplit(shift(@ARGV));
  174.     $origin = '.' unless ( $origin );    # root
  175.     if ( $file eq '' || $file eq '-' ) {
  176.         $file eq 'Standard Input';
  177.         @ARGV = ();    # STDIN is last
  178.         $date = 'See Above';
  179.     } else {
  180.         if ( -r $file ) {
  181.             ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  182.                 $atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
  183.             ($sec,$min,$hour,$mday,$mon,$year,@rest) = localtime($mtime);
  184.             $mon++;    # 0 == January
  185.             $date = sprintf($datefmt, $year, $mon, $mday, $hour, $min, $sec);
  186.         } else {
  187.             $date = "Not Found";
  188.             $origin = $!;    # the error message
  189.         }
  190.     }
  191.     print OFILE "# $date\t$file\n";
  192.     print OFILE "#\t$origin\n";
  193. }
  194. print OFILE "#\n";
  195. print OFILE "#\n";
  196.  
  197. # Build up an output record and then write it out using a
  198. # format which may break a long record into multiple lines,
  199. # all starting with the same address and canonical name.
  200. format OFILE =
  201. @<<<<<<<<<<<<<<  ~^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  202. $addr,              $names
  203. .
  204.  
  205. $: = ' ';    # OK to break $names on a blank
  206.  
  207. foreach $addr ( @addrs ) {
  208.   @hosts = split(/$dns'delim/, $hostsbyaddr{$addr});
  209.   %nameseen = ();
  210.   $names = '';
  211.   $canon = $hosts[0];        # save the first one
  212.  
  213.   foreach $host ( @hosts ) {
  214.     unless ( defined($nameseen{$host}) ) {
  215.       $nameseen{$host} = 1;
  216.       $names .= " $host";
  217.       if ( defined($abbrevsbyhost{$host}) ) {
  218.         @abbrevs = split(/$dns'delim/, $abbrevsbyhost{$host});
  219.         foreach $abbrev ( @abbrevs ) {
  220.           unless ( defined($nameseen{$abbrev}) ) {
  221.             $nameseen{$abbrev} = 1;
  222.             $names .= " $abbrev";
  223.           }
  224.         }
  225.       }
  226.     }
  227.  
  228.     if ( defined($cnamesbyhost{$host}) ) {
  229.       @aliases = split(/$dns'delim/, $cnamesbyhost{$host});
  230.       foreach $alias ( @aliases ) {
  231.         unless ( defined($nameseen{$alias}) ) {
  232.           $nameseen{$alias} = 1;
  233.           $names .= " $alias";
  234.           if ( defined($abbrevsbyhost{$alias}) ) {
  235.             @abbrevs = split(/$dns'delim/, $abbrevsbyhost{$alias});
  236.             foreach $abbrev ( @abbrevs ) {
  237.               unless ( defined($nameseen{$abbrev}) ) {
  238.                 $nameseen{$abbrev} = 1;
  239.                 $names .= " $abbrev";
  240.               }
  241.             }
  242.           }
  243.         }
  244.       }
  245.     }
  246.   }
  247.   $names =~ s/^ $canon *//;    # we'll put it back below
  248.   do {
  249.     #print STDERR "|$names|\n";
  250.     $names = "$canon $names";
  251.     write(OFILE);    # has side effect of shortening $names
  252.   } while ( $names );
  253. }
  254.  
  255. exit(0);
  256.