mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 19:32:31 +00:00 
			
		
		
		
	git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@1561 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			1036 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1036 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/perl
 | |
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| #This is ported forward from xCAT 1.3
 | |
| #TODO: A lot of stuff was handled by the script portion of makedns, notably:
 | |
| # db.cache
 | |
| # forwarders
 | |
| # chroot
 | |
| # dnsallowq
 | |
| # mucking with sysconfig
 | |
| package xCAT_plugin::bind;
 | |
| use Sys::Hostname;
 | |
| use Cwd;
 | |
| use xCAT::Table;
 | |
| use Data::Dumper;
 | |
| 
 | |
| use Sys::Syslog;
 | |
| sub handled_commands {
 | |
|     return {"makedns" => "bind"};
 | |
| }
 | |
| 
 | |
| #NAME
 | |
| #
 | |
| #    h2n - Translate host table to name server file format
 | |
| #    $Date: 1999/08/08 17:17:56 $  $Revision: 8.2 $
 | |
| #
 | |
| #SYNOPSIS
 | |
| #
 | |
| #    h2n -d DOMAIN -n NET [options]
 | |
| 
 | |
| # Various defaults
 | |
| my $Host;
 | |
| my $doaliases = 1;
 | |
| my $domx = 1;
 | |
| my $dowks = 0;
 | |
| my $dotxt = 0;
 | |
| my $dontdodomains = 0;
 | |
| my $Bootfile = "/etc/named.conf";
 | |
| my $DBDir = "/var/named/";
 | |
| my $Domain = "";
 | |
| my $Hostfile = "/etc/hosts";
 | |
| my $Commentfile = "";
 | |
| my $Commentfileread = 0;
 | |
| my $User = "root";
 | |
| my $RespHost = "";
 | |
| my $RespUser = "";
 | |
| my $DefSerial = 1;
 | |
| my $DefRefresh = 10800;
 | |
| my $DefRetry = 3600;
 | |
| my $DefExpire = 604800;
 | |
| my $DefTtl = 86400;
 | |
| my $UseDefSOAValues = 0;
 | |
| my $DefMxWeight = 10;
 | |
| my $Defsubnetmask = "";
 | |
| my $ForceSerial = -1;
 | |
| my $UseDateInSerial = 1;
 | |
| my $DateSerial = 0;
 | |
| my $Version = 8;
 | |
| my $request;
 | |
| my $callback;
 | |
| my @forwarders;
 | |
| sub process_request {
 | |
|     $request = shift;
 | |
|     $callback = shift;
 | |
|     $Host = hostname;
 | |
|     $Host =~ s/\..*//;       		
 | |
|     my $sitetab = xCAT::Table->new('site');
 | |
|     unless ($sitetab) {
 | |
|         $callback->({error=>["No site table found"],errorcode=>[1]});
 | |
|         return;
 | |
|     }
 | |
|     my @args = @{$request->{arg}};
 | |
|     (my $fent) = $sitetab->getAttribs({key=>'forwarders'},'value');
 | |
|     if ($fent and defined $fent->{value}) {
 | |
|         @forwarders = split /[,:;]/,$fent->{value};
 | |
|     }
 | |
|     unless (grep /^-d$/,@args) {
 | |
|         (my $dent) = $sitetab->getAttribs({key=>'domain'},'value');
 | |
|         if ($dent and $dent->{value}) {
 | |
|             push @args,"-d";
 | |
|             $dent->{value} =~ s/\.$//;
 | |
|             push @args,$dent->{value};
 | |
|         }
 | |
|     }
 | |
|     unless (grep /^-s$/,@args) {
 | |
|         push @args,"-s";
 | |
|         push @args,$Host;
 | |
|     }
 | |
|     unless (grep /^-n$/,@args) {
 | |
|         my $nettab = xCAT::Table->new('networks');
 | |
| 	unless ($nettab) {
 | |
| 	  $callback->({error=>"Unable to open networks table, has makenetworks been run?"});
 | |
| 	  return;
 | |
| 	}
 | |
|         foreach (@{$nettab->getAllEntries()}) {
 | |
|             push @args,"-n";
 | |
|             push @args,$_->{net}.":".$_->{mask}
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
| push(@bootmsgs_v4, "primary\t0.0.127.IN-ADDR.ARPA db.127.0.0\n");
 | |
| push(@bootmsgs_v8, 
 | |
|      qq|zone "0.0.127.IN-ADDR.ARPA" in {\n\ttype master;\n\tfile "db.127.0.0";\n\tnotify no;\n};\n\n|);
 | |
| 
 | |
| &PARSEARGS(@args);
 | |
| &FIXUP;
 | |
| 
 | |
| open(HOSTS, $Hostfile) || die "can not open $Hostfile";
 | |
| 
 | |
| LINE: while(<HOSTS>){
 | |
|     next if /^[ \t]*#/;  # skip comment lines
 | |
|     next if /^$/;  	 # skip empty lines
 | |
|     chop;                # remove the trailing newline
 | |
|     tr/A-Z/a-z/;	 # translate to lower case 
 | |
| 
 | |
|     ($data,$comment) = split('#', $_, 2);
 | |
|     ($addr, $names) = split(/[ 	]+/, $data, 2);
 | |
|     if ($names =~ /^[ \t]*$/) {
 | |
| 	    #$callback->({data=>["Bad line in hosts file ignored '$_'"]});
 | |
| 	    next LINE;
 | |
|     }
 | |
|     $addr =~ s/^[    ]*//;
 | |
|     $addr =~ s/[    ]*$//;
 | |
|     if ($addr !~ /^\d+\.\d+\.\d+\.\d+$/) {
 | |
|        $callback->({data=>["Ignoring $addr (not a valid IPv4 address)"]});
 | |
|        next LINE;
 | |
|     }
 | |
| 
 | |
|     # Match -e args
 | |
|     foreach $netpat (@elimpats){
 | |
| 	    next LINE if (/[.\s]$netpat/);
 | |
|     }
 | |
| 
 | |
|     # Process -c args
 | |
|     foreach $netpat (@cpats){
 | |
| 	if (/\.$netpat/) {
 | |
| 	    ($canonical, $aliases) = split(' ', $names, 2);
 | |
| 	    $canonical =~ s/\.$netpat//; 
 | |
| 	    if($Cnames{$canonical} != 1){
 | |
| 	        printf DOMAIN "%-20s IN  CNAME %s.%s.\n", 
 | |
| 		       $canonical, $canonical, $cpatrel{$netpat};
 | |
| 		$Cnames{$canonical} = 1;
 | |
| 	    }
 | |
| 	    next LINE;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     # Check that the address is in the address list.
 | |
|     $match = 'none';
 | |
|     foreach $netpat (@Netpatterns){
 | |
| 	$match = $netpat, last if ($addr =~ /^$netpat\./ or $addr =~ /^$netpat$/);
 | |
|     }
 | |
|     next if ($match eq 'none');
 | |
| 
 | |
|     ($canonical, $aliases) = split(' ', $names, 2);  # separate out aliases
 | |
|     next if ($dontdodomains && $canonical =~ /\./);  # skip domain names
 | |
|     $canonical =~ s/$Domainpattern//;     # strip off domain if there is one
 | |
|     $Hosts{$canonical} .= $addr . " ";    # index addresses by canonical name
 | |
|     $Aliases{$addr} .= $aliases . " ";    # index aliases by address
 | |
|     $Comments{"$canonical-$addr"} = $comment;
 | |
| 
 | |
|     # Print PTR records
 | |
|     $file = $Netfiles{$match};
 | |
|     printf $file "%-30s\tIN  PTR   %s.%s.\n", 
 | |
| 	   &REVERSE($addr), $canonical, $Domain;
 | |
| }
 | |
| 
 | |
| #
 | |
| # Go through the list of canonical names.
 | |
| # If there is more than 1 address associated with the
 | |
| # name, it is a multi-homed host.  For each address 
 | |
| # look up the aliases since the aliases are associated 
 | |
| # with the address, not the canonical name.
 | |
| #
 | |
| foreach $canonical (keys %Hosts){
 | |
|     @addrs = split(' ', $Hosts{$canonical});
 | |
|     $numaddrs = $#addrs + 1;
 | |
|     foreach $addr (@addrs) {
 | |
| 	#
 | |
| 	# Print address record for canonical name.
 | |
| 	#
 | |
| 	if($Cnames{$canonical} != 1){
 | |
| 	    printf DOMAIN "%-20s IN  A     %s\n", $canonical, $addr;
 | |
| 	} else {
 | |
| 	   syslog("local1|err","$canonical - can't create A record because CNAME exists for name.\n");
 | |
| 	}
 | |
| 	#
 | |
| 	# Print cname or address records for each alias.
 | |
| 	# If this is a multi-homed host, print an address
 | |
| 	# record for each alias.  If this is a single address
 | |
| 	# host, print a cname record.
 | |
| 	#
 | |
| 	if ($doaliases) {
 | |
| 	    @aliases = split(' ', $Aliases{$addr});
 | |
| 	    foreach $alias (@aliases){
 | |
| 		#
 | |
| 		# Skip over the alias if the alias and canonical
 | |
| 		# name only differ in that one of them has the
 | |
| 		# domain appended to it.
 | |
| 		#
 | |
|     		next if ($dontdodomains && $alias =~ /\./); # skip domain names
 | |
| 		$alias =~ s/$Domainpattern//;
 | |
| 		if($alias eq $canonical){
 | |
| 		    next;
 | |
| 		}
 | |
| 
 | |
|                 $aliasforallnames = 0;
 | |
| 		if($numaddrs > 1){
 | |
|                     #
 | |
|                     # If alias exists for *all* addresses of this host, we
 | |
|                     # can use a CNAME instead of an address record.
 | |
|                     #
 | |
|                     $aliasforallnames = 1;
 | |
|                     $xalias = $alias . " ";  # every alias ends with blank
 | |
|                     @xaddrs = split(' ', $Hosts{$canonical});
 | |
|                     foreach $xaddr (@xaddrs) {
 | |
|                         if(!($Aliases{$xaddr} =~ /\b$xalias/)) {
 | |
|                             $aliasforallnames = 0;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
| 		if(($numaddrs > 1) && !$aliasforallnames){
 | |
| 		    printf DOMAIN "%-20s IN  A     %s\n", $alias, $addr;
 | |
| 		} else {
 | |
| 		    #
 | |
| 		    # Flag aliases that have already been used
 | |
| 		    # in CNAME records or have A records.
 | |
| 		    #
 | |
| 		    if(($Cnames{$alias} != 1) && (!$Hosts{$alias})){
 | |
| 			printf DOMAIN "%-20s IN  CNAME %s.%s.\n", 
 | |
| 			       $alias, $canonical, $Domain;
 | |
| 			$Cnames{$alias} = 1;
 | |
| 		    } else {
 | |
| 			syslog "local1|err","$alias - CNAME or A exists already; alias ignored\n";
 | |
| 		    }
 | |
| 		}
 | |
| 
 | |
|                 if($aliasforallnames){
 | |
|                     #
 | |
|                     # Since a CNAME record was created, remove this
 | |
|                     # name from the alias list so we don't encounter
 | |
|                     # it again for the next address of this host.
 | |
|                     #
 | |
|                     $xalias = $alias . " ";  # every alias ends with blank
 | |
|                     @xaddrs = split(' ', $Hosts{$canonical});
 | |
|                     foreach $xaddr (@xaddrs) {
 | |
|                         $Aliases{$xaddr} =~ s/\b$xalias//;
 | |
|                     }
 | |
|                 }
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     if ($domx) {
 | |
| 	&MX($canonical, @addrs);
 | |
|     }
 | |
|     if ($dotxt) {
 | |
| 	&TXT($canonical, @addrs);
 | |
|     }
 | |
|     if ($Commentfile ne "") {
 | |
| 	&DO_COMMENTS($canonical, @addrs);
 | |
|     }
 | |
| }
 | |
| 
 | |
| # Deal with spcl's
 | |
| if (-r "spcl.$Domainfile") {
 | |
|     print DOMAIN "\$INCLUDE spcl.$Domainfile\n";
 | |
| }
 | |
| foreach $n (@Networks) {
 | |
|     if (-r "spcl.$n") {
 | |
| 	$file = "DB.$n";
 | |
| 	print $file "\$INCLUDE spcl.$n\n";
 | |
|     }
 | |
| }
 | |
| 
 | |
| # generate boot.* files
 | |
| &GEN_BOOT;
 | |
| 
 | |
| }
 | |
| 
 | |
| #
 | |
| # Generate resource record data for
 | |
| # strings from the commment field that
 | |
| # are found in the comment file (-C).
 | |
| #
 | |
| sub DO_COMMENTS {
 | |
|     local($canonical, @addrs) = @_;
 | |
|     local(*F, @c, $c, $a, $comments);
 | |
|     
 | |
|     if (!$Commentfileread) {
 | |
| 	open(F, $Commentfile) || die "Unable to open file $Commentfile: $!";
 | |
| 	$Commentfileread++;
 | |
| 	while (<F>) {
 | |
| 	    chop;
 | |
| 	    ($key, $c) = split(':', $_, 2);
 | |
| 	    $CommentRRs{$key} = $c;
 | |
| 	}
 | |
| 	close(F);
 | |
|     }
 | |
|     
 | |
|     foreach $a (@addrs) {
 | |
| 	$key = "$canonical-$a";
 | |
| 	$comments .= " $Comments{$key}";
 | |
|     }
 | |
| 
 | |
|     @c = split(' ', $comments);
 | |
|     foreach $c (@c) {
 | |
| 	if($CommentRRs{$c}){
 | |
| 	    printf DOMAIN "%-20s %s\n", $canonical, $CommentRRs{$c};
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #
 | |
| # Generate MX record data
 | |
| #
 | |
| sub MX {
 | |
|     local($canonical, @addrs) = @_;
 | |
|     local($first, $a, $key, $comments);
 | |
| 
 | |
|     if($Cnames{$canonical}){
 | |
| 	syslog "local1|err","$canonical - can't create MX record because CNAME exists for name.\n";
 | |
| 	return;
 | |
|     }
 | |
|     $first = 1;
 | |
| 
 | |
|     foreach $a (@addrs) {
 | |
| 	$key = "$canonical-$a";
 | |
| 	$comments .= " $Comments{$key}";
 | |
|     }
 | |
|     
 | |
|     if ($comments !~ /\[no smtp\]/) {
 | |
|         # Add WKS if requested
 | |
|         if ($dowks) {
 | |
| 	    foreach $a (@addrs) {
 | |
| 	        printf DOMAIN "%-20s IN  WKS   %s TCP SMTP\n", $canonical, $a;
 | |
| 	    }
 | |
|         }
 | |
| 	printf DOMAIN "%-20s IN  MX    %s %s.%s.\n", $canonical, $DefMxWeight, 
 | |
| 	       $canonical, $Domain; 
 | |
| 	$first = 0;
 | |
|     }
 | |
|     if ($#Mx >= 0) {
 | |
| 	foreach $a (@Mx) {
 | |
| 	    if ($first) {
 | |
| 		printf DOMAIN "%-20s IN  MX    %s\n", $canonical, $a; 
 | |
| 		$first = 0;
 | |
| 	    } else {
 | |
| 		printf DOMAIN "%-20s IN  MX    %s\n", "", $a; 
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| #
 | |
| # Generate TXT record data
 | |
| #
 | |
| sub TXT {
 | |
|     local($canonical, @addrs) = @_;
 | |
|     local($a, $key, $comments);
 | |
| 
 | |
|     foreach $a (@addrs) {
 | |
| 	$key = "$canonical-$a";
 | |
| 	$comments .= " $Comments{$key}";
 | |
|     }
 | |
|     $comments =~ s/\[no smtp\]//g;
 | |
|     $comments =~ s/^\s*//;
 | |
|     $comments =~ s/\s*$//;
 | |
|     
 | |
|     if ($comments ne "") {
 | |
| 	printf DOMAIN "%s IN  TXT   \"%s\"\n", $canonical, $comments;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #
 | |
| # Create the SOA record at the beginning of the file
 | |
| #
 | |
| sub MAKE_SOA {
 | |
|     local($fname, $file) = @_;
 | |
|     local($s);
 | |
| 
 | |
|     if ( -s $fname) {
 | |
| 	open($file, "$fname") || die "Unable to open $fname: $!";
 | |
| 	$_ = <$file>;
 | |
| 	chop;
 | |
| 	if (/\($/) {
 | |
| 	    if (! $soa_warned) {
 | |
| 		syslog "local1|err","Converting SOA format to new style.\n";
 | |
| 		$soa_warned++;
 | |
| 	    }
 | |
| 	    if ($ForceSerial > 0) {
 | |
| 		$Serial = $ForceSerial;
 | |
| 	    } else {
 | |
| 		($Serial, $junk) = split(' ', <$file>, 2);
 | |
| 		$Serial++;
 | |
|                 if($UseDateInSerial && ($DateSerial > $Serial)){
 | |
|                     $Serial = $DateSerial;
 | |
|                 }
 | |
| 	    }
 | |
| 	    ($Refresh, $junk) = split(' ', <$file>, 2);
 | |
| 	    ($Retry, $junk) = split(' ', <$file>, 2);
 | |
| 	    ($Expire, $junk) = split(' ', <$file>, 2);
 | |
| 	    ($Ttl, $junk) = split(' ', <$file>, 2);
 | |
| 	} else {
 | |
|         if (/TTL/) {
 | |
|             $_ = <$file>;
 | |
|         }
 | |
| 	    split(' ');
 | |
| 	    if ($#_ == 11) {
 | |
| 		if ($ForceSerial > 0) {
 | |
| 		    $Serial = $ForceSerial;
 | |
| 		} else {
 | |
| 		    $Serial = ++@_[6];
 | |
|                     if($UseDateInSerial && ($DateSerial > $Serial)){
 | |
|                         $Serial = $DateSerial;
 | |
|                     }
 | |
| 		}
 | |
| 		$Refresh = @_[7];
 | |
| 		$Retry = @_[8];
 | |
| 		$Expire = @_[9];
 | |
| 		$Ttl = @_[10];
 | |
| 	    } else {
 | |
| 		syslog "local1|err","Improper format SOA in $fname.\n";
 | |
| 		syslog "local1|err","I give up ... sorry.\n";
 | |
| 		exit(1);
 | |
| 	    }
 | |
| 	}
 | |
|         if($UseDefSOAValues){
 | |
| 	    $Refresh = $DefRefresh;
 | |
| 	    $Retry = $DefRetry;
 | |
| 	    $Expire = $DefExpire;
 | |
| 	    $Ttl = $DefTtl;
 | |
|         }
 | |
| 	close($file);
 | |
|     } else {
 | |
| 	if ($ForceSerial > 0) {
 | |
| 	    $Serial = $ForceSerial;
 | |
| 	} else {
 | |
| 	    $Serial = $DefSerial;
 | |
|             if($UseDateInSerial && ($DateSerial > $Serial)){
 | |
|                 $Serial = $DateSerial;
 | |
|             }
 | |
| 	}
 | |
| 	$Refresh = $DefRefresh;
 | |
| 	$Retry = $DefRetry;
 | |
| 	$Expire = $DefExpire;
 | |
| 	$Ttl = $DefTtl;
 | |
| 	close($file);
 | |
|     }
 | |
| 
 | |
|     open($file, "> $fname") || die "Unable to open $fname: $!";
 | |
| 
 | |
|     print $file '$TTL 86400'."\n";
 | |
|     print $file "\@ IN  SOA $RespHost $RespUser ";
 | |
|     print $file "( $Serial $Refresh $Retry $Expire $Ttl )\n";
 | |
|     foreach $s (@Servers) {
 | |
| 	print $file "  IN  NS  $s\n";
 | |
|     }
 | |
|     print $file "\n";
 | |
| }
 | |
| 
 | |
| 
 | |
| #
 | |
| # Reverse the octets of an IP address and append
 | |
| # in-addr.arpa.
 | |
| #
 | |
| sub REVERSE {
 | |
|     join('.', reverse(split('\.', $_[0]))) . '.IN-ADDR.ARPA.';
 | |
| }
 | |
| 
 | |
| 
 | |
| #
 | |
| # Establish what we will be using for SOA records
 | |
| #
 | |
| sub FIXUP {
 | |
|     local($s);
 | |
| 
 | |
|     if ($Host =~ /\./) {
 | |
| 	$RespHost = "$Host.";
 | |
|     } else {
 | |
| 	$RespHost = "$Host.$Domain.";
 | |
|     }
 | |
|     $RespHost =~ s/\.\././g;
 | |
| 
 | |
|     if ($User =~ /@/) {				# -u user@...
 | |
| 	if ($User =~ /\./) {
 | |
| 	    $RespUser = "$User.";		# -u user@terminator.movie.edu
 | |
| 	} else {
 | |
| 	    $RespUser = "$User.$Domain."; 	# -u user@terminator
 | |
| 	}
 | |
| 	$RespUser =~ s/@/./;
 | |
|     } elsif ($User =~ /\./) {
 | |
| 	$RespUser = "$User.";			# -u user.terminator.movie.edu
 | |
|     } else {
 | |
| 	$RespUser = "$User.$RespHost";		# -u user
 | |
|     }
 | |
|     $RespUser =~ s/\.\././g;			# Strip any ".."'s to "."
 | |
| 
 | |
|     # Clean up nameservers
 | |
|     if (!defined(@Servers)) {
 | |
| 	syslog "local1|err","No -s option specified.  Assuming \"-s $Host.$Domain\"\n";
 | |
| 	push(@Servers, "$Host.$Domain.");
 | |
|     } else {
 | |
| 	foreach $s (@Servers) {
 | |
| 	    if ($s !~ /\./) {
 | |
| 		$s .= ".$Domain";
 | |
| 	    }
 | |
| 	    if ($s !~ /\.$/) {
 | |
| 		$s .= ".";
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     # Clean up MX hosts
 | |
|     foreach $s (@Mx) {
 | |
| 	$s =~ s/:/ /;
 | |
| 	if ($s !~ /\./) {
 | |
| 	    $s .= ".$Domain";
 | |
| 	}
 | |
| 	if ($s !~ /\.$/) {
 | |
| 	    $s .= ".";
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     # Now open boot file and print saved data
 | |
|     open(BOOT, "> $Bootfile")  || die "can not open $Bootfile";
 | |
| 
 | |
|     #
 | |
|     # Write either the version 4 boot file directives or the 
 | |
|     # version 8 boot file directives.
 | |
|     #
 | |
| 
 | |
|     if($Version == 4) {
 | |
|         print BOOT "\ndirectory $DBDir\n";
 | |
|         foreach $line (@bootmsgs_v4) {
 | |
| 	    print BOOT $line;
 | |
|         }
 | |
|         print BOOT "cache\t. db.cache\n";
 | |
|         if (-r "spcl.boot") {
 | |
|             print BOOT "include\tspcl.boot\n";
 | |
|         }
 | |
|     } else {
 | |
|         print BOOT 
 | |
|               qq|\noptions {\n\tdirectory "$DBDir";\n|;
 | |
|          if (@forwarders) {
 | |
|             print BOOT qq|\tforwarders {\n|;
 | |
|             foreach (@forwarders) {
 | |
|                 print BOOT qq|\t\t$_;\n|;
 | |
|             }
 | |
|             print BOOT qq|\t};\n|;
 | |
|          }
 | |
|         if (-r "spcl.options") {
 | |
|             print BOOT "\t# These options came from the file spcl.options\n";
 | |
|             #
 | |
|             # Copy the options in since "include" can't be used
 | |
|             # within a statement.
 | |
|             #
 | |
|             open(OPTIONS, "<spcl.options") || die "Can't open spcl.options\n";
 | |
|             while(<OPTIONS>)
 | |
|             {
 | |
|                 print BOOT;
 | |
|             }
 | |
|             close(OPTIONS);
 | |
|         }
 | |
|         print BOOT qq|};\n\n|;
 | |
|         foreach $line (@bootmsgs_v8) {
 | |
| 	    print BOOT $line;
 | |
|         }
 | |
|         unless (@forwarders) {
 | |
|             print BOOT qq|zone "." in {\n\ttype hint;\n\tfile "db.cache";\n};\n\n|;
 | |
|         }
 | |
|         if (-r "spcl.boot") {
 | |
|             print BOOT qq|include "spcl.boot";\n\n|;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Go ahead and start creating files and making SOA's
 | |
|     foreach $i (@makesoa) {
 | |
| 	($x1, $x2) = split(' ', $i);
 | |
| 	&MAKE_SOA($x1, $x2);
 | |
|     }
 | |
|     printf DOMAIN "%-20s IN  A     127.0.0.1\n", "localhost";
 | |
|     
 | |
|     $file = "DB.127.0.0.1";
 | |
|     &MAKE_SOA($DBDir."db.127.0.0", $file);
 | |
|     my $nothing;
 | |
|     open($nothing,">>",$DBDir."db.cache");
 | |
|     close($nothing);
 | |
|     printf $file "%-30s\tIN  PTR   localhost.\n", &REVERSE("127.0.0.1");
 | |
|     close($file);
 | |
| }
 | |
| 
 | |
| 
 | |
| sub PARSEARGS {
 | |
|     local(@args) = @_;
 | |
|     local($i, $net, $subnetmask, $option, $tmp1);
 | |
|     local(*F, $file, @newargs, @targs);
 | |
|     local($sec,$min,$hour,$mday,$mon,$year,$rest);
 | |
|     ($sec,$min,$hour,$mday,$mon,$year,$rest) = localtime(time);
 | |
|     $DateSerial = ($mday * 100) + 
 | |
|                   (($mon + 1) * 10000) + 
 | |
|                   (($year + 1900) * 1000000);
 | |
| 
 | |
|     $i = 0;
 | |
|     while ($i <= $#args){
 | |
| 	$option = $args[$i];
 | |
| 	if($option eq "-d"){
 | |
|             if ($Domain ne "") {
 | |
| 		syslog "local1|err","Only one -d option allowed.\n";
 | |
| 		syslog "local1|err","I give up ... sorry.\n";
 | |
| 		exit(1);
 | |
|             }
 | |
| 	    $Domain = $args[++$i];
 | |
| 	    $Domainpattern = "." . $Domain;
 | |
| 	    $Domainpattern =~ s/\./\\./g;        # for stripping off domain
 | |
| 
 | |
| 	    # Add entry to the boot file.
 | |
| 	    $Domainfile = $Domain;
 | |
| 	    $Domainfile =~ s/\..*//;
 | |
| 	    push(@makesoa, $DBDir."db.$Domainfile DOMAIN");
 | |
| 	    push(@bootmsgs_v4, "primary\t$Domain db.$Domainfile\n");
 | |
| 	    push(@bootmsgs_v8, 
 | |
|                qq|zone "$Domain" in {\n\ttype master;\n\tfile "db.$Domainfile";\n};\n\n|);
 | |
| 
 | |
| 	} elsif ($option eq "-f"){
 | |
| 	    $file = $args[++$i];
 | |
| 	    open(F, $file) || die "Unable to open args file $file: $!";
 | |
| 	    while (<F>) {
 | |
| 		next if (/^#/);
 | |
| 		next if (/^$/);
 | |
| 		chop;
 | |
| 		@targs = split(' ');
 | |
| 		push(@newargs, @targs);
 | |
| 	    }
 | |
| 	    close(F);
 | |
| 	    &PARSEARGS(@newargs);
 | |
| 
 | |
| 	} elsif ($option eq "-z"){
 | |
| 	    $Bootsecsaveaddr = $args[++$i];
 | |
| 	    if (!defined($Bootsecaddr)) {
 | |
| 		$Bootsecaddr = $Bootsecsaveaddr;
 | |
| 	    }
 | |
| 
 | |
| 	} elsif ($option eq "-Z"){
 | |
| 	    $Bootsecaddr = $args[++$i];
 | |
| 	    if (!defined($Bootsecsaveaddr)) {
 | |
| 		$Bootsecsaveaddr = $Bootsecaddr;
 | |
| 	    }
 | |
| 
 | |
| 	} elsif ($option eq "-b"){
 | |
| 	    $Bootfile = $args[++$i];
 | |
| 
 | |
| 	} elsif ($option eq "-A"){
 | |
| 	    $doaliases = 0;
 | |
| 
 | |
| 	} elsif ($option eq "-M"){
 | |
| 	    $domx = 0;
 | |
| 
 | |
| 	} elsif ($option eq "-w"){
 | |
| 	    $dowks = 1;
 | |
| 
 | |
| 	} elsif ($option eq "-D"){
 | |
| 	    $dontdodomains = 1;
 | |
| 
 | |
| 	} elsif ($option eq "-t"){
 | |
| 	    $dotxt = 1;
 | |
| 
 | |
| 	} elsif ($option eq "-u"){
 | |
| 	    $User = $args[++$i];
 | |
| 
 | |
| 	} elsif ($option eq "-s"){
 | |
| 	    while ($args[++$i] !~ /^-/ && $i <= $#args) {
 | |
| 		push(@Servers, $args[$i]);
 | |
| 	    }
 | |
| 	    $i--;
 | |
| 
 | |
| 	} elsif ($option eq "-m"){
 | |
| 	    if ($args[++$i] !~ /:/) {
 | |
| 		syslog "local1|err","Improper format for -m option ignored ($args[$i]).\n";
 | |
| 	    }
 | |
| 	    push(@Mx, $args[$i]);
 | |
| 
 | |
| 	} elsif ($option eq "-c"){
 | |
| 	    $tmp1 = $args[++$i];
 | |
| 	    if ($tmp1 !~ /\./) {
 | |
| 		$tmp1 .= ".$Domain";
 | |
| 	    }
 | |
|             if ($Domain eq $tmp1) {
 | |
| 		syslog "local1|err","Domain for -c option must not match domain for -d option.\n";
 | |
| 		syslog "local1|err","I give up ... sorry.\n";
 | |
| 		exit(1);
 | |
|             }
 | |
| 	    $tmp2 = $tmp1;
 | |
| 	    $tmp2 =~ s/\./\\./g; 
 | |
| 	    $cpatrel{$tmp2} = $tmp1;
 | |
| 	    push(@cpats, $tmp2);
 | |
| 
 | |
| 	} elsif ($option eq "-e"){
 | |
| 	    $tmp1 = $args[++$i];
 | |
| 	    if ($tmp1 !~ /\./) {
 | |
| 		$tmp1 .= ".$Domain";
 | |
| 	    }
 | |
| 	    $tmp1 =~ s/\./\\./g; 
 | |
| 	    push(@elimpats, $tmp1);
 | |
| 
 | |
| 	} elsif ($option eq "-h"){
 | |
| 	    $Host = $args[++$i];
 | |
| 
 | |
| 	} elsif ($option eq "-o"){
 | |
| 	    if (   $args[++$i] !~ /^[:\d]*$/ 
 | |
| 		|| split(':', $args[$i]) != 4) {
 | |
| 		syslog "local1|err","Improper format for -o ($args[$i]).\n";
 | |
| 		syslog "local1|err","I give up ... sorry.\n";
 | |
| 		exit(1);
 | |
| 	    }
 | |
| 	    ($DefRefresh, $DefRetry, $DefExpire, $DefTtl) = split(':', $args[$i]);
 | |
|             $UseDefSOAValues = 1;
 | |
| 
 | |
| 	} elsif ($option eq "-i"){
 | |
| 	    $ForceSerial = $args[++$i];
 | |
| 
 | |
| 	} elsif ($option eq "-H"){
 | |
| 	    $Hostfile = $args[++$i];
 | |
| 	    if (! -r $Hostfile || -z $Hostfile) {
 | |
| 		syslog "local1|err","Invalid file specified for -H ($Hostfile).\n";
 | |
| 		syslog "local1|err","I give up ... sorry.\n";
 | |
| 		exit(1);
 | |
| 	    }
 | |
| 
 | |
| 	} elsif ($option eq "-C"){
 | |
| 	    $Commentfile = $args[++$i];
 | |
| 	    if (! -r $Commentfile || -z $Commentfile) {
 | |
| 		syslog "local1|err","Invalid file specified for -C ($Commentfile).\n";
 | |
| 		syslog "local1|err","I give up ... sorry.\n";
 | |
| 		exit(1);
 | |
| 	    }
 | |
| 
 | |
| 	} elsif ($option eq "-N"){
 | |
| 	    $Defsubnetmask = $args[++$i];
 | |
| 	    if (   $Defsubnetmask !~ /^[.\d]*$/ 
 | |
| 		|| split('\.', $Defsubnetmask) != 4) {
 | |
| 		syslog "local1|err","Improper subnet mask ($Defsubnetmask).\n";
 | |
| 		syslog "local1|err","I give up ... sorry.\n";
 | |
| 		exit(1);
 | |
| 	    }
 | |
| 	    if ($#Networks >= 0) {
 | |
| 		syslog "local1|err","Hmm, -N option should probably be specified before any -n options.\n";
 | |
| 	    }
 | |
| 
 | |
| 	} elsif ($option eq "-n"){
 | |
| 	    (my $tnet, $subnetmask) = split(':',$args[++$i]);
 | |
|         $net = "";
 | |
|         my @netm = split(/\./,$subnetmask);
 | |
|         my @tnets = split(/\./,$tnet);
 | |
|         foreach (0..3) {
 | |
|            my $res = ($tnets[$_]+0) & ($netm[$_]+0);
 | |
|            if ($netm[$_]) {
 | |
|               $net.= $res.'.';
 | |
|            }
 | |
|         }
 | |
|         $net =~ s/\.$//;
 | |
|         
 | |
| 	    if ($subnetmask eq "") {
 | |
| 		foreach $tmp1 (&SUBNETS($net, $Defsubnetmask)) {
 | |
| 		    &BUILDNET($tmp1);
 | |
| 		}
 | |
| 	    } else {
 | |
| 		if (   $subnetmask !~ /^[.\d]*$/ 
 | |
| 		    || split('\.', $subnetmask) != 4) {
 | |
| 		    syslog "local1|err","Improper subnet mask ($subnetmask).\n";
 | |
| 		    syslog "local1|err","I give up ... sorry.\n";
 | |
| 		    exit(1);
 | |
| 		}
 | |
| 		foreach $tmp1 (&SUBNETS($net, $subnetmask)) {
 | |
| 		    &BUILDNET($tmp1);
 | |
| 		}
 | |
| 	    }
 | |
| 
 | |
| 	} else {
 | |
| 	    if($option =~ /^-.*/){
 | |
| 		syslog "local1|err","Unknown option: $option ... ignored.\n";
 | |
| 	    }
 | |
| 	}
 | |
| 	$i++;
 | |
|     }
 | |
|     
 | |
|     if (!defined(@Networks) || $Domain eq "") {
 | |
| 	syslog "local1|err","Must specify one -d and at least one -n.\n";
 | |
| 	syslog "local1|err","I give up ... sorry.\n";
 | |
| 	exit(1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| sub BUILDNET {
 | |
|     local($net) = @_;
 | |
| 
 | |
|     push(@Networks, $net);
 | |
|     #
 | |
|     # Create pattern to match against.  
 | |
|     # The dots must be changed to \. so they 
 | |
|     # aren't used as wildcards.
 | |
|     #
 | |
|     $netpat = $net;
 | |
|     $netpat =~ s/\./\\./g;
 | |
|     push(@Netpatterns, $netpat);
 | |
| 
 | |
|     #
 | |
|     # Create db files for PTR records.
 | |
|     # Save the file names in an array for future use.
 | |
|     #
 | |
|     $netfile = "DB.$net";
 | |
|     $Netfiles{$netpat} = $netfile;
 | |
|     push(@makesoa, $DBDir."db.$net $netfile");
 | |
| 
 | |
|     # Add entry to the boot file.
 | |
|     $revaddr = &REVERSE($net);
 | |
|     chop($revaddr);   # remove trailing dot
 | |
|     push(@bootmsgs_v4, "primary $revaddr db.$net\n");
 | |
|     push(@bootmsgs_v8, 
 | |
|          qq|zone "$revaddr" in {\n\ttype master;\n\tfile "db.$net";\n};\n\n|);
 | |
| }
 | |
| 
 | |
| 
 | |
| #
 | |
| # Calculate all the subnets from a network number and mask.
 | |
| # This was originally written for awk, not perl.
 | |
| #
 | |
| sub SUBNETS {
 | |
|     local($network, $mask) = @_;
 | |
|     local(@ans, @net, @mask, $buf, $number, $i, $j, $howmany);
 | |
| 
 | |
|     @net = split(/\./, $network);
 | |
|     @mask = split(/\./, $mask);
 | |
|     $number = '';
 | |
|     #
 | |
|     # Only expand bytes 1, 2, or 3
 | |
|     # for DNS purposes
 | |
|     #
 | |
|     for ($i = 0; $i < 4; $i++) {
 | |
| 	if ($mask[$i] == 255) {
 | |
| 	    $number = $number . $net[$i] . '.';
 | |
| 	} elsif (($mask[$i] == 0) || $mask[$i] eq '') {
 | |
| 	    push(@ans, $network);
 | |
| 	    last;
 | |
| 	} else {
 | |
| 	    #
 | |
| 	    # This should be done as a bit-wise or
 | |
| 	    # but awk does not have an or symbol
 | |
| 	    #
 | |
| 	    $howmany = 255 - $mask[$i];
 | |
| 	    for ($j = 0; $j <= $howmany; $j++) {
 | |
| 		if ($net[$i] + $j <= 255) {
 | |
| 		    $buf = sprintf("%s%d", $number, $net[$i] + $j);
 | |
| 		    push(@ans, $buf);
 | |
| 		}
 | |
| 	    }
 | |
| 	    last;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if ($#ans == -1) {
 | |
| 	push(@ans, $network);
 | |
|     }
 | |
|     
 | |
|     @ans;
 | |
| }
 | |
| 
 | |
| 
 | |
| sub GEN_BOOT {
 | |
|     local(*F, $revaddr, $n);
 | |
| 
 | |
|     if (0) { #! -e "boot.cacheonly") { DISABLE THIS PART
 | |
|         #
 | |
|         # Create a boot file for a cache-only server
 | |
|         #
 | |
| 	open(F, ">boot.cacheonly") || die "Unable to open boot.cacheonly: $!";
 | |
|         if($Version == 4) {
 | |
| 	    print F "directory\t$DBDir\n";
 | |
| 	    print F "primary\t\t0.0.127.IN-ADDR.ARPA    db.127.0.0\n";
 | |
| 	    print F "cache\t\t.                       db.cache\n";
 | |
|             if (-r "spcl.cacheonly") {
 | |
|                 printf F "include\t\tspcl.cacheonly\n";
 | |
|             }
 | |
| 	    close(F);
 | |
|         } else {
 | |
|             print F qq|\noptions {\n\tdirectory "$DBDir";\n|;
 | |
|             if (@forwarders) {
 | |
|                 print F qq|\tforwarders {\n|;
 | |
|                 foreach (@forwarders) {
 | |
|                     print F qq|\t\t$_;\n|;
 | |
|                 }
 | |
|                 print F qq|\t};\n|;
 | |
|             }
 | |
|             if (-r "spcl.options") {
 | |
|                 print F "\t# These options came from the file spcl.options\n";
 | |
|                 #
 | |
|                 # Copy the options in since "include" can't be used
 | |
|                 # within a statement.
 | |
|                 #
 | |
|                 open(OPTIONS, "<spcl.options") || die "Can't open spcl.options\n";
 | |
|                 while(<OPTIONS>)
 | |
|                 {
 | |
|                     print F;
 | |
|                 }
 | |
|                 close(OPTIONS);
 | |
|             }
 | |
|             print F qq|};\n\n|;
 | |
|             print F qq|zone "0.0.127.IN-ADDR.ARPA" in {\n\ttype master;|;
 | |
|             print F qq|\n\tfile "db.127.0.0";|;
 | |
|             print F qq|\n\tnotify no;\n};\n\n|;
 | |
|             #print F qq|zone "." in {\n\ttype hint;\n\tfile "db.cache";\n};\n\n|;
 | |
|             if (-r "spcl.cacheonly") {
 | |
|                 print F qq|include "spcl.cacheonly";\n\n|;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     #
 | |
|     # Create a 2 boot files for a secondary (slave) servers.
 | |
|     # One boot file doesn't save the zone data in a file.  The
 | |
|     # other boot file does save the zone data in a file.
 | |
|     #
 | |
|     if (defined($Bootsecaddr)) {
 | |
| 	open(F, ">boot.sec") || die "Unable to open boot.sec: $!";
 | |
|         if($Version == 4) {
 | |
| 	    print  F "directory\t$DBDir\n";
 | |
| 	    print  F "primary\t\t0.0.127.IN-ADDR.ARPA    db.127.0.0\n";
 | |
| 	    printf F "secondary\t%-23s $Bootsecaddr\n", $Domain;
 | |
| 	    foreach $n (@Networks) {
 | |
| 	        $revaddr = &REVERSE($n);
 | |
| 	        chop($revaddr);
 | |
| 	        printf F "secondary\t%-23s $Bootsecaddr\n", $revaddr;
 | |
|             }
 | |
| 	    print  F "cache\t\t.                       db.cache\n";
 | |
|             if (-r "spcl.boot") {
 | |
|                 printf F "include\t\tspcl.boot\n";
 | |
|             }
 | |
| 	} else {
 | |
|             print F qq|\noptions {\n\tdirectory "$DBDir";\n|;
 | |
|             if (-r "spcl.options") {
 | |
|                 print F "\t# These options came from the file spcl.options\n";
 | |
|                 #
 | |
|                 # Copy the options in since "include" can't be used
 | |
|                 # within a statement.
 | |
|                 #
 | |
|                 open(OPTIONS, "<spcl.options") || die "Can't open spcl.options\n";
 | |
|                 while(<OPTIONS>)
 | |
|                 {
 | |
|                     print F;
 | |
|                 }
 | |
|                 close(OPTIONS);
 | |
|             }
 | |
|             print F qq|};\n\n|;
 | |
|             print F qq|zone "0.0.127.IN-ADDR.ARPA" in {\n\ttype master;|;
 | |
|             print F qq|\n\tfile "db.127.0.0";|;
 | |
|             print F qq|\n\tnotify no;\n};\n\n|;
 | |
|             print F qq|zone "$Domain" in {\n\ttype slave;\n\tmasters {|;
 | |
|             print F qq| $Bootsecaddr; };\n};\n\n|;
 | |
| 
 | |
| 	    foreach $n (@Networks) {
 | |
| 	        $revaddr = &REVERSE($n);
 | |
| 	        chop($revaddr);
 | |
|                 print F qq|zone "$revaddr" in {\n\ttype slave;\n\tmasters {|;
 | |
|                 print F qq| $Bootsecaddr; };\n};\n\n|;
 | |
|             }
 | |
|             #print F qq|zone "." in {\n\ttype hint;\n\tfile "db.cache";\n};\n\n|;
 | |
|             if (-r "spcl.boot") {
 | |
|                 print F qq|include "spcl.boot";\n\n|;
 | |
|             }
 | |
|         }
 | |
| 	close(F);
 | |
| 
 | |
| 	open(F, ">boot.sec.save") || die "Unable to open boot.sec.save: $!";
 | |
|         if($Version == 4) {
 | |
| 	    print  F "directory\t$DBDir\n";
 | |
| 	    print  F "primary\t\t0.0.127.IN-ADDR.ARPA    db.127.0.0\n";
 | |
| 	    printf F "secondary\t%-23s $Bootsecsaveaddr db.%s\n", 
 | |
| 	           $Domain, $Domainfile;
 | |
| 	    foreach $n (@Networks) {
 | |
| 	        $revaddr = &REVERSE($n);
 | |
| 	        chop($revaddr);
 | |
| 	        printf F "secondary\t%-23s $Bootsecsaveaddr db.%s\n", 
 | |
| 		       $revaddr, $n;
 | |
| 	    }
 | |
| 	    print  F "cache\t\t.                       db.cache\n";
 | |
|             if (-r "spcl.boot") {
 | |
|                 printf F "include\t\tspcl.boot\n";
 | |
|             }
 | |
|         } else {
 | |
|             print F
 | |
|                   qq|\noptions {\n\tdirectory "$DBDir";\n|;
 | |
|             if (-r "spcl.options") {
 | |
|                 print F "\t# These options came from the file spcl.options\n";
 | |
|                 #
 | |
|                 # Copy the options in since "include" can't be used
 | |
|                 # within a statement.
 | |
|                 #
 | |
|                 open(OPTIONS, "<spcl.options") || die "Can't open spcl.options\n";
 | |
|                 while(<OPTIONS>)
 | |
|                 {
 | |
|                     print F;
 | |
|                 }
 | |
|                 close(OPTIONS);
 | |
|             }
 | |
|             print F qq|};\n\n|;
 | |
|             print F qq|zone "0.0.127.IN-ADDR.ARPA" in {\n\ttype master;|;
 | |
|             print F qq|\n\tfile "db.127.0.0";|;
 | |
|             print F qq|\n\tnotify no;\n};\n\n|;
 | |
| 
 | |
|             print F qq|zone "$Domain" in {\n\ttype slave;\n\tfile "db.$Domainfile";|;
 | |
|             print F qq|\n\tmasters { $Bootsecsaveaddr; };\n};\n\n|;
 | |
| 
 | |
| 	    foreach $n (@Networks) {
 | |
| 	        $revaddr = &REVERSE($n);
 | |
| 	        chop($revaddr);
 | |
|                 print F 
 | |
|                  qq|zone "$revaddr" in {\n\ttype slave;\n\tfile "db.$n";\n\tmasters {|;
 | |
|                 print F qq| $Bootsecsaveaddr; };\n};\n\n|;
 | |
|             }
 | |
| 
 | |
|             #print F qq|zone "." in {\n\ttype hint;\n\tfile "db.cache";\n};\n\n|;
 | |
|             if (-r "spcl.boot") {
 | |
|                 print F qq|include "spcl.boot";\n\n|;
 | |
|             }
 | |
|         }
 | |
| 	close(F);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 1;
 |