aboutsummaryrefslogtreecommitdiff
path: root/contrib/ms2isc/ms2isc.pl
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ms2isc/ms2isc.pl')
-rw-r--r--contrib/ms2isc/ms2isc.pl634
1 files changed, 634 insertions, 0 deletions
diff --git a/contrib/ms2isc/ms2isc.pl b/contrib/ms2isc/ms2isc.pl
new file mode 100644
index 0000000..da3e10f
--- /dev/null
+++ b/contrib/ms2isc/ms2isc.pl
@@ -0,0 +1,634 @@
+#set ts=3
+#
+# ms2isc.pl
+# MS NT4 DHCP to ISC DHCP Configuration Migration Tool
+#
+# Author: Shu-Min Chang
+#
+# Copyright(c) 2003 Intel Corporation. All rights reserved
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright notice
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution
+# 3. Neither the name of Intel Corporation nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE INTEL CORPORATION AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO PROCUREMENT OF SUBSTITUE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVICED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+
+use strict;
+use Socket;
+use Getopt::Std;
+use Filehandle;
+use Registry; # Custom Perl Module to make Registry access easier.
+
+my $usage = << 'ENDOFHELP';
+
+Purpose: A Perl Script converting MS NT4 DHCP configuration to ISC DHCP3
+configuration file by reading NT4's registry.
+
+Requires: Registry.pm and ActiveState 5.6.0
+
+Usage: $ARGV -s <Srv> -o <Out> [-p <Pri> [-k <key>]] [-f <Fo>]
+
+ <Srv> Server IP or name for NT4 DHCP server to fetch the configuration from.
+ <Out> Output filename for the configuration file.
+ <Pri> Primary DNS server name for sending the dynamic DNS update to.
+ <Key> Key name for use in updating the dynamic DNS zone.
+ <Fo> Failover peer name shared with the DHCP partner.
+
+Essentially the <Srv> needs to be an NT4 (3.x should work but not tested) which
+you should have registry read access to. You must run this script from a
+Windows machine because of the requirement to access the registry.
+
+The <Pri> is optional parameter for desginating the dynamic DNS update if
+missing then the "zone" section of the declaration will be skipped. The <Key>
+is needed if you've configured your DNS zone with a key, in addition, you'll
+need to define that key in this DHCP configuration file elsewhere manually,
+read the DHCP Handbook to figure out what you need to define.
+
+The <Fo> specifies the fail-over peer name in the pool section, you'll need to
+define additional detail elsewhere manually, again read the DHCP handbook.
+
+NOTE: the program only knows of the following global and subnet options:
+ 3, 6, 15, 28, 44, and 46
+
+ If it runs into options other than the known ones, it will quit. You
+ may fix this by modifying the following procedures:
+ GetGlobalOptions
+ GetScopes
+ PrintSubnetConfig
+
+ In addition, the resulting subnets configuration will have the "deny
+ dynamic bootp clients" you should take them out if that's not what you
+ want :).
+
+ Finally, as the parameter structures implied, it is assumed that you
+ want the same zone primary and update key for all zones and that the
+ same failover is to be applied to all the pools. Furthermore the
+ subnet zones are all assumed to be class C delineated, but if you
+ happend to be delegated at the class B level, this will work fine too.
+
+Author: Shu-Min Chang <smchang@yahoo.com>
+
+Copyright: Please read the top of the source code
+
+Acknowledgement:
+ Brian L. King for coding help, Douglas A. Darrah for testing, and James E.
+Pressley for being the DHCP reference book :).
+
+Usage: $ARGV -s <Srv> -o <Out> [-p <Pri> [-k <key>]] [-f <Fo>]
+
+Version: 1.0.1
+
+ENDOFHELP
+
+###################### Begin Main Program ####################################
+
+ my (%opts, %GlobalOptions, %SuperScopes, %Scopes);
+
+ ### Get parameters and make sure that they meet the require/optoinal criteria
+ getopts('s:o:p:k:f:', \%opts) or die $usage;
+ ($opts{s} and $opts{o}) or die $usage;
+ if ($opts{k}) { $opts{p} or die $usage; }
+
+ ### Read all the registry stuff into the memory
+ %GlobalOptions = GetGlobalOptions($opts{s});
+ %SuperScopes = GetSuperScope($opts{s});
+ %Scopes = GetScopes ($opts{s});
+
+ ### Process and print out to the output file
+ my ($outfile, $i, $j, @Domains);
+
+ $outfile = new FileHandle "> $opts{o}";
+ if (!defined $outfile) {
+ die "Can't open file: $opts{o}: $!";
+ }
+
+ for $i (keys %SuperScopes) {
+ print $outfile "\n##############################################################\n";
+ my ($Scopename) = $i;
+ $Scopename =~ s/ //g;
+ print $outfile "shared-network $Scopename {\n";
+ foreach $j (@{$SuperScopes{$i}}) {
+ PrintSubnetConfig($outfile, \%GlobalOptions, \%{$Scopes{$j}}, $j, "\t", $opts{f});
+ InsertIfUnique (\@Domains, $Scopes{$j}{domain}) if exists $Scopes{$j}{domain};
+ delete $Scopes{$j};
+ }
+ print $outfile "}\n";
+ if ($opts{p} or $opts{k}) {
+ foreach $j (@{$SuperScopes{$i}}) {
+ PrintSubnetUpdate($outfile, $j, $opts{p}, $opts{k});
+ }
+ }
+ }
+
+ for $i (keys %Scopes) {
+ print $outfile "\n##############################################################\n";
+ PrintSubnetConfig($outfile, \%GlobalOptions, \%{$Scopes{$i}}, $i, "", $opts{f});
+ if ($opts{p} or $opts{k}) { PrintSubnetUpdate($outfile, $i, $opts{p}, $opts{k}); }
+ InsertIfUnique (\@Domains, $Scopes{$i}{domain}) if exists $Scopes{$i}{domain};
+ }
+
+ if ($opts{p} or $opts{k}) {
+ InsertIfUnique (\@Domains, $GlobalOptions{domain}) if exists $GlobalOptions{domain};
+ for $i (@Domains) {
+ PrintDomainUpdate($outfile, $i, $opts{p}, $opts{k});
+ }
+ }
+
+ undef ($outfile);
+ print "Done.\n";
+ exit();
+
+################################## End Main Program ###########################
+
+
+
+
+
+######################################################################
+sub InsertIfUnique ($$) {
+ my ($Array, $data) = @_;
+# purpose: insert $data into array @{$Array} iff the data is not in there yet
+# input:
+# $data: scalar data to be added to the @{$Array} if unique
+# $Array: reference of the Array to compare the uniqueness of the $data
+# output:
+# $Array: reference of the array with the resulting array.
+# return: none
+
+ my ($i);
+
+ for ($i=0; $i<=$#{$Array} && ${$Array}[$i] ne $data; $i++) { }
+
+ if ($i > $#{$Array}) {
+ ${$Array}[$i] = $data;
+ }
+}
+######################################################################
+sub PrintDomainUpdate ($$$$) {
+ my ($outfile, $Domain, $DDNSServer, $key) = @_;
+# purpose: print out the foward domain zone update declaration
+# input:
+# $outfile: filehandle of the file to write the output to
+# $Domain: a string representing the forward domain
+# $DDNSServer: a string of the DNS server accepting the DDNS update
+# $key: a string representing the key used to update the zone
+# output: none
+# return: none
+#
+
+ print $outfile "zone $Domain {\n";
+ print $outfile "\tprimary $DDNSServer;\n";
+ !$key or print $outfile "\tkey $key;\n";
+ print $outfile "}\n";
+
+}
+######################################################################
+sub PrintSubnetUpdate ($$$$) {
+ my ($outfile, $Subnet, $DDNSServer, $key) = @_;
+# purpose: print out the reverse domain zone update declaration
+# input:
+# $outfile: filehandle of the file to write the output to
+# $Subnet: a string representing the subnet in the form 1.2.3.4
+# $DDNSServer: a string of the DNS server accepting the DDNS update
+# $key: a string representing the key used to update the zone
+# output: none
+# return: none
+#
+
+ my ($Reverse);
+
+ $_ = join (".", reverse(split(/\./, $Subnet)));
+ m/\d*\.(.*)/;
+ $Reverse = $1;
+ print $outfile "zone $Reverse.in-addr.arpa. {\n";
+ print $outfile "\tprimary $DDNSServer;\n";
+ !$key or print $outfile "\tkey $key;\n";
+ print $outfile "}\n";
+
+}
+######################################################################
+sub PrintSubnetConfig ($$$$$$) {
+ my ($outfile, $GlobalOptions, $Scope, $Subnet, $prefix, $failover) = @_;
+# purpose: print out the effective scope configuration for one subnet as
+# derived from the global and scope options.
+# input:
+# $outfile: filehandle of the file to write the output to
+# $GlobalOptions: refernce to the hashed variable from GetGlobalOptions
+# $Scopes: reference to the hashed variable of the subnet in interest
+# $Subnet: string variable of the subnet being processed
+# $prefix: string to be printed before each line (designed for tab)
+# $failover: string to be used for the "failover peer" line
+# output: none
+# return: none
+#
+ my ($pound) = ( ${$Scope}{disable}? "#".$prefix : $prefix);
+ print $outfile $pound, "subnet $Subnet netmask ${$Scope}{mask} {\n";
+ print $outfile "$prefix# Name: ${$Scope}{name}\n";
+ print $outfile "$prefix# Comment: ${$Scope}{comment}\n";
+ if (exists ${$Scope}{routers}) {
+ print $outfile $pound, "\toption routers @{${$Scope}{routers}};\n";
+ } elsif (exists ${$GlobalOptions}{routers}) {
+ print $outfile $pound, "\toption routers @{${$GlobalOptions}{routers}};\t# NOTE: obtained from global option, bad practice detected\n";
+ } else {
+ print $outfile "### WARNING: No router was found for this subnet!!! ##########\n";
+ }
+
+ if (exists ${$Scope}{dnses}) {
+ print $outfile $pound, "\toption domain-name-servers ", join(",", @{${$Scope}{dnses}}), ";\n";
+ } elsif (exists ${$GlobalOptions}{dnses}) {
+ print $outfile $pound, "\toption domain-name-servers ", join(",", @{${$GlobalOptions}{dnses}}), ";\n";
+ }
+
+ if (exists ${$Scope}{domain}) {
+ print $outfile $pound, "\toption domain-name \"${$Scope}{domain}\";\n";
+ } elsif (exists ${$GlobalOptions}{domain}) {
+ print $outfile $pound, "\toption domain-name \"${$GlobalOptions}{domain}\";\n";
+ }
+
+ if (exists ${$Scope}{broadcast}) {
+ print $outfile $pound, "\toption broadcast-address ${$Scope}{broadcast};\n";
+ } elsif (exists ${$GlobalOptions}{broadcast}) {
+ print $outfile $pound, "\toption broadcast-address ${$GlobalOptions}{broadcast};\n";
+ }
+
+ if (exists ${$Scope}{winses}) {
+ print $outfile $pound, "\toption netbios-name-servers ", join(",", @{${$Scope}{winses}}), ";\n";
+ } elsif (exists ${$GlobalOptions}{winses}) {
+ print $outfile $pound, "\toption netbios-name-servers ", join(",", @{${$GlobalOptions}{winses}}), ";\n";
+ }
+
+ if (exists ${$Scope}{winstype}) {
+ print $outfile $pound, "\toption netbios-node-type ${$Scope}{winstype};\n";
+ } elsif (exists ${$GlobalOptions}{winstype}) {
+ print $outfile $pound, "\toption netbios-node-type ${$GlobalOptions}{winstype};\n"
+ }
+
+ print $outfile $pound, "\tdefault-lease-time ${$Scope}{leaseduration};\n";
+ print $outfile $pound, "\tpool {\n";
+ for (my $r=0; $r<=$#{${$Scope}{ranges}}; $r+=2) {
+ print $outfile $pound, "\t\trange ${$Scope}{ranges}[$r] ${$Scope}{ranges}[$r+1];\n";
+ }
+ !$failover or print $outfile $pound, "\t\tfailover peer \"$failover\";\n";
+ print $outfile $pound, "\t\tdeny dynamic bootp clients;\n";
+ print $outfile $pound, "\t}\n";
+ print $outfile $pound, "}\n";
+}
+
+######################################################################
+sub GetScopes ($) {
+ my ($Server) = @_;
+ my (%Scopes);
+# purpose: to return NT4 server's scope configuration
+# input:
+# $Server: string of the valid IP or name of the NT4 server
+# output: none
+# return:
+# %Scope: hash of hash of hash of various data types to be returned of the
+# following data structure
+# $Scope{<subnet>}{disable} => boolean
+# $Scope{<subnet>}{mask} => string (e.g. "1.2.3.255")
+# $Scope{<subnet>}{name} => string (e.g "Office Subnet #1")
+# $Scope{<subnet>}{comment} => string (e.g. "This is a funny subnet")
+# $Scope{<subnet>}{ranges} => array of paired inclusion IP addresses
+# (e.g. "1.2.3.1 1.2.3.10 1.2.3.100 10.2.3.200
+# says that we have 2 inclusion ranges of
+# 1-10 and 100-200)
+# $Scopes{<subnet>}{routers} => array of IP address strings
+# $Scopes{<subnet>}{dnses} => array of IP address/name string
+# $Scopes{<subnet>}{domain} > string
+# $Scopes{<subnet>}{broadcast} => string
+# $Scopes{<subnet>}{winses} => array of IP addresses/name string
+# $Scopes{<subnet>}{winstype} => integer
+# $Scopes{<subnet>}{leaseduration} => integer
+
+ my ($RegVal, @Subnets, @Router, $SubnetName, $SubnetComment, @SubnetOptions, @SRouter, @SDNSServers, @SDomainname, @SWINSservers, @SNetBIOS, @SLeaseDuration, @SSubnetState, @SExclusionRanges, @SSubnetAddress, @SSubnetMask, @SFirstAddress, $SStartAddress, $SEndAddress, @InclusionRanges, @SBroadcastAddress);
+
+ print "Getting list of subnets\n";
+ if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets", \@Subnets)) {
+ die "Unable to obtain a list of subnets from the server!\n";
+ }
+
+ for (my $i=0; $i<=$#Subnets; $i++) {
+ print "\t Fetching Subnet $Subnets[$i] (",$i+1, "/", $#Subnets+1, "): ";
+
+ print ".";
+ if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges", \@SFirstAddress)) {
+ # Don't know why MS has a tree for this, but as far
+ # as I can tell, only one subtree will ever come out of
+ # this, so I'm skipping the 'for' loop
+
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges\\$SFirstAddress[0]\\StartAddress", \$RegVal)) {
+ $SStartAddress = $RegVal;
+ }
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges\\$SFirstAddress[0]\\EndAddress", \$RegVal)) {
+ $SEndAddress = $RegVal;
+ }
+# print "\n\tInclusion Range: ", Registry::ExtractIp($SStartAddress), " - ", Registry::ExtractIp($SEndAddress),"\n";
+
+ } else {
+ die "\n\n# Error Getting Inclusion Range FirstAddress!!!\n\n";
+ }
+
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\ExcludedIpRanges", \$RegVal)) {
+ @SExclusionRanges = Registry::ExtractExclusionRanges($RegVal);
+
+# for (my $j=2; $j<=$#SExclusionRanges; $j+=2) {
+# if (unpack("L",$SExclusionRanges[$j]) < unpack("L",$SExclusionRanges[$j-2])) {
+# print ("\n******** Subnet exclusion ranges out of order ********\n");
+# }
+# }
+
+ @SExclusionRanges = sort(@SExclusionRanges);
+
+# print "\n\tExclusion Ranges: ";
+# for (my $j=0; $j<=$#SExclusionRanges; $j+=2) {
+# print "\n\t\t",Registry::ExtractIp($SExclusionRanges[$j])," - ",Registry::ExtractIp($SExclusionRanges[$j+1]);
+# }
+
+ }
+ @InclusionRanges = FindInclusionRanges ($SStartAddress, $SEndAddress, @SExclusionRanges);
+
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetName", \$RegVal)) {
+ $SubnetName = $RegVal;
+# print "\n\tSubnetName: $SubnetName";
+ }
+
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetComment", \$RegVal)) {
+ $SubnetComment = $RegVal;
+# print "\n\tSubnetComment: $SubnetComment";
+ }
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetAddress", \$RegVal)) {
+ @SSubnetAddress = Registry::ExtractIp($RegVal);
+# print "\n\tSubnetAddress: $SSubnetAddress[0]";
+ }
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetMask", \$RegVal)) {
+ @SSubnetMask = Registry::ExtractIp($RegVal);
+# print "\n\tSubnetMask: $SSubnetMask[0]";
+ }
+
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetState", \$RegVal)) {
+ @SSubnetState = Registry::ExtractHex ($RegVal);
+# print "\n\tSubnetState = $SSubnetState[0]";
+ }
+
+ $Scopes{$Subnets[$i]}{disable} = hex($SSubnetState[0]) ? 1 : 0;
+ $Scopes{$Subnets[$i]}{mask} = $SSubnetMask[0];
+ $Scopes{$Subnets[$i]}{name} = $SubnetName;
+ $Scopes{$Subnets[$i]}{comment} = $SubnetComment;
+ for (my $r=0; $r<=$#InclusionRanges; $r++) {
+ $Scopes{$Subnets[$i]}{ranges}[$r] = Registry::ExtractIp($InclusionRanges[$r]);
+ }
+
+################## Get scope options
+
+ my (@SubnetOptionsList);
+
+ print "\n\t\tOptions:";
+ if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetOptions", \@SubnetOptionsList)) {
+ die "Unable to get subnet options list for $Subnets[$i]!\n";
+ }
+
+ for (my $j=0; $j<=$#SubnetOptionsList; $j++) {
+ print ".";
+ if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetOptions\\$SubnetOptionsList[$j]\\OptionValue", \$RegVal)) {
+ for ($SubnetOptionsList[$j]) {
+ /003/ and do {
+# @SRouter = Registry::ExtractOptionIps($RegVal);
+ $Scopes{$Subnets[$i]}{routers} = [Registry::ExtractOptionIps($RegVal)];
+ last;
+ };
+ /006/ and do {
+ @SDNSServers = Registry::ExtractOptionIps($RegVal);
+ for (my $d=0; $d<=$#SDNSServers; $d++) {
+ my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $SDNSServers[$d])), &AF_INET);
+ $Scopes{$Subnets[$i]}{dnses}[$d] = $ipname ? $ipname : $SDNSServers[$d];
+ }
+ last;
+ };
+ /015/ and do {
+ @SDomainname = Registry::ExtractOptionStrings($RegVal);
+ $Scopes{$Subnets[$i]}{domain} = $SDomainname[0];
+ last;
+ };
+ /028/ and do {
+ @SBroadcastAddress = Registry::ExtractOptionIps($RegVal);
+ $Scopes{$Subnets[$i]}{broadcast} = $SBroadcastAddress[0];
+ last;
+ };
+ /044/ and do {
+ @SWINSservers = Registry::ExtractOptionIps($RegVal);
+ for (my $w=0; $w<=$#SWINSservers; $w++) {
+ my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $SWINSservers[$w])), &AF_INET);
+ $Scopes{$Subnets[$i]}{winses}[$w] = $ipname ? $ipname : $SWINSservers[$w];
+ }
+ last;
+ };
+ /046/ and do {
+ @SNetBIOS = Registry::ExtractOptionHex($RegVal);
+ $Scopes{$Subnets[$i]}{winstype} = hex($SNetBIOS[0]);
+ last;
+ };
+ /051/ and do {
+ @SLeaseDuration = Registry::ExtractOptionHex($RegVal);
+ $Scopes{$Subnets[$i]}{leaseduration} = hex($SLeaseDuration[0]);
+ last;
+ };
+ die "This program does not recognize subnet option \#$SubnetOptionsList[$j] yet!\n"
+ }
+ } else {
+ die "Unable to obtain option SubnetOptionsList[$j] from $Subnets[$i], most likely a registry problem!\n"
+ }
+ }
+ print "\n";
+ }
+
+ return %Scopes;
+}
+
+######################################################################
+sub FindInclusionRanges ($$@) {
+ my ($StartAddress, $EndAddress, @ExclusionRanges) = @_;
+# Purpose: to calculate and return the DHCP inclusion ranges out of
+# data provided by the NT4 DHCP server
+# input: $StartAddress:
+# $EndAddress:
+# @ExclusionRanges
+# output: none
+# return: An arry of IP address pair representing the inclusion ranges
+# in the native registry format.
+#
+
+ my ($SA, $EA, @ER);
+ $SA = unpack("L", $StartAddress);
+ $EA = unpack("L", $EndAddress);
+ @ER = @ExclusionRanges;
+ for (my $i=0; $i<=$#ER; $i++) {
+ $ER[$i] = unpack ("L", $ER[$i]);
+ }
+
+ my @InclusionRanges;
+
+
+ $InclusionRanges[0] = $SA;
+ $InclusionRanges[1] = $EA;
+
+ for (my $i=0; $i<=$#ER; $i+=2) {
+ if ($ER[$i] == $InclusionRanges[$#InclusionRanges-1]) {
+ $InclusionRanges[$#InclusionRanges-1] = $ER[$i+1] + 1;
+ }
+ if ($ER[$i] > $InclusionRanges[$#InclusionRanges-1]) {
+ $InclusionRanges[$#InclusionRanges] = $ER[$i]-1;
+ }
+ if (($ER[$i+1] > $InclusionRanges[$#InclusionRanges]) &&
+ ($ER[$i+1] != $EA)) {
+ $InclusionRanges[$#InclusionRanges+1] = $ER[$i+1] + 1;
+ $InclusionRanges[$#InclusionRanges+1] = $EA;
+ }
+ if ($InclusionRanges[$#InclusionRanges] < $InclusionRanges[$#InclusionRanges-1]) {
+ $#InclusionRanges -= 2;
+ }
+ }
+
+ for (my $i=0; $i<=$#InclusionRanges; $i++) {
+ $InclusionRanges[$i] = pack("L", $InclusionRanges[$i]);
+ # print "Inclusion: ", Registry::ExtractIp($InclusionRanges[$i]), "\n";
+ }
+ return @InclusionRanges;
+}
+
+####################################################################
+sub GetSuperScope ($) {
+ my ($Server) = @_;
+ my (%SuperScopes);
+#
+# purpose: gets the Superscope list from the given server
+# input:
+# $Server: string of the valid IP address or name of the NT4 server
+# ouput: none
+# return:
+# %SuperScopes: hash of array subnets with the following data structure
+# $SuperScopes{<SuperscopeName>} => array of sunbets
+#
+ my (@SuperScopeNames, @SCSubnetList);
+
+ print "Getting Superscope list: ";
+ if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\SuperScope", \@SuperScopeNames)) {
+ for (my $i=0; $i<=$#SuperScopeNames; $i++) {
+ print ".";
+ if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\SuperScope\\$SuperScopeNames[$i]", \@SCSubnetList)) {
+ $SuperScopes{$SuperScopeNames[$i]} = [@SCSubnetList];
+ }
+ }
+ print "\n";
+ }
+
+ return %SuperScopes;
+}
+
+####################################################################
+sub GetGlobalOptions($) {
+ my ($Server) = @_;
+ my (%GlobalOptions);
+# purpose: to return NT4 server's global scope configuration
+# input:
+# $Server: string of the valid IP or name of the NT4 server
+# output: none
+# return:
+# %GlobalOptions: hash of hash of various data types to be returned of the
+# following data structure
+# $GlobalOptions{routers} => array of IP address strings
+# $GlobalOptions{dnses} => array of IP address/name string
+# $GlobalOptions{domain} > string
+# $GlobalOptions{broadcast} => string
+# $GlobalOptions{winses} => array of IP addresses/name string
+# $GlobalOptions{winstype} => integer
+
+ my ($RegVal, @temp, @GlobalOptionValues);
+
+ print "Getting Global Options: ";
+ if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\GlobalOptionValues", \@GlobalOptionValues)) {
+ die "Unable to obtain GlobalOptionValues";
+ }
+
+ for (my $i=0; $i<=$#GlobalOptionValues; $i++) {
+ print ".";
+ if (Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\configuration\\globaloptionvalues\\$GlobalOptionValues[$i]\\optionvalue", \$RegVal)) {
+ die "Unable to retrive global option $GlobalOptionValues[$i]\n";
+ }
+
+
+ for ($GlobalOptionValues[$i]) {
+ /003/ and do {
+ @temp=Registry::ExtractOptionIps($RegVal);
+ $GlobalOptions{routers} = [@temp];
+ last;
+ };
+ /006/ and do {
+ # DNS Servers
+ @temp = Registry::ExtractOptionIps($RegVal);
+ for (my $d=0; $d<=$#temp; $d++) {
+ my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $temp[$d])), &AF_INET);
+ $GlobalOptions{dnses}[$d] = $ipname ? $ipname : $temp[$d];
+ }
+ last;
+ };
+ /015/ and do {
+ # Domain Name
+ @temp = Registry::ExtractOptionStrings($RegVal);
+ $GlobalOptions{domain} = $temp[0];
+ last;
+ };
+ /028/ and do {
+ # broadcast address
+ @temp = Registry::ExtractOptionIps($RegVal);
+ $GlobalOptions{broadcast} = $temp[0];
+ last;
+ };
+ /044/ and do {
+ # WINS Servers
+ @temp = Registry::ExtractOptionIps ($RegVal);
+ $GlobalOptions{winses} = [@temp];
+ for (my $w=0; $w<=$#temp; $w++) {
+ my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $temp[$w])), &AF_INET);
+ $GlobalOptions{winses}[$w] = $ipname ? $ipname : $temp[$w];
+ }
+ last;
+ };
+ /046/ and do {
+ # NETBIOS node type
+ @temp = Registry::ExtractOptionHex($RegVal);
+ $GlobalOptions{winstype} = hex($temp[0]);
+ last;
+ };
+ die "This program does not recgonize global option \#$GlobalOptionValues[$i] yet!\n"
+ }
+ }
+ print "\n";
+
+ return %GlobalOptions;
+}