# @PERL@

# @(#) cvtzone.pl 1.3 98/12/21 @(#)

# updatehosts DNS maintenance package
# Copyright (C) 1998  Smoot Carl-Mitchell
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# 
# smoot@tic.com

# convert a zone file to updatehost format
# zone files can be generated by dig axfr command
# read input from stdin

require "getopts.pl";

Getopts("ad:hio:");
if ($opt_h || ! $opt_d || ! $opt_o) {
	print STDERR <<EOF;
usage cvtzone [-a] -d domain -o directory
	-a - append to output files instead of overwriting
	-d - default domain for output
	-h - this help message
	-i - IP address prefix
	-o - directory to write output
EOF
	exit;
}

$continue = 0;
$default_domain = opt_d;
$default_domain .= "." if $default_domain !~ /\.$/;
$ip_prefix = $opt_i;
$seen_soa = 0;

# setup default FIELD headers
$main = "#FIELDS GLOBAL null=X host no=. suffix=.$default_domain ip ";
$main = "no = . prefix=$ip_prefix " if $ip_prefix;
$main = "ether hard os contact ptr ttl\n";
$main .= "localhost. ";
$main = "." if $ip_prefix;
$main = "127.0.0.1\n";

$cname = "#FIELDS GLOBAL host no=.  suffix=.$default_domain alias suffix=.$default_domain ttl\n";

$mx = "#FIELDS domain no=. suffix=.$default_domain priority host no=. suffix=.$default_domain ttl\n";

$ns = "#FIELDS domain no=. suffix=.$default_domain server no=. suffix=.$default_domain ttl\n";
$ns .= "localhost. localhost.\n";
$ns .= "127.in-addr.arpa. localhost.\n";

$soa = "#FIELDS domain no=. suffix=.$default_domain server no=. suffix=.$default_domain contact suffix=.$default_domain refresh retry expire min checknames notify\n";
$soa .= "localhost. localhost. root 3600 300 604800 86400 warn no\n";
$soa .= "127.in-addr.arpa. localhost. root 3600 300 604800 86400 warn no\n";

while (<>) {
	chop;
	# strip comments and ignore blank lines
	s/;.*$//;
	next if /^\s*$/;

	# process an $ORIGIN statement
	if (/^\$ORIGIN/) {
		s/\$ORIGIN //;
		$origin_domain = $_;

		next;
	}

	# continuation line processing - only on SOA records
	if ($continue) {
		# end of continuation lines
		if (/ \)/) {
			s/ \)//;
			$continue = 0;
		}
		# strip leading and trailing whitespace
		s/(^\s*)(.*)(\s*$)/ $2 /;
		$value .= $_;
	}
	else {
		# set the domain for each record
		s/^@/$origin_domain/ unless $continue;
		s/^\s/$current_domain/ unless $continue;

		($domain, $ttl, $in, $type, $value) = split(' ', $_, 5);

		# fully qualify the domain
		$domain =  "$domain.$origin_domain" if $domain !~ /\.$/;

		$current_domain = $domain;
		# continuation lines
		if ($value =~ / \(/) {
			$continue = 1;
			$value =~ s/ \(//;
		}

	}

	next if $continue;

	if ($type eq "SOA") {
		($server, $contact, $serial, $refresh, $retry, $expire, $min) = split(' ', $value);

		$seen_soa = 1;
		# need to interpret values, since they are in a readable format
		$refresh = cvttime($refresh);
		$retry = cvttime($retry);
		$expire = cvttime($expire);
		$min = cvttime($min);

		# fully-qualify any partially qualified domains and then strip them
		# to less the default_domain
		$domain = strip_domain($domain, $origin_domain, $default_domain);
		$server = strip_domain($server, $origin_domain, $default_domain);
		$contact = strip_domain($contact, $origin_domain, $default_domain);

		$soa .= "$domain $type $server $contact $refresh $retry $expire $min warn yes\n";
		next;
	}

	if ($type eq "NS") {
		$domain = strip_domain($domain, $origin_domain, $default_domain);
		$value = strip_domain($value, $origin_domain, $default_domain);
		$ns .= "$domain $value\n";
		next;
	}

	if ($type eq "A") {
		$domain = strip_domain($domain, $origin_domain, $default_domain);
		$value = strip_ip($value, $ip_prefix);
		$main .= "$domain $value\n";
		next;
	}

	if ($type eq "MX") {
		($priority, $mail_server) = split(/ /, $value);
		$domain = strip_domain($domain, $origin_domain, $default_domain);
		$mail_server = strip_mail_server($mail_server, $default_mail_server);
		$mx .= "$domain $priority $mail_server\n";
		next;
	}

	if ($type eq "CNAME") {
		$domain = strip_domain($domain, $origin_domain, $default_domain);
		$value = strip_domain($value, $origin_domain, $default_domain);
		$cname .= "$domain $value\n";
		next;
	}
}

$op = ">";
$op = ">>" if $opt_a;
# write all the file out to the directory
open(OUT, "$op $directory/main") || die "cannot open $directory/main\n";
print OUT $main;
open(OUT, "$op $directory/mx") || die "cannot open $directory/mx\n";
print OUT $mx;
open(OUT, "$op $directory/cname") || die "cannot open $directory/cname\n";
print OUT $cname;
open(OUT, "$op $directory/ns") || die "cannot open $directory/ns\n";
print OUT $ns;
open(OUT, "$op $directory/soa") || die "cannot open $directory/soa\n";
print OUT $soa;

sub strip_domain {
	local($domain) = shift;
	local($origin_domain) = shift;
	local($default_domain) = shift;

	# fully-qualify the domain with the origin_domain
	if ($domain !~ /\.$/) {
		if ($origin_domain) {
			$domain .= ".$origin_domain";
		}
		else {
			$domain .= ".$default_domain";
		}
	}

	# now strip off the default domain
	$domain =~ s/\.$default_domain$//;

	return $domain;
}

sub strip_ip {
	local($ip) = shift;
	local($ip_prefix) = shift;

	$ip =~ s/^$ip_prefix//;
	return $ip;
}

sub cvttime {
	local($input) = shift;

	# do nothing if all digits
	return $input if $input =~ /^[0-9][0-9]*$/;

	# parse the string
	$input = "\L$input\E";
	local(@chars) = split(//, $input);
	
	# string looks like xxwxxxdxxhxmxxs
	# convert to seconds
	local($output) = 0;
	local($value) = "";
	local($char);
	for $char (@chars) {
		if ($char =~ /[0-9]/) {
			$value .= $char;
			next;
		}
		if ($char eq "w") {
			$output += int($value)*60*60*24*7;
			$value = "";
			next;
		}
		if ($char eq "d") {
			$output += int($value)*60*60*24;
			$value = "";
			next;
		}
		if ($char eq "h") {
			$output += int($value)*60*60;
			$value = "";
			next;
		}
		if ($char eq "m") {
			$output += int($value)*60;
			$value = "";
			next;
		}
		if ($char eq "s") {
			$output += int($value);
			$value = "";
			next;
		}
	}
	return $output;
}
