Showing posts with label ip address. Show all posts
Showing posts with label ip address. Show all posts

17 January, 2016

Search host name based on IP from Forward Lookup zone - DNS

There are times when the need calls for very ugly but practical workarounds. This time, we want to know the DNS name of a host, we only know the IP address and we don't have reverse lookup zones.

In this case, we can list all the A records from the forward lookup zone and search for the IP address we know.


Use WMI

If you have admin rights on the DNS server, you can use WMI:
gwmi -Namespace root/microsoftDNS -q "select * from MicrosoftDNS_AType where recorddata='10.1.1.123'" | select Ownername,recordData


Use dnscmd

However, if you don't have any sort of permissions, you can try to use dnscmd to enumerate all records from the given zone and then use powershell to search for the IP, then do some text parsing to get a proper output:



A bit of explanation:
  • $zoneContent = dnscmd $dnsserver /enumrecords $dnsDomain . /continue
    Get the full list of records from the given zone
  • if($item -match "$ip"){...
    Go through each line in the output and if the given line contains the IP you are looking for, start processing the data
  • if($item -match "^  "){
    If the line starts with spaces, that means it will have an IP which belongs to a host with multiple IPs, so we will need to list the previous line as well
  • $aging = $($tmp=$zoneContent[$k-1] -match "aging:(?<number>[^\]]+)"; $matches.number)
    $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)
    Calculate the time stamp of the record from the Aging number (which is the number of hours from 1st Jan 1601
  • New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($zoneContent[$k-1].split(" ")[0]); timestamp=$timestamp}
    Put the data into an object and throw it to the std out
The sample script in full:








 $ip = "10.1.1.122"  
 $dnsServer = "c3podc1"  
 $dnsDomain = "tatooine.com"  
   
 $zoneContent = dnscmd $dnsserver /enumrecords $dnsDomain . /continue  
 $k = 0  
   
 Foreach($item in $zoneContent){  
    if($item -match "$ip"){  
       # if the host has 2 IPs and we searched for the 2nd one, we will need the previous line from the output  
       if($item -match "^ "){  
          $aging = $($tmp=$zoneContent[$k-1] -match "aging:(?<number>[^\]]+)"; $matches.number)  
          $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)  
          New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($zoneContent[$k-1].split(" ")[0]); timestamp=$timestamp}  
            
          $aging = $($tmp=$item -match "aging:(?<number>[^\]]+)"; $matches.number)  
          $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)  
          New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($zoneContent[$k-1].split(" ")[0]); timestamp=$timestamp}  
       }  
       else{  
          $aging = $($tmp=$item -match "aging:(?<number>[^\]]+)"; $matches.number)  
          $timestamp = (Get-Date ("1601/01/01 00:00")).addhours($aging)  
          New-Object -TypeName psobject -Property @{"IP"=$ip; Host=($item.split(" ")[0]); timestamp=$timestamp}  
       }  
    }  
    $k++  
 }  
   

02 February, 2013

Verify ComputerName remotely - OS

Quick question for you, my fellow IT engineers, how much do you trust the content of your DNS zone? Good question, isn't it? If a DNS zone and its servers are setup correctly (according to the size and requirements of the given infrastructure) then the content of DNS is supposed to be up-to-date, so DNS scavenging is setup to delete old records...etc.

However, in a global IT infrastructure, there's always someone rebuilding a server with a new name. Imagine this: there's a very enthusiastic engineer who is testing a new multicast OS build method by installing OS on 200+ virtual machines (VM). And to make this test more comprehensive, he/she rebuilds these VMs with new names 4-5 times - but keeps the IP addresses because changing the MAC <-> IP assignment would be too much hassle... yeah, you got it right, cleaning up DNS is not that much hassle at all?! :)
So at the end of the test we end up with ~800 incorrect DNS records (which we initially don't know about).

I've got scripts to check out different aspects of list of servers remotely and if I hit a name which points to an IP of one of those VMs and it already has a new name, then all remote queries will fail (while ping will be successful). Why? Because Windows has a so called Strict Name checking, it does not allow incoming connections if the connection has a different target name. (unless you disable this behaviour).

Solution:
To make sure my checks are transparent, I need to see if a server's name is different to what it was on my list. Here is an example code which can do that. For the sake of the simple example, I want to query the last boot time of each host on a list:

   
# get the IP of the server from DNS

   $ip = [System.Net.Dns]::GetHostAddresses($srv)[0].IPAddressToString

      # creating an object to store results
      $obj = "" | Select Computername,Real_computername,LastBootTime
      $obj.Computername = $srv

     
# reading the name of the computer (contacted via its IP) from WMI

      $obj.Real_computername = (gwmi -class Win32_ComputerSystem -ComputerName $ip).name

      
# reading boot time of the remote host

      $obj.LastBootTime = (gwmi -class Win32_OperatingSystem -ComputerName $ip).lastbootuptime

To explain the essential line:
$ip = [System.Net.Dns]::GetHostAddresses($srv)
This line returns an array, but this time I only care about the first IP, so the [0] element of the array, because I have only 1 IP for each sever.
The rest of the script is straightforward and commented.

Example output:
Computername          Real_computername       LastBootTime
------------          -----------------       ------------
R2D2                  NEWR2D2                 20130129000920.125000+060



Entire example code:
 ## Usage: PS C:\> gc hostlist.txt | getBootTime.ps1
  
 function PingServer ([string]$srv){
      $ping = new-object System.Net.Networkinformation.Ping
      Trap {Continue} $pingresult = $ping.send($srv, 3000, [byte[]][char[]]"z"*16)
      if($pingresult.Status -ieq "Success"){$true} else {$false}
 }
  
 $hostlist = @($Input)
 foreach($srv in $hostlist){
  
      # get the IP of the server from DNS
      $ip = [System.Net.Dns]::GetHostAddresses($srv)[0].IPAddressToString
  
      if(PingServer $ip){
  
           # creating an object to store results
           $obj = "" | Select Computername,Real_computername,LastBootTime
           $obj.Computername = $srv
  
           # reading the name of the computer (contacted via its IP) from WMI
           $obj.Real_computername = (gwmi -class Win32_ComputerSystem -ComputerName $ip).name
           # reading boot time of the remote host
           $obj.LastBootTime = (gwmi -class Win32_OperatingSystem -ComputerName $ip).lastbootuptime
           $objcoll += $obj
      }
 }  


May the Force...
t