#191973 - 2009-01-29 07:02 PM
Re: Finding the closest resource
[Re: Richard H. ]
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4402
Loc: New Jersey
Here's the UDF I created to query the SRV records. It's also useful for locating DC, PDC, GC and similar AD records. I'll post it to the UDF forum after further testing and possibly some feedback.
Glenn
;;
;;======================================================================
;;
;;FUNCTION GetResourceBySrv()
;;
;;ACTION Returns an array of SRV record data
;;
;;AUTHOR Glenn Barnas
;;
;;VERSION 1.0 / 2009/01/09
;;
;;SYNTAX GetResourceBySrv(IpAddr [, Short] [, Type])
;;
;;PARAMETERS IpAddr - REQUIRED, IP string of host to lookup. Can be null
;; if Short is true (IP is ignored)
;;
;; Short - OPTIONAL, Flag requesting short processing. Returns
;; the entire array instead of the matching hostname(s)
;; Short is forced true if a Type value is specified.
;;
;; Type - OPTIONAL, specifies the type of SRV record to return. The
;; default type is the custom record "_swdist._tcp" (easily changed)
;;
;;RETURNS Array of Arrays containing DNS SRV record data. Array format is:
;; Hostname, IP, Weight, Priority, Service_Port
;;
;; By default, the UDF returns SRV records of the type "_swdist._tcp". It
;; uses the Weight value as a CIDR netmasl value and only returns records
;; where the IpAddr argument is in the record's subnet. It also sorts the
;; data from most-specific to least specific subnet.
;;
;; If Short is True, all SRV record data is returned for external processing.
;; This is useful for obtaining other SRV record types.
;;
;;REMARKS In a general form, this UDF can return a set of DNS SRV records by
;; specifying a Type parameter. This is useful for locating specific
;; network resources, such as the PDC, all DCs, all LDAP servers, and so
;; forth. In this manner, only the Type parameter is significant, and the
;; UDF lends itself to many generic applications.
;;
;; In the target application, this UDF retrieves specific, custom
;; SRV records ("_swdist._tcp") which identify a hierarchy of file
;; server resources. There are three types of file server:
;; - Master, with a priority and weight of 0
;; - Secondary, with a priority of 1 and a weight of 1-31
;; - Slave, with a priority of 2 and a weight of 1-31
;; The slave server provides resources for a single location, the
;; secondary server supports a region or scope of subnets, and the
;; master is queried as a last resort when no closer resource is available.
;; Data is replicated from the master to secondary and slave systems.
;;
;; The Priority value is not used by this UDF. The data returned is sorted
;; by the maskbits value, so that the resource server closest to the
;; client can be tried first. For example, the master site has a weight
;; of 0, a secondary site has an address of 172.16.9.43 and a weight of 20,
;; and the slave site has an address of 172.16.12.20 and a weight of 24.
;; If a query is made with an address of 172.16.12.95, all three records
;; will be returned, since that address exists in each of the three networks.
;; Since the Weight values represent the maskbits, the data is sorted as
;; Slave (24), Secondary (20) and then Master (0).
;; The application will try to access the resource on the local Slave server.
;; If it is not found, or is unavailable, the application can try the
;; next resource provider (the Secondary server). Failing that, the
;; Master server can be queried.
;;
;; This method of resource localization is especially useful when
;; common sets of data (like software installation shares) are replicated
;; from the master site out to regional offices or remote branch locations.
;; With slow WAN links, the closest server is always tried first. Of course,
;; you must create the SRV records that you wish to use!
;;
;;DEPENDENCIES WScript
;;
;;TESTED WITH W2K, WXP, W2K3, W2K8, Vista
;;
;;EXAMPLES ; Get all domain controllers from local domain
;; $DcList = GetResourceBySrv('', 1, '_ldap._tcp.dc._msdcs')
;;
;; ; Get primary domain controller from local domain
;; $PDCe = GetResourceBySrv('', 1, '_ldap._tcp.pdc._msdcs')
;;
;; ; Get the list of replicated file servers closest to me
;; $MyIP = Join(Split(@IPADDRESS0, ' '), '')
;; $Servers = GetResourceBySrv($MyIP)
;; $Tag = 0
;; For Each $ServerRecord in $Servers
;; If Not $Tag
;; $ServerPath = '\\' + $ServerRecord[0] + '\share\folder\file.ext'
;; If Exist $ServerPath
;; ; open file, run command, etc..
;; If Not @ERROR
;; $Tag = 1 ; set Tag on successful process, prevent further attempts
;; EndIf
;; EndIf
;; EndIf
;; Next
;;
;;
;
Function GetResourceBySrv($_IpAddr , OPTIONAL $_Short , OPTIONAL $_Type )
Dim $_ , $_A ; Temp vars
Dim $_I , $_J , $_R ; Index pointers
Dim $_aR ; Return string
Dim $_oExec ; WScript object
Dim $_Rec [4 ] ; Working record
Dim $_aRtn [0 ] ; array of all SRV records
Dim $_aAdd ; array of address values
Dim $_DVal [33 ] ; array of decimal network values
Dim $_Network , $_Mask ; network and mask decimal values
Dim $_Hosts ; # of hosts in the subnet
If Not $_Type
$_Type = '_swdist._tcp' ; default SRV record type
Else
$_Short = 1 ; force short processing for non-default types
EndIf
; Use WScript to execute the command and check the result
$_oExec = CreateObject ("WScript.Shell" ).Exec('nslookup -type=all ' + $_Type )
If Not VarType ($_oExec ) = 9
$GetSrv = ''
Exit 10
EndIf
$_J = -1 ; pointer for returned data
; get the command result and extract what is needed
$_aR = Split ($_oExec .StdOut.ReadAll, @CRLF )
; enumerate the resulting data and place the data into the record fields
For $_I = 0 To UBound ($_aR )
If InStr ($_aR [$_I ], 'SRV service location:' )
$_ = Trim (Split ($_aR [$_I + 1 ], '=' )[1 ])
$_Rec [3 ] = $_
$_ = Trim (Split ($_aR [$_I + 2 ], '=' )[1 ])
$_Rec [2 ] = $_
$_ = Trim (Split ($_aR [$_I + 3 ], '=' )[1 ])
$_Rec [4 ] = $_
$_ = Trim (Split ($_aR [$_I + 4 ], '=' )[1 ])
$_Rec [0 ] = $_
; skip over the current data and locate the A record reference to get the IP Addr
$_A = AScan ($_aR , $_Rec [0 ], $_I + 5 , , 1 )
$_ = Trim (Split ($_aR [$_A ], '=' )[1 ])
$_Rec [1 ] = $_
; update the array of SRV records
$_J = $_J + 1 ; increment the pointer & resize the array
ReDim Preserve $_aRtn [$_J ]
$_aRtn [$_J ] = $_Rec ; add the new data record to the array
$_I = $_I + 4 ; skip the processed input data
EndIf
Next
If $_Short ; do we just return the data?
$GetResourceBySrv = $_aRtn
Exit 0
EndIf
; =====================================================================================
; Enumerate the SRV records, using the Weight as a CIDR netmask
; Calculate the network and subnet size
; order the results that match the specified network by increasing subnet size
$_R = -1 ; init index pointer
Dim $_aWork [0 ] ; create working array
$_DVal [32 ] = 1.0 ; init bit values
For $_I = 31 to 1 Step -1
$_DVal [$_I ] = $_DVal [$_I + 1 ] * 2.0
Next
; Convert the supplied IP address to a double value representing the decimal address
$_aAdd = Split ($_IpAddr , '.' )
$_IpAddr = (CDbl ($_aAdd [0 ]) * 16777216.0 ) + (CDbl ($_aAdd [1 ]) * 65536.0 ) + (CDbl ($_aAdd [2 ]) * 256.0 ) + (CDbl ($_aAdd [3 ]) * 1.0 )
; Enumerate the SRV records in the array generated above
For Each $_Rec in $_aRtn
; Data Format: Hostname, IP, Mask, Priority, Service_Port
; Set the number of hosts in the defined network base on the netmask
$_Hosts = 1.0
For $_J = 31 to Val ($_Rec [2 ]) Step -1
$_Hosts = ($_Hosts * 2.0 )
Next
; convert server IP address to decimal value
$_aAdd = Split ($_Rec [1 ], '.' )
$_ = (CDbl ($_aAdd [0 ]) * 16777216.0 ) + (CDbl ($_aAdd [1 ]) * 65536.0 ) + (CDbl ($_aAdd [2 ]) * 256.0 ) + (CDbl ($_aAdd [3 ]) * 1.0 )
; Convert the Server IP address to its local network address based on the supplied maskbits
$_Network = 0.0
For $_J = 1 to $_Rec [2 ] ; process each maskbit to value if present
If $_ >= CDbl ($_DVal [$_J ])
$_Network = $_Network + $_DVal [$_J ]
$_ = $_ - $_DVal [$_J ] ; remove the processed value from the address
EndIf
Next
; If the target address is between the network start and end addresses, add the record
; to the array to be returned
If $_IPAddr >= $_Network And $_IpAddr < ($_Network + $_Hosts )
$_R = $_R + 1
ReDim Preserve $_aWork [$_R ]
$_aWork [$_R ] = $_Rec
EndIf
Next
; all matching records have been found. Sort the data into the return array
; by largest to smallest maskbit values (closest to farthest). If two servers
; have identical maskbit values, they are returned in no specific order.
ReDim $_aRtn [UBound ($_aWork )]
$_R = 0 ; output pointer
For $_I = 31 to 0 Step -1 ; cycle through all possible maskbit values
For $_J = 0 to UBound ($_aWork )
If $_aWork [$_J ][2 ] = $_I
$_aRtn [$_R ] = $_aWork [$_J ]
$_R = $_R + 1
EndIf
Next
Next
$GetResourceBySrv = $_aRtn
Exit 0
EndFunction
_________________________
Actually I
am a Rocket Scientist!
Top
Moderator: Jochen , Allen , Radimus , Glenn Barnas , ShaneEP , Ruud van Velsen , Arend_ , Mart
0 registered
and 764 anonymous users online.