http://qs321.pair.com?node_id=140380
Category: NT Admin
Author/Contact Info DaveRoberts@iname.com
Description: This script is used to improve the reliability of trusts between NT domains. The lmhosts file is used to identify domain controllers, and is referred to by the NT operating system when building and maintaining trusts - using computers by order of occurance in the lmhosts file. This script takes a distributed copy of a standard lmhosts file and re-writes this to the normal lmhosts location (%SystemRoot%/system32/drivers/etc) re-ordering the entries in approximate order of network responsiveness. The intended effect of this is to ensure that trusts are maintained with computers that are i) alive on the network and ii) relativly close
use Net::hostent;
use Net::Ping;
use Socket;
use Win32;
use Win32::TieRegistry (Delimiter=>"/", ArrayValues=>0,
  qw(REG_DWORD REG_SZ REG_MULTI_SZ));

use constant TRUE     => 1;
use constant FALSE     => 0;

my($p) = Net::Ping->new("icmp");

# Identify OS directories

$Etc = Win32::ExpandEnvironmentStrings("%SystemRoot%/System32/Drivers/
+Etc");
chmod(0666,"$Etc/Lmhosts") || print "failed to make $Etc/Lmhosts write
+able\n";

my($lmhOrig)="c:/tmp/lmhosts";
my($myname)=uc(Win32::NodeName());
my($timeout) = 6;
my($timestep) = 0.1;

my(%ip,%pl,$myip,$mynm);
open(LMH,"$lmhOrig")||die("Unable to open $lmhOrig\n");
foreach (<LMH>) {
  chop;
#  print "LMH: $_\n";
  if ( /(\d+\.\d+\.\d+\.\d+)\s+([\da-z]+)\s(.*)?/i ) {
    
    my($cip)   = $1;
    my($cname) = uc($2);
    my($preld) = $3;
    $preld =~ s/^\s+//;
    #printf "** %-20s %-20s %s\n",$cip,$cname,$preld;
    $ip{$cname}=$cip;  # Array of network addresses indexed by compute
+r name
    $pl{$cname}=$preld;
    if ( $cname eq $myname ) {
      $myip = $cip;
    }
  }
}
close LMH;

unless ($myip) {
  unless ($h = gethost($me)) {
    warn "$0: no such host: $me\n";
    exit;
  }
  if ( @{$h->addr_list} > 1 ) {
    printf "\taddress is [%s]\n", inet_ntoa($h->addr);
    $myip = inet_ntoa($h->addr);
    warn "$0 - this computer has multiple addresses - using $myip\n";
    } else {
    $myip = inet_ntoa($h->addr);
  }
}

print "\nComputer Name  : $myname\n";
print "Network Address: $myip\n\n";

# Identify local host address and netmask
unless ($h = gethost($myname)) {
  warn "$0: no such host: $myname\n";
  exit;
}

# Open registry

$NetBTKey = $Registry->{"//" . $me . "/LMachine/SYSTEM/CurrentControlS
+et/Services/NetBT/"} ||
die "\n  Failed to connect to registry on $me\n\n";

$SvcKey = $Registry->{"//" . $me . "/LMachine/SYSTEM/CurrentControlSet
+/Services/"} ||
die "\n  Failed to connect to registry on $me\n\n";


# *********************************************
# Get network adapters
# *********************************************
@Adapters = grep(!/^Ndis/i, keys %{$NetBTKey->{"Adapters/"}});
$AdapterCount = @Adapters;
# Sort adapters by Bind order
foreach $ServiceName (split(/\000/, $NetBindKey->{"Tcpip/Linkage/Bind"
+})) {
  $ServiceName =~ s/^\\device\\NetBT_//i;
  push(@AdaptersByBind, $ServiceName) if grep { /^$ServiceName\/$/ } @
+Adapters;
}
# Add non-bound adapters
foreach $ServiceName (@Adapters) {
  $ServiceName =~ s/\/$//;  # Remove trailing '/'s
  push(@AdaptersByBind, $ServiceName) if !grep { /^$ServiceName$/ } @A
+daptersByBind;
}

print "Network Adapters Identified   : @Adapters\n";
print "Network Adapters In Bind Order: @AdaptersByBind\n\n";

foreach $ServiceName (@AdaptersByBind) {

  #print "Adapter: $ServiceName\n";
  $NetBTaKey = "Adapters/" . $ServiceName . "/";
  $iFaceKey  = $ServiceName . "/Parameters/TCPIP/";
  $pEnableDHCP = hex($SvcKey->{$iFaceKey . "EnableDHCP"});
  print "EnableDHCP: $pEnableDHCP\n";
  if (! $pEnableDHCP) {
    $pIPAddress  = $SvcKey->{$iFaceKey  . "IPAddress"       };
    $pSubnetMask = $SvcKey->{$iFaceKey  . "SubnetMask"      };
    $pGateway    = $SvcKey->{$iFaceKey  . "DefaultGateway"  };
    $pWserverA   = $NetBTKey->{$NetBTaKey . "NameServer"      };
    $pWserverB   = $NetBTKey->{$NetBTaKey . "NameServerBackup"};
  }else{
    $pIPAddress  = $SvcKey->{$iFaceKey . "DhcpIPAddress"} ?         $S
+vcKey->{$iFaceKey . "DhcpIPAddress"} : "";
    $pSubnetMask = $SvcKey->{$iFaceKey . "DhcpSubnetMask"} ?        $S
+vcKey->{$iFaceKey . "DhcpSubnetMask"} : "";
    $pGateway    = $SvcKey->{$iFaceKey . "DhcpDefaultGateway"} ?    $S
+vcKey->{$iFaceKey . "DhcpDefaultGateway"} : "";
    $pWserverA   = $NetBTKey->{$NetBTaKey . "DhcpNameServer"} ?       
+$NetBTKey->{$NetBTaKey . "DhcpNameServer"} : "";
    $pWserverB   = $NetBTKey->{$NetBTaKey . "DhcpNameServerBackup"} ? 
+$NetBTKey->{$NetBTaKey . "DhcpNameServerBackup"} : "";
  }

  $pIPAddress  =~ s/([\.0-9]+)/$1/;
  if ($pIPAddress =~ /$myip/) {
    $mynm = $pSubnetMask;
    $mygw = $pGateway;
    $DNShostname   = $SvcKey->{"Tcpip/Parameters/Hostname"};
    $DNSdomain     = $SvcKey->{"Tcpip/Parameters/Domain"};
    $DNSnamservers = $SvcKey->{"Tcpip/Parameters/NameServer"};
    $DNSsearchlist = $SvcKey->{"Tcpip/Parameters/SearchList"};
    $WINSusedns    = hex($NetBTKey->{"Parameters/EnableDNS"});
    $WINSuselmhosts= hex($NetBTKey->{"Parameters/EnableLMHOSTS"});
    print " ********************************************\n";
    print " Adapter Selected:  $ServiceName\n";
    if ( $SvcKey->{"Tcpip/Linkage/Bind"} =~ /$ServiceName/i ) {
      print " ********************************************\n";
      print "   TCPIP EnableDHCP          = $pEnableDHCP\n";
      print "   TCPIP IPAddress           = $pIPAddress\n";
      print "   TCPIP SubnetMask          = $pSubnetMask\n";
      print "   TCPIP DefaultGateway      = $pGateway\n";
      print "\n";
      print "   DNS Hostname              = $DNShostname\n";
      print "   DNS Domain                = $DNSdomain\n";
      print "   DNS NameServer            = $DNSnameservers\n";
      print "   DNS SearchList            = $DNSsearchlist\n";
      print "\n";
      print "   WINS NameServer           = $pWserverA\n";
      print "   WINS NameServerBackup     = $pWserverB\n";
      print "   WINS EnableDNS            = $WINSusedns\n";
      print "   WINS EnableLMHOSTS        = $WINSuselmhosts\n";
      print " ********************************************\n";
      }else{
      print "Disabled in BIND\n";
    }
  }
}
#  Find the network number from local ip and netmask
my($ipa,$ipb,$ipc,$ipd) = split(/\./,$myip);
my $ip32 = ($ipa << 24) + ($ipb << 16) + ($ipc << 8) + $ipd;
my($nma,$nmb,$nmc,$nmd) = split(/\./,$mynm);
my $nm32 = ($nma << 24) + ($nmb << 16) + ($nmc << 8) + $nmd;
$mynw = ($ip32 & $nm32);
$MyNw = ($mynw & 0xFF);
$mynw=$mynw >> 8;
$MyNw = ($mynw & 0xFF) . '.' . $MyNw;
$mynw=$mynw >> 8;
$MyNw = ($mynw & 0xFF) . '.' . $MyNw;
$mynw=$mynw >> 8;
$MyNw = ($mynw & 0xFF) . '.' . $MyNw;

print "\nNetwork Address: $MyNw\n";
print "        Netmask: $mynm\n\n";

# Verify local default gateway is reachable within 3 seconds

unless ( $p->ping($mygw,3)){
  print "Local gateway $mygw is unreachable - quitting\n";
  exit;
}

my(@lm,@un); # Init output arrays
push (@lm,"# Local hosts");
# Put all hosts in local network first in the new lmhosts file
while (($name,$ip)=each %ip) {
  push (@lm,sprintf "%-15s %-12s %s",$ip{$name},$name,$pl{$name})
    if ( CheckIPSubnet($ip,$MyNw,$mynm) );
}

# Find unreachable hosts - and don't test again (makes iterative proce
+ss faster)
print "Identifying any unreachable hosts\n";
push (@un,"#");
push (@un,"# Hosts with a response over $timeout seconds");
while (($name,$ip)=each %ip) {
  next if ( grep {/$name/} @lm);  # Ignore any local hosts (alive or n
+ot)
  print "Testing $name ($ip)\n";
  push (@un,sprintf "%-15s %-12s %s",$ip{$name},$name,$pl{$name}) unle
+ss ( $p->ping($ip,$timeout) );
}

# Determine hosts in order of response time
for($t=$timestep;$t<=$timeout;$t+=$timestep) {
  print "# Testing network response with $t secs\n";
  my($no)=0;
  while (($name,$ip)=each %ip) {
    next if ( grep {/$name/} @lm);  # Ignore if host is already in the
+ new lmhosts file (@lm)
    next if ( grep {/$name/} @un);  # Ignore if host is already in the
+ unreachable lmhosts file (@un)
    print "Testing $name ($ip)\n";
    if ( $p->ping($ip,$t)) {
      push (@lm,"#") if ($no == 0);
      push (@lm,sprintf "# Hosts with a response under %.1f seconds",$
+t) if ($no == 0);
      push (@lm,sprintf "%-15s %-12s %s",$ip{$name},$name,$pl{$name});
      $no++;
    }
  }
}

push (@lm,@un); # Add unreachable lmhosts to end of new lmhosts file
      
open (LMH,">$Etc/Lmhosts")||die "Failed to open $Etc/Lmhosts for writi
+ng\n";
foreach (@lm){
  print "$_\n";
  print LMH "$_\n";
}
close LMH;
      
exit;
#*********************************************************************
+****************************
# CheckIPSubnet - Check if IP address is within entity subnet range
#*********************************************************************
+****************************
      sub CheckIPSubnet($$$) {
        my($ip, $nw, $sn)       = @_;
        my($ipa,$ipb,$ipc,$ipd) = split(/\./,$ip);
        my $ip32 = ($ipa << 24) + ($ipb << 16) + ($ipc << 8) + $ipd;
        my ($sn32);
        if ( $sn =~ /\d+\.\d+\.\d+\.\d+/ ) {
          my($sna,$snb,$snc,$snd) = split(/\./,$sn);
          $sn32 = ($sna << 24) + ($snb << 16) + ($snc << 8) + $snd;
          }elsif ( $sn =~ /^\d+$/ ) {
          $sn32=0;
          for($i=0;$i<$sn;$i++) {
            $sn32 = $sn32 | 1;
            $sn32 = $sn32 << 1;
          }
          $sn32 = $sn32 << (31-$sn);
        }
        my($nwa,$nwb,$nwc,$nwd) = split(/\./,$nw);
        my $nb32 = ($nwa << 24) + ($nwb << 16) + ($nwc << 8) + $nwd;
        my $nt32 = $nb32 | ($sn32 ^ "11111111111111111111111111111111"
+);
        return TRUE if (($ip32 > $nb32) && ($nt32 gt $ip32));
        return FALSE;
      }