1#set ts=3 2# 3# ms2isc.pl 4# MS NT4 DHCP to ISC DHCP Configuration Migration Tool 5# 6# Author: Shu-Min Chang 7# 8# Copyright(c) 2003 Intel Corporation. All rights reserved 9# 10# Redistribution and use in source and binary forms, with or without 11# modification, are permitted provided that the following conditions are met: 12# 13# 1. Redistributions of source code must retain the above copyright notice, 14# this list of conditions and the following disclaimer. 15# 2. Redistributions in binary form must reproduce the above copyright notice 16# this list of conditions and the following disclaimer in the documentation 17# and/or other materials provided with the distribution 18# 3. Neither the name of Intel Corporation nor the names of its contributors 19# may be used to endorse or promote products derived from this software 20# without specific prior written permission. 21# 22# THIS SOFTWARE IS PROVIDED BY THE INTEL CORPORATION AND CONTRIBUTORS "AS IS" 23# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25# ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE 26# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL EXEMPLARY, OR 27# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO PROCUREMENT OF SUBSTITUE 28# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31# OF THE USE OF THIS SOFTWARE, EVEN IF ADVICED OF THE POSSIBILITY OF SUCH 32# DAMAGE. 33 34use strict; 35use Socket; 36use Getopt::Std; 37use Filehandle; 38use Registry; # Custom Perl Module to make Registry access easier. 39 40my $usage = << 'ENDOFHELP'; 41 42Purpose: A Perl Script converting MS NT4 DHCP configuration to ISC DHCP3 43configuration file by reading NT4's registry. 44 45Requires: Registry.pm and ActiveState 5.6.0 46 47Usage: $ARGV -s <Srv> -o <Out> [-p <Pri> [-k <key>]] [-f <Fo>] 48 49 <Srv> Server IP or name for NT4 DHCP server to fetch the configuration from. 50 <Out> Output filename for the configuration file. 51 <Pri> Primary DNS server name for sending the dynamic DNS update to. 52 <Key> Key name for use in updating the dynamic DNS zone. 53 <Fo> Failover peer name shared with the DHCP partner. 54 55Essentially the <Srv> needs to be an NT4 (3.x should work but not tested) which 56you should have registry read access to. You must run this script from a 57Windows machine because of the requirement to access the registry. 58 59The <Pri> is optional parameter for desginating the dynamic DNS update if 60missing then the "zone" section of the declaration will be skipped. The <Key> 61is needed if you've configured your DNS zone with a key, in addition, you'll 62need to define that key in this DHCP configuration file elsewhere manually, 63read the DHCP Handbook to figure out what you need to define. 64 65The <Fo> specifies the fail-over peer name in the pool section, you'll need to 66define additional detail elsewhere manually, again read the DHCP handbook. 67 68NOTE: the program only knows of the following global and subnet options: 69 3, 6, 15, 28, 44, and 46 70 71 If it runs into options other than the known ones, it will quit. You 72 may fix this by modifying the following procedures: 73 GetGlobalOptions 74 GetScopes 75 PrintSubnetConfig 76 77 In addition, the resulting subnets configuration will have the "deny 78 dynamic bootp clients" you should take them out if that's not what you 79 want :). 80 81 Finally, as the parameter structures implied, it is assumed that you 82 want the same zone primary and update key for all zones and that the 83 same failover is to be applied to all the pools. Furthermore the 84 subnet zones are all assumed to be class C delineated, but if you 85 happend to be delegated at the class B level, this will work fine too. 86 87Author: Shu-Min Chang <smchang@yahoo.com> 88 89Copyright: Please read the top of the source code 90 91Acknowledgement: 92 Brian L. King for coding help, Douglas A. Darrah for testing, and James E. 93Pressley for being the DHCP reference book :). 94 95Usage: $ARGV -s <Srv> -o <Out> [-p <Pri> [-k <key>]] [-f <Fo>] 96 97Version: 1.0.1 98 99ENDOFHELP 100 101###################### Begin Main Program #################################### 102 103 my (%opts, %GlobalOptions, %SuperScopes, %Scopes); 104 105 ### Get parameters and make sure that they meet the require/optoinal criteria 106 getopts('s:o:p:k:f:', \%opts) or die $usage; 107 ($opts{s} and $opts{o}) or die $usage; 108 if ($opts{k}) { $opts{p} or die $usage; } 109 110 ### Read all the registry stuff into the memory 111 %GlobalOptions = GetGlobalOptions($opts{s}); 112 %SuperScopes = GetSuperScope($opts{s}); 113 %Scopes = GetScopes ($opts{s}); 114 115 ### Process and print out to the output file 116 my ($outfile, $i, $j, @Domains); 117 118 $outfile = new FileHandle "> $opts{o}"; 119 if (!defined $outfile) { 120 die "Can't open file: $opts{o}: $!"; 121 } 122 123 for $i (keys %SuperScopes) { 124 print $outfile "\n##############################################################\n"; 125 my ($Scopename) = $i; 126 $Scopename =~ s/ //g; 127 print $outfile "shared-network $Scopename {\n"; 128 foreach $j (@{$SuperScopes{$i}}) { 129 PrintSubnetConfig($outfile, \%GlobalOptions, \%{$Scopes{$j}}, $j, "\t", $opts{f}); 130 InsertIfUnique (\@Domains, $Scopes{$j}{domain}) if exists $Scopes{$j}{domain}; 131 delete $Scopes{$j}; 132 } 133 print $outfile "}\n"; 134 if ($opts{p} or $opts{k}) { 135 foreach $j (@{$SuperScopes{$i}}) { 136 PrintSubnetUpdate($outfile, $j, $opts{p}, $opts{k}); 137 } 138 } 139 } 140 141 for $i (keys %Scopes) { 142 print $outfile "\n##############################################################\n"; 143 PrintSubnetConfig($outfile, \%GlobalOptions, \%{$Scopes{$i}}, $i, "", $opts{f}); 144 if ($opts{p} or $opts{k}) { PrintSubnetUpdate($outfile, $i, $opts{p}, $opts{k}); } 145 InsertIfUnique (\@Domains, $Scopes{$i}{domain}) if exists $Scopes{$i}{domain}; 146 } 147 148 if ($opts{p} or $opts{k}) { 149 InsertIfUnique (\@Domains, $GlobalOptions{domain}) if exists $GlobalOptions{domain}; 150 for $i (@Domains) { 151 PrintDomainUpdate($outfile, $i, $opts{p}, $opts{k}); 152 } 153 } 154 155 undef ($outfile); 156 print "Done.\n"; 157 exit(); 158 159################################## End Main Program ########################### 160 161 162 163 164 165###################################################################### 166sub InsertIfUnique ($$) { 167 my ($Array, $data) = @_; 168# purpose: insert $data into array @{$Array} iff the data is not in there yet 169# input: 170# $data: scalar data to be added to the @{$Array} if unique 171# $Array: reference of the Array to compare the uniqueness of the $data 172# output: 173# $Array: reference of the array with the resulting array. 174# return: none 175 176 my ($i); 177 178 for ($i=0; $i<=$#{$Array} && ${$Array}[$i] ne $data; $i++) { } 179 180 if ($i > $#{$Array}) { 181 ${$Array}[$i] = $data; 182 } 183} 184###################################################################### 185sub PrintDomainUpdate ($$$$) { 186 my ($outfile, $Domain, $DDNSServer, $key) = @_; 187# purpose: print out the foward domain zone update declaration 188# input: 189# $outfile: filehandle of the file to write the output to 190# $Domain: a string representing the forward domain 191# $DDNSServer: a string of the DNS server accepting the DDNS update 192# $key: a string representing the key used to update the zone 193# output: none 194# return: none 195# 196 197 print $outfile "zone $Domain {\n"; 198 print $outfile "\tprimary $DDNSServer;\n"; 199 !$key or print $outfile "\tkey $key;\n"; 200 print $outfile "}\n"; 201 202} 203###################################################################### 204sub PrintSubnetUpdate ($$$$) { 205 my ($outfile, $Subnet, $DDNSServer, $key) = @_; 206# purpose: print out the reverse domain zone update declaration 207# input: 208# $outfile: filehandle of the file to write the output to 209# $Subnet: a string representing the subnet in the form 1.2.3.4 210# $DDNSServer: a string of the DNS server accepting the DDNS update 211# $key: a string representing the key used to update the zone 212# output: none 213# return: none 214# 215 216 my ($Reverse); 217 218 $_ = join (".", reverse(split(/\./, $Subnet))); 219 m/\d*\.(.*)/; 220 $Reverse = $1; 221 print $outfile "zone $Reverse.in-addr.arpa. {\n"; 222 print $outfile "\tprimary $DDNSServer;\n"; 223 !$key or print $outfile "\tkey $key;\n"; 224 print $outfile "}\n"; 225 226} 227###################################################################### 228sub PrintSubnetConfig ($$$$$$) { 229 my ($outfile, $GlobalOptions, $Scope, $Subnet, $prefix, $failover) = @_; 230# purpose: print out the effective scope configuration for one subnet as 231# derived from the global and scope options. 232# input: 233# $outfile: filehandle of the file to write the output to 234# $GlobalOptions: refernce to the hashed variable from GetGlobalOptions 235# $Scopes: reference to the hashed variable of the subnet in interest 236# $Subnet: string variable of the subnet being processed 237# $prefix: string to be printed before each line (designed for tab) 238# $failover: string to be used for the "failover peer" line 239# output: none 240# return: none 241# 242 my ($pound) = ( ${$Scope}{disable}? "#".$prefix : $prefix); 243 print $outfile $pound, "subnet $Subnet netmask ${$Scope}{mask} {\n"; 244 print $outfile "$prefix# Name: ${$Scope}{name}\n"; 245 print $outfile "$prefix# Comment: ${$Scope}{comment}\n"; 246 if (exists ${$Scope}{routers}) { 247 print $outfile $pound, "\toption routers @{${$Scope}{routers}};\n"; 248 } elsif (exists ${$GlobalOptions}{routers}) { 249 print $outfile $pound, "\toption routers @{${$GlobalOptions}{routers}};\t# NOTE: obtained from global option, bad practice detected\n"; 250 } else { 251 print $outfile "### WARNING: No router was found for this subnet!!! ##########\n"; 252 } 253 254 if (exists ${$Scope}{dnses}) { 255 print $outfile $pound, "\toption domain-name-servers ", join(",", @{${$Scope}{dnses}}), ";\n"; 256 } elsif (exists ${$GlobalOptions}{dnses}) { 257 print $outfile $pound, "\toption domain-name-servers ", join(",", @{${$GlobalOptions}{dnses}}), ";\n"; 258 } 259 260 if (exists ${$Scope}{domain}) { 261 print $outfile $pound, "\toption domain-name \"${$Scope}{domain}\";\n"; 262 } elsif (exists ${$GlobalOptions}{domain}) { 263 print $outfile $pound, "\toption domain-name \"${$GlobalOptions}{domain}\";\n"; 264 } 265 266 if (exists ${$Scope}{broadcast}) { 267 print $outfile $pound, "\toption broadcast-address ${$Scope}{broadcast};\n"; 268 } elsif (exists ${$GlobalOptions}{broadcast}) { 269 print $outfile $pound, "\toption broadcast-address ${$GlobalOptions}{broadcast};\n"; 270 } 271 272 if (exists ${$Scope}{winses}) { 273 print $outfile $pound, "\toption netbios-name-servers ", join(",", @{${$Scope}{winses}}), ";\n"; 274 } elsif (exists ${$GlobalOptions}{winses}) { 275 print $outfile $pound, "\toption netbios-name-servers ", join(",", @{${$GlobalOptions}{winses}}), ";\n"; 276 } 277 278 if (exists ${$Scope}{winstype}) { 279 print $outfile $pound, "\toption netbios-node-type ${$Scope}{winstype};\n"; 280 } elsif (exists ${$GlobalOptions}{winstype}) { 281 print $outfile $pound, "\toption netbios-node-type ${$GlobalOptions}{winstype};\n" 282 } 283 284 print $outfile $pound, "\tdefault-lease-time ${$Scope}{leaseduration};\n"; 285 print $outfile $pound, "\tpool {\n"; 286 for (my $r=0; $r<=$#{${$Scope}{ranges}}; $r+=2) { 287 print $outfile $pound, "\t\trange ${$Scope}{ranges}[$r] ${$Scope}{ranges}[$r+1];\n"; 288 } 289 !$failover or print $outfile $pound, "\t\tfailover peer \"$failover\";\n"; 290 print $outfile $pound, "\t\tdeny dynamic bootp clients;\n"; 291 print $outfile $pound, "\t}\n"; 292 print $outfile $pound, "}\n"; 293} 294 295###################################################################### 296sub GetScopes ($) { 297 my ($Server) = @_; 298 my (%Scopes); 299# purpose: to return NT4 server's scope configuration 300# input: 301# $Server: string of the valid IP or name of the NT4 server 302# output: none 303# return: 304# %Scope: hash of hash of hash of various data types to be returned of the 305# following data structure 306# $Scope{<subnet>}{disable} => boolean 307# $Scope{<subnet>}{mask} => string (e.g. "1.2.3.255") 308# $Scope{<subnet>}{name} => string (e.g "Office Subnet #1") 309# $Scope{<subnet>}{comment} => string (e.g. "This is a funny subnet") 310# $Scope{<subnet>}{ranges} => array of paired inclusion IP addresses 311# (e.g. "1.2.3.1 1.2.3.10 1.2.3.100 10.2.3.200 312# says that we have 2 inclusion ranges of 313# 1-10 and 100-200) 314# $Scopes{<subnet>}{routers} => array of IP address strings 315# $Scopes{<subnet>}{dnses} => array of IP address/name string 316# $Scopes{<subnet>}{domain} > string 317# $Scopes{<subnet>}{broadcast} => string 318# $Scopes{<subnet>}{winses} => array of IP addresses/name string 319# $Scopes{<subnet>}{winstype} => integer 320# $Scopes{<subnet>}{leaseduration} => integer 321 322 my ($RegVal, @Subnets, @Router, $SubnetName, $SubnetComment, @SubnetOptions, @SRouter, @SDNSServers, @SDomainname, @SWINSservers, @SNetBIOS, @SLeaseDuration, @SSubnetState, @SExclusionRanges, @SSubnetAddress, @SSubnetMask, @SFirstAddress, $SStartAddress, $SEndAddress, @InclusionRanges, @SBroadcastAddress); 323 324 print "Getting list of subnets\n"; 325 if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets", \@Subnets)) { 326 die "Unable to obtain a list of subnets from the server!\n"; 327 } 328 329 for (my $i=0; $i<=$#Subnets; $i++) { 330 print "\t Fetching Subnet $Subnets[$i] (",$i+1, "/", $#Subnets+1, "): "; 331 332 print "."; 333 if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges", \@SFirstAddress)) { 334 # Don't know why MS has a tree for this, but as far 335 # as I can tell, only one subtree will ever come out of 336 # this, so I'm skipping the 'for' loop 337 338 print "."; 339 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges\\$SFirstAddress[0]\\StartAddress", \$RegVal)) { 340 $SStartAddress = $RegVal; 341 } 342 print "."; 343 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\IpRanges\\$SFirstAddress[0]\\EndAddress", \$RegVal)) { 344 $SEndAddress = $RegVal; 345 } 346# print "\n\tInclusion Range: ", Registry::ExtractIp($SStartAddress), " - ", Registry::ExtractIp($SEndAddress),"\n"; 347 348 } else { 349 die "\n\n# Error Getting Inclusion Range FirstAddress!!!\n\n"; 350 } 351 352 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\ExcludedIpRanges", \$RegVal)) { 353 @SExclusionRanges = Registry::ExtractExclusionRanges($RegVal); 354 355# for (my $j=2; $j<=$#SExclusionRanges; $j+=2) { 356# if (unpack("L",$SExclusionRanges[$j]) < unpack("L",$SExclusionRanges[$j-2])) { 357# print ("\n******** Subnet exclusion ranges out of order ********\n"); 358# } 359# } 360 361 @SExclusionRanges = sort(@SExclusionRanges); 362 363# print "\n\tExclusion Ranges: "; 364# for (my $j=0; $j<=$#SExclusionRanges; $j+=2) { 365# print "\n\t\t",Registry::ExtractIp($SExclusionRanges[$j])," - ",Registry::ExtractIp($SExclusionRanges[$j+1]); 366# } 367 368 } 369 @InclusionRanges = FindInclusionRanges ($SStartAddress, $SEndAddress, @SExclusionRanges); 370 371 print "."; 372 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetName", \$RegVal)) { 373 $SubnetName = $RegVal; 374# print "\n\tSubnetName: $SubnetName"; 375 } 376 377 print "."; 378 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetComment", \$RegVal)) { 379 $SubnetComment = $RegVal; 380# print "\n\tSubnetComment: $SubnetComment"; 381 } 382 print "."; 383 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetAddress", \$RegVal)) { 384 @SSubnetAddress = Registry::ExtractIp($RegVal); 385# print "\n\tSubnetAddress: $SSubnetAddress[0]"; 386 } 387 print "."; 388 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetMask", \$RegVal)) { 389 @SSubnetMask = Registry::ExtractIp($RegVal); 390# print "\n\tSubnetMask: $SSubnetMask[0]"; 391 } 392 393 print "."; 394 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetState", \$RegVal)) { 395 @SSubnetState = Registry::ExtractHex ($RegVal); 396# print "\n\tSubnetState = $SSubnetState[0]"; 397 } 398 399 $Scopes{$Subnets[$i]}{disable} = hex($SSubnetState[0]) ? 1 : 0; 400 $Scopes{$Subnets[$i]}{mask} = $SSubnetMask[0]; 401 $Scopes{$Subnets[$i]}{name} = $SubnetName; 402 $Scopes{$Subnets[$i]}{comment} = $SubnetComment; 403 for (my $r=0; $r<=$#InclusionRanges; $r++) { 404 $Scopes{$Subnets[$i]}{ranges}[$r] = Registry::ExtractIp($InclusionRanges[$r]); 405 } 406 407################## Get scope options 408 409 my (@SubnetOptionsList); 410 411 print "\n\t\tOptions:"; 412 if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetOptions", \@SubnetOptionsList)) { 413 die "Unable to get subnet options list for $Subnets[$i]!\n"; 414 } 415 416 for (my $j=0; $j<=$#SubnetOptionsList; $j++) { 417 print "."; 418 if (!Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\Subnets\\$Subnets[$i]\\SubnetOptions\\$SubnetOptionsList[$j]\\OptionValue", \$RegVal)) { 419 for ($SubnetOptionsList[$j]) { 420 /003/ and do { 421# @SRouter = Registry::ExtractOptionIps($RegVal); 422 $Scopes{$Subnets[$i]}{routers} = [Registry::ExtractOptionIps($RegVal)]; 423 last; 424 }; 425 /006/ and do { 426 @SDNSServers = Registry::ExtractOptionIps($RegVal); 427 for (my $d=0; $d<=$#SDNSServers; $d++) { 428 my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $SDNSServers[$d])), &AF_INET); 429 $Scopes{$Subnets[$i]}{dnses}[$d] = $ipname ? $ipname : $SDNSServers[$d]; 430 } 431 last; 432 }; 433 /015/ and do { 434 @SDomainname = Registry::ExtractOptionStrings($RegVal); 435 $Scopes{$Subnets[$i]}{domain} = $SDomainname[0]; 436 last; 437 }; 438 /028/ and do { 439 @SBroadcastAddress = Registry::ExtractOptionIps($RegVal); 440 $Scopes{$Subnets[$i]}{broadcast} = $SBroadcastAddress[0]; 441 last; 442 }; 443 /044/ and do { 444 @SWINSservers = Registry::ExtractOptionIps($RegVal); 445 for (my $w=0; $w<=$#SWINSservers; $w++) { 446 my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $SWINSservers[$w])), &AF_INET); 447 $Scopes{$Subnets[$i]}{winses}[$w] = $ipname ? $ipname : $SWINSservers[$w]; 448 } 449 last; 450 }; 451 /046/ and do { 452 @SNetBIOS = Registry::ExtractOptionHex($RegVal); 453 $Scopes{$Subnets[$i]}{winstype} = hex($SNetBIOS[0]); 454 last; 455 }; 456 /051/ and do { 457 @SLeaseDuration = Registry::ExtractOptionHex($RegVal); 458 $Scopes{$Subnets[$i]}{leaseduration} = hex($SLeaseDuration[0]); 459 last; 460 }; 461 die "This program does not recognize subnet option \#$SubnetOptionsList[$j] yet!\n" 462 } 463 } else { 464 die "Unable to obtain option SubnetOptionsList[$j] from $Subnets[$i], most likely a registry problem!\n" 465 } 466 } 467 print "\n"; 468 } 469 470 return %Scopes; 471} 472 473###################################################################### 474sub FindInclusionRanges ($$@) { 475 my ($StartAddress, $EndAddress, @ExclusionRanges) = @_; 476# Purpose: to calculate and return the DHCP inclusion ranges out of 477# data provided by the NT4 DHCP server 478# input: $StartAddress: 479# $EndAddress: 480# @ExclusionRanges 481# output: none 482# return: An arry of IP address pair representing the inclusion ranges 483# in the native registry format. 484# 485 486 my ($SA, $EA, @ER); 487 $SA = unpack("L", $StartAddress); 488 $EA = unpack("L", $EndAddress); 489 @ER = @ExclusionRanges; 490 for (my $i=0; $i<=$#ER; $i++) { 491 $ER[$i] = unpack ("L", $ER[$i]); 492 } 493 494 my @InclusionRanges; 495 496 497 $InclusionRanges[0] = $SA; 498 $InclusionRanges[1] = $EA; 499 500 for (my $i=0; $i<=$#ER; $i+=2) { 501 if ($ER[$i] == $InclusionRanges[$#InclusionRanges-1]) { 502 $InclusionRanges[$#InclusionRanges-1] = $ER[$i+1] + 1; 503 } 504 if ($ER[$i] > $InclusionRanges[$#InclusionRanges-1]) { 505 $InclusionRanges[$#InclusionRanges] = $ER[$i]-1; 506 } 507 if (($ER[$i+1] > $InclusionRanges[$#InclusionRanges]) && 508 ($ER[$i+1] != $EA)) { 509 $InclusionRanges[$#InclusionRanges+1] = $ER[$i+1] + 1; 510 $InclusionRanges[$#InclusionRanges+1] = $EA; 511 } 512 if ($InclusionRanges[$#InclusionRanges] < $InclusionRanges[$#InclusionRanges-1]) { 513 $#InclusionRanges -= 2; 514 } 515 } 516 517 for (my $i=0; $i<=$#InclusionRanges; $i++) { 518 $InclusionRanges[$i] = pack("L", $InclusionRanges[$i]); 519 # print "Inclusion: ", Registry::ExtractIp($InclusionRanges[$i]), "\n"; 520 } 521 return @InclusionRanges; 522} 523 524#################################################################### 525sub GetSuperScope ($) { 526 my ($Server) = @_; 527 my (%SuperScopes); 528# 529# purpose: gets the Superscope list from the given server 530# input: 531# $Server: string of the valid IP address or name of the NT4 server 532# ouput: none 533# return: 534# %SuperScopes: hash of array subnets with the following data structure 535# $SuperScopes{<SuperscopeName>} => array of sunbets 536# 537 my (@SuperScopeNames, @SCSubnetList); 538 539 print "Getting Superscope list: "; 540 if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\SuperScope", \@SuperScopeNames)) { 541 for (my $i=0; $i<=$#SuperScopeNames; $i++) { 542 print "."; 543 if (!Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\SuperScope\\$SuperScopeNames[$i]", \@SCSubnetList)) { 544 $SuperScopes{$SuperScopeNames[$i]} = [@SCSubnetList]; 545 } 546 } 547 print "\n"; 548 } 549 550 return %SuperScopes; 551} 552 553#################################################################### 554sub GetGlobalOptions($) { 555 my ($Server) = @_; 556 my (%GlobalOptions); 557# purpose: to return NT4 server's global scope configuration 558# input: 559# $Server: string of the valid IP or name of the NT4 server 560# output: none 561# return: 562# %GlobalOptions: hash of hash of various data types to be returned of the 563# following data structure 564# $GlobalOptions{routers} => array of IP address strings 565# $GlobalOptions{dnses} => array of IP address/name string 566# $GlobalOptions{domain} > string 567# $GlobalOptions{broadcast} => string 568# $GlobalOptions{winses} => array of IP addresses/name string 569# $GlobalOptions{winstype} => integer 570 571 my ($RegVal, @temp, @GlobalOptionValues); 572 573 print "Getting Global Options: "; 574 if (Registry::GetRegSubkeyList ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\Configuration\\GlobalOptionValues", \@GlobalOptionValues)) { 575 die "Unable to obtain GlobalOptionValues"; 576 } 577 578 for (my $i=0; $i<=$#GlobalOptionValues; $i++) { 579 print "."; 580 if (Registry::GetRegKeyVal ("\\\\$Server\\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DHCPServer\\configuration\\globaloptionvalues\\$GlobalOptionValues[$i]\\optionvalue", \$RegVal)) { 581 die "Unable to retrive global option $GlobalOptionValues[$i]\n"; 582 } 583 584 585 for ($GlobalOptionValues[$i]) { 586 /003/ and do { 587 @temp=Registry::ExtractOptionIps($RegVal); 588 $GlobalOptions{routers} = [@temp]; 589 last; 590 }; 591 /006/ and do { 592 # DNS Servers 593 @temp = Registry::ExtractOptionIps($RegVal); 594 for (my $d=0; $d<=$#temp; $d++) { 595 my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $temp[$d])), &AF_INET); 596 $GlobalOptions{dnses}[$d] = $ipname ? $ipname : $temp[$d]; 597 } 598 last; 599 }; 600 /015/ and do { 601 # Domain Name 602 @temp = Registry::ExtractOptionStrings($RegVal); 603 $GlobalOptions{domain} = $temp[0]; 604 last; 605 }; 606 /028/ and do { 607 # broadcast address 608 @temp = Registry::ExtractOptionIps($RegVal); 609 $GlobalOptions{broadcast} = $temp[0]; 610 last; 611 }; 612 /044/ and do { 613 # WINS Servers 614 @temp = Registry::ExtractOptionIps ($RegVal); 615 $GlobalOptions{winses} = [@temp]; 616 for (my $w=0; $w<=$#temp; $w++) { 617 my ($ipname, $rest) = gethostbyaddr(pack("C4", split(/\./, $temp[$w])), &AF_INET); 618 $GlobalOptions{winses}[$w] = $ipname ? $ipname : $temp[$w]; 619 } 620 last; 621 }; 622 /046/ and do { 623 # NETBIOS node type 624 @temp = Registry::ExtractOptionHex($RegVal); 625 $GlobalOptions{winstype} = hex($temp[0]); 626 last; 627 }; 628 die "This program does not recgonize global option \#$GlobalOptionValues[$i] yet!\n" 629 } 630 } 631 print "\n"; 632 633 return %GlobalOptions; 634} 635