#! /usr/bin/perl
#
#ident	"@(#)bind:BIND-4_9_7-REL-PLANIX-1:gencidrzone,v 1.3 1996/08/29 04:58:22 woods Exp"
#
#	gencidrzone - generate zone and include files for
#			classless in-addr delegation
#
#	(C)Copyright 1996 Mathias Koerber <mathias@singnet.com.sg>
#	Free to use for all
#	No warranties, claims etc ..
#
#	generates two files:
#		1. skeleton/sample zonefile for subdomain.
#		2. include file for parent zone. Include file
#		   contains: delegation NS records and all CNAME records
#
#	see usage below
#

require "newgetopt.pl";

($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst, $zone, $gmtoff) = localtime();
$year += ($year < 70) ? 2000 : 1900;

# some defaults
$opt_primary		= "<your_primary>";
$opt_contact		= "<zone_contact_address>";
$opt_providordomain	= $ENV{"DOMAINNAME"};
$opt_serialnumber	= sprintf("%-4.4d%-2.2d%-2.2d00",$year,($mon+1),$mday);
$opt_refresh		= 10800;		# 3 hours
$opt_retry		= 7200;			# 2 hours
$opt_expire		= 604800;		# 1 week
$opt_minimum		= 10800;		# 3 hours

if ((&NGetOpt("subdomain:s",
	      "contact=s",
	      "providordomain:s",
	      "primary=s",
	      "secondary:s@",
	      "serialnumber:s",
	      "refresh:i",
	      "retry:i",
	      "expire:i",
	      "minimum:i",
	      ) == 0) || ($#ARGV != 0)) {
	print STDERR <<EOF;
usage $0 [options] <addressblock>

where: 	<addressblock> is the block in prefix-length notation

required flags include:
	-contact <email_addr>	SOA contact address
		default: placeholder string
	-primary <name>		name of the primary server
		default: placeholder string

optional flags:
	-providordomain		providor domain name
		default: DOMAINNAME from environment
	-subdomain <name>	name for the subdomain to
				be delegated
		default: last byte of the first address
			in the block (in decimal)
		example: aaa.bbb.ccc.128/26
			default:
				128.ccc.bbb.aaa.in-addr.arpa
			-subdomain them:
				them.ccc.bbb.aaa.in-addr.arpa
	-secondary <name>	secondary NS (may appear mult. times)
		default: placeholder string
	-serialnumber <number>	default SOA value
		default: YYYYMMDD00
	-refresh <number>		-"-
		default: 3 hours
	-retry <number>			-"-
		default: 2 hours
	-expire <number>		-"-
		default: 1 week
	-minimum <number>		-"-
		default: 3 hours
EOF
	exit 2;
}

@opt_secondary = ("<your_secondary>") if (!@opt_secondary);

# perform some courtesy translations
#
$opt_contact =~ tr/\@/./;

# and some sanity ones
#
chop($opt_primary) if ($opt_primary =~ /\.$/);
chop($opt_contact) if ($opt_contact =~ /\.$/);
for $i (0 .. $#opt_secondary) {
	chop($opt_secondary[$i]) if ($opt_secondary[$i] =~ /\.$/);
}
chop($opt_providordomain) if ($opt_providordomain =~ /\.$/);

if ($opt_providordomain !~ /^\./) {
	$opt_providordomain = "." . $opt_providordomain;
}

($ip,$bits) = split('/',$ARGV[0]);
($a,$b,$c,$d) = split(/\./,$ip);

if ($bits <= 24) {
	print "gencidrzone only makes sense for prefixes > 24 bits.\n";
	print "Please try again\n";
	exit(2);
}

$add1 = (($a * (256**3)) + ($b * (256**2)) + ($c * (256**1)) + $d);
$mb = (2**32)-(2**(32-$bits));
$mb2 = 2**(32-$bits)-1;

$add2 = ($add1 & $mb);
$add3 = ($add2 | $mb2);

($fa,$fb,$fc,$fd) = &unp($add2);
($la,$lb,$lc,$ld) = &unp($add3);

($na,$nb,$nc,$nd) = &unp(~(2**(32 - $bits) - 1));

$subdomain = $opt_subdomain ? $opt_subdomain : $fd;

$subnetname = "sub-" . $subdomain . "-net" . $opt_providordomain;
$subnetbroad = "sub-" . $subdomain . "-bcast" . $opt_providordomain;

$fdh = $fd + 1;
$ldh = $ld - 1;
  
open(SUB,">$subdomain.$fc.$fb.$fa.db");
open(INC,">$fc.$b.$fa.inc.$subdomain");

print SUB <<"EOF";
;
;	CIDRD reverse delegation for $ARGV[0]
;
;	(addresses from $fa.$fb.$fc.$fd to $la.$lb.$lc.$ld)
;
;	WARNING:  Please read this entire comment carefully!
;
;	This is the reverse zone file for the sub-zone named:
;
;		$subdomain.$fc.$fb.$fa.in-addr.arpa
;
;	Your site has been allocated the address range $ARGV[0].
;	(I.e. addresses from $fa.$fb.$fc.$fd to $la.$lb.$lc.$ld)
;
;	Since this range is smaller than a classical Class C (/24),
;	you cannot be given authority over the full reverse domain:
;
;		$fc.$fb.$fa.in-addr.arpa
;
;	(you are sharing it with other networks).
;
;	For this reason we are only allocating you a subdomain of the
;	above reverse domain.  This subdomain is called:
;
;		$subdomain.$fc.$fb.$fa.in-addr.arpa.
;
;	To set up a primary nameserver for this (reverse) domain, you
;	will need to add a line:
;
;		primary	$subdomain.$fc.$fb.$fa.in-addr.arpa <zonefile>
;
;	into your nameserver's named.boot file, where <zonefile> will
;	have to be replaced with the path/filename of your zonefile.
;
;	You may use this file you are currently reading as the zonefile
;	for your reverse domain.  Please remember to make the necessary
;	changes:
;
;		- replace the references to <your_primary_nameserver>
;		  and <your_contact_address> with the real data, and
;
;		- edit the PTR records as indicated below..
;
;	In it you can register the PTR records for your domain.  Please
;	note that you cannot use the traditional IN-ADDR.ARPA zone entries
;	with the following notation:
;
;		XX.$fc.$fb.$fa.in-addr.arpa.	IN PTR	<somehostname>
;
;	I.e. you cannot give the full reverse domainname on the left
;	hand side since you will have to use the delegated subdomain.
;	We advise you to use the pre-listed records below, only giving
;	the last octet in the host address.
;
;	Please do *not* change the \$ORIGIN.
;
;	Please note that you can only list addresses within the	range of
;	$fdh to $ldh in this file, and that the first and last addresses
;	in your allocated block cannot be used for hosts (they are reserved
;	for the network and broadcast address respectively).
;
;	We have (or will shortly) set up CNAME translations of:
;
;		XX.$fc.$fb.$fa.in-addr.arpa
;	to:
;		XX.$subdomain.$fc.$fb.$fa.in-addr.arpa
;
;	for each address in your network range.
;
;	For more information on this allocation scheme, please see the URL:
;
;ftp://ftp.internic.net/internet-drafts/draft-ietf-cidrd-classless-inaddr-01.txt
;
;	NOTE:  please enter your primary and secondary servers and contact
;	address below (don't forget the trailing '.')
;
;	Don't forget to replace the '\@' in the contact address with '.' !!!
;
;	Don't delete the trailing '.' either!
;
;	CAVEAT ADMINISTRATOR:  *never* use '#' as the comment character
;	in files used by the nameserver (named.boot, zonefiles, etc).
;	The correct comment character is the semicolon (';').
;	Named might not work if you use '#' !!!!
;
;	IMPORTANT:  DO NOT FORGET TO UPDATE THE SERIAL NUMBER
;	EACH TIME YOU CHANGE THIS FILE !!!

\$ORIGIN $subdomain.$fc.$fb.$fa.in-addr.arpa.
\@	IN	SOA	$opt_primary. $opt_contact. (
			$opt_serialnumber	; Serial
			$opt_refresh		; Refresh
			$opt_retry		; Retry
			$opt_expire		; Expire
			$opt_minimum )		; Min TTL
\@	IN	NS	$opt_primary.
EOF

# now print out "secondary" the NS lines for the zone....
#
for $i (@opt_secondary) {
	print SUB "\@\tIN\tNS\t$i.\n";
}

print SUB <<"EOF";

;	NOTE:  The following RRs will only be seen locally, and must
;	also be present in the zone for the entire classic non-CIDR
;	network:
;
\@	IN	PTR	$subnetname.
\@	IN	A	$na.$nb.$nc.$nd		; subnet netmask

;------
;
;	WARNING:  You cannot use the first and last addresses for hosts.
;
;	The first is $fa.$fb.$fc.$fd, which is a network address,
;	and last is $la.$lb.$lc.$ld, which is a broadcast address.
;
;------
;
;	The individual PTR records below are still commented out.
;	Fill in the correct hostnames and remove the leading ';'.
;
;	Don't forget to leave the trailing '.' there!!!
;
;	We advise that you only uncomment the PTR record you
;	really need.

EOF

print INC <<"EOF";
;
;	CIDRD delegation for $ARGV[0]
;
;	(addresses from $fa.$fb.$fc.$fd to $la.$lb.$lc.$ld)
;
;	This file should be "include'd" in the zone file for:
;
;		$fc.$fb.$fa.in-addr.arpa

$subdomain	IN	NS	$opt_primary.
EOF

# now print out the "secondary" NS lines for the zone....
#
for $i (@opt_secondary) {
	print INC "\tIN\tNS\t$i.\n";
}

print INC <<"EOF";
	IN	PTR	$subnetname.
	IN	A	$na.$nb.$nc.$nd		; subnet netmask
;
;	The corresponding A record should be put in the zone file for:
;
;		$opt_providordomain
;
;	$subnetname.	IN	A	$fa.$fb.$fc.$fd

EOF

for $dd (($fdh) .. ($ldh)) {
	print SUB ";$dd\tIN\tPTR\t<some_hostname_$dd>.\n";
	print INC "$dd\tIN\tCNAME\t$dd.$subdomain.$fc.$fb.$fa.in-addr.arpa.\n";
}

print SUB <<"EOF";

;	this is the sub-net's broadcast address, and can
;	not be used for a host address:
;
;	NOTE:  The following RR will only be seen locally, and must
;	also be present in the zone for the entire classic non-CIDR
;	network:
;
$ld	IN	PTR	$subnetbroad.
EOF

print INC <<"EOF";

;	this is the sub-net's broadcast address, and can
;	not be used for a host address:
;
$ld	IN	PTR	$subnetbroad.
	IN	UINFO	"subnet $fd broadcast address"

;	The corresponding A record should be put in the zone file for:
;
;		$opt_providordomain
;
;	$subnetbroad.	IN	A	$la.$lb.$lc.$ld
EOF

close(SUB);
close(INC);

sub unp {
	local($o) = $_[0];
	local($r);
	local($a, $b, $c, $d);

	$d = $o & 0x000000ff;
        $o >>= 8;
	$c = $o & 0x000000ff;
        $o >>= 8;
	$b = $o & 0x000000ff;
        $o >>= 8;
	$a = $o & 0x000000ff;

	return($a, $b, $c, $d);
}
