Annotation of embedaddon/dhcp/contrib/ms2isc/ms2isc.pl, revision 1.1

1.1     ! misho       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: 
        !            34: use strict;
        !            35: use Socket;
        !            36: use Getopt::Std;
        !            37: use Filehandle;
        !            38: use Registry; # Custom Perl Module to make Registry access easier.
        !            39: 
        !            40: my $usage = << 'ENDOFHELP';
        !            41: 
        !            42: Purpose: A Perl Script converting MS NT4 DHCP configuration to ISC DHCP3 
        !            43: configuration file by reading NT4's registry.
        !            44: 
        !            45: Requires: Registry.pm and ActiveState 5.6.0
        !            46: 
        !            47: Usage: $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: 
        !            55: Essentially the <Srv> needs to be an NT4 (3.x should work but not tested) which
        !            56: you should have registry read access to.  You must run this script from a 
        !            57: Windows machine because of the requirement to access the registry.
        !            58: 
        !            59: The <Pri> is optional parameter for desginating the dynamic DNS update if
        !            60: missing then the "zone" section of the declaration will be skipped.  The <Key>
        !            61: is needed if you've configured your DNS zone with a key, in addition, you'll
        !            62: need to define that key in this DHCP configuration file elsewhere manually,
        !            63: read the DHCP Handbook to figure out what you need to define.
        !            64: 
        !            65: The <Fo> specifies the fail-over peer name in the pool section, you'll need to
        !            66: define additional detail elsewhere manually, again read the DHCP handbook.
        !            67: 
        !            68: NOTE: 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: 
        !            87: Author: Shu-Min Chang <smchang@yahoo.com>
        !            88: 
        !            89: Copyright: Please read the top of the source code
        !            90: 
        !            91: Acknowledgement:
        !            92:   Brian L. King for coding help, Douglas A. Darrah for testing, and James E.
        !            93: Pressley for being the DHCP reference book :).
        !            94: 
        !            95: Usage: $ARGV -s <Srv> -o <Out> [-p <Pri> [-k <key>]] [-f <Fo>]
        !            96: 
        !            97: Version: 1.0.1
        !            98: 
        !            99: ENDOFHELP
        !           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: ######################################################################
        !           166: sub 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: ######################################################################
        !           185: sub 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: ######################################################################
        !           204: sub 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: ######################################################################
        !           228: sub 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: ######################################################################
        !           296: sub 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: ######################################################################
        !           474: sub 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: ####################################################################
        !           525: sub 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: ####################################################################
        !           554: sub 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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>