Forum Discussion

phakesley's avatar
phakesley
Icon for Neophyte rankNeophyte
4 months ago
Solved

Public DNS resolution monitoring

Newbie to LM and have been asked for a method to monitor Public DNS A,MX,PTR record monitoring for a number of DNS Zones e.g. customer1.domain.com, customer2.domain.co.uk. I know I do a powershell command resolve-DnsName <domain> -Server <Target DNS Server> -Type <A etc> and get the correct output.

What I do not know is how to turn this into a datasoure and use properties to pass in the domains and record types.

Has anyone got some scripts and examples I can use to create a datasource in LM please.

Much appreciated if you could help

  • Datasources cannot put text into datapoints, they have to be numeric.

    So you want to see if a given FQDN will resolve against Google’s servers? or do you want to see if it will resolve against a specified server?

    Have you looked at this? (Groovy is recommended since it will work on both Linux and Windows collectors, PowerShell only works on Windows currently.) Their example is pretty good although it doesn’t show how to specify the DNS server. This would be easily fixed by setting the DNS server on the collector to be your target DNS server.

    If you wanted to specify the DNS server, it looks like you’d do something like this. However, someone with more Groovy/Java skills will have to chime in on how to actually get it to work. 5 minutes of my time were fruitless.

    About using properties to create your instances, that depends a little more on what you want to track. Do you want to track multiple domains against only one DNS server? Or do you want to test each of multiple domains against a list of DNS server?  Either way, here’s a strategy you could use:

    Set a property called “dns.resolve_targets” with a value like this:

    google.com|Google,amazon.com|Amazon,logicmonitor.com|LogicMonitor

    Set another property called “dns.resolvers” with a value containing the list of DNS servers (fun thing about this is that you don’t have to specify a good display name for the DNS server, the script below will fall back to just the IP address of the DNS server):

    8.8.8.8|Google Primary,8.8.4.4|Google Secondary,76.76.2.0|Control D Primary,76.76.10.0|Control D Secondary,9.9.9.9|Quad9 Primary,149.112.112.112|Quad9 Secondary,208.67.222.222|OpenDNS Home Primary,208.67.220.220|OpenDNS Home Secondary,1.1.1.1

    Then your discovery script could look like this:

    hostProps.get("dns.resolvers").tokenize(",").each{server ->
    (dnsip,servername) = server.tokenize("|")
    hostProps.get("dns.resolve_targets").tokenize(",").each{target ->
    (domain,target_name) = target.tokenize("|")
    println("${dnsip}__${domain}##${target_name} via ${servername}######dns.server=${servername ?: dnsip}")
    }
    }
    return 0

    You’d need to decide if you’re going to do script or batchscript for collection.

    If doing script, you can just do:

    (dnsserver, target) = hostProps.get("wilvalue").tokenize("_")

    And you’ll have a variable called dnsserver containing the IP address of the DNS server and a variable called target containing the FQDN to be looked up.

    If doing batchscript, you’ll just copy the script above to get into your double-nested loop:

    import org.xbill.DNS.*

    hostProps.get("dns.resolvers").tokenize(",").each{server ->
    (dnsip,servername) = server.tokenize("|")
    hostProps.get("dns.resolve_targets").tokenize(",").each{target ->
    (domain,target_name) = target.tokenize("|")
    records = new Lookup(target_name, Type.A).run() //this needs to be modified to somehow specify the DNS server IP contained in dnsip

    // Analyze and output the numbers about the records here

    }
    }
    return 0

    You could add another loop to the outside of this collection script to specify a list of record types to loop through:

    import org.xbill.DNS.*

    [Type.A,Type.MX,Type.PTR].each{recordType->
    hostProps.get("dns.resolvers").tokenize(",").each{server ->
    (dnsip,servername) = server.tokenize("|")
    hostProps.get("dns.resolve_targets").tokenize(",").each{target ->
    (domain,target_name) = target.tokenize("|")
    records = new Lookup(target_name, recordType).run() //this needs to be modified to somehow specify the DNS server IP contained in dnsip

    // Analyze and output the numbers about the records here

    }
    }
    }
    return 0

4 Replies

  • Datasources cannot put text into datapoints, they have to be numeric.

    So you want to see if a given FQDN will resolve against Google’s servers? or do you want to see if it will resolve against a specified server?

    Have you looked at this? (Groovy is recommended since it will work on both Linux and Windows collectors, PowerShell only works on Windows currently.) Their example is pretty good although it doesn’t show how to specify the DNS server. This would be easily fixed by setting the DNS server on the collector to be your target DNS server.

    If you wanted to specify the DNS server, it looks like you’d do something like this. However, someone with more Groovy/Java skills will have to chime in on how to actually get it to work. 5 minutes of my time were fruitless.

    About using properties to create your instances, that depends a little more on what you want to track. Do you want to track multiple domains against only one DNS server? Or do you want to test each of multiple domains against a list of DNS server?  Either way, here’s a strategy you could use:

    Set a property called “dns.resolve_targets” with a value like this:

    google.com|Google,amazon.com|Amazon,logicmonitor.com|LogicMonitor

    Set another property called “dns.resolvers” with a value containing the list of DNS servers (fun thing about this is that you don’t have to specify a good display name for the DNS server, the script below will fall back to just the IP address of the DNS server):

    8.8.8.8|Google Primary,8.8.4.4|Google Secondary,76.76.2.0|Control D Primary,76.76.10.0|Control D Secondary,9.9.9.9|Quad9 Primary,149.112.112.112|Quad9 Secondary,208.67.222.222|OpenDNS Home Primary,208.67.220.220|OpenDNS Home Secondary,1.1.1.1

    Then your discovery script could look like this:

    hostProps.get("dns.resolvers").tokenize(",").each{server ->
    (dnsip,servername) = server.tokenize("|")
    hostProps.get("dns.resolve_targets").tokenize(",").each{target ->
    (domain,target_name) = target.tokenize("|")
    println("${dnsip}__${domain}##${target_name} via ${servername}######dns.server=${servername ?: dnsip}")
    }
    }
    return 0

    You’d need to decide if you’re going to do script or batchscript for collection.

    If doing script, you can just do:

    (dnsserver, target) = hostProps.get("wilvalue").tokenize("_")

    And you’ll have a variable called dnsserver containing the IP address of the DNS server and a variable called target containing the FQDN to be looked up.

    If doing batchscript, you’ll just copy the script above to get into your double-nested loop:

    import org.xbill.DNS.*

    hostProps.get("dns.resolvers").tokenize(",").each{server ->
    (dnsip,servername) = server.tokenize("|")
    hostProps.get("dns.resolve_targets").tokenize(",").each{target ->
    (domain,target_name) = target.tokenize("|")
    records = new Lookup(target_name, Type.A).run() //this needs to be modified to somehow specify the DNS server IP contained in dnsip

    // Analyze and output the numbers about the records here

    }
    }
    return 0

    You could add another loop to the outside of this collection script to specify a list of record types to loop through:

    import org.xbill.DNS.*

    [Type.A,Type.MX,Type.PTR].each{recordType->
    hostProps.get("dns.resolvers").tokenize(",").each{server ->
    (dnsip,servername) = server.tokenize("|")
    hostProps.get("dns.resolve_targets").tokenize(",").each{target ->
    (domain,target_name) = target.tokenize("|")
    records = new Lookup(target_name, recordType).run() //this needs to be modified to somehow specify the DNS server IP contained in dnsip

    // Analyze and output the numbers about the records here

    }
    }
    }
    return 0
  • What are you looking to alert on? Or are you just looking to track it? There are varying outputs from resolve-dnsname depending on the record you are hitting.

    If you are looking to just track, I would suggest using a ConfigSource for this.

  • Joe tahnks for the response. Although struggling to pass text data to the datapoints I have a basic DataSource that monitors A record for a given name and trakcs to response time and the DNS response

    e.g.

    $TestDNS = Resolve-DnsName [domain] -Server 8.8.8.8 -DnsOnly

    if(-Not $TestDNS)

    { write-host state=1}

    else

    {write-host state=0}

    exit 0


    I initially tried to get DnsName, TTL and Type and pass these back into datapoints but could not get the text data to appear. So went all basic. It is working to a fashion.

  • text will not pass through a dataSource, I use propertySources if I have to record that somehow.  I usually try to avoid negatives in my if Logic (for clarity)… and matching true/false (1/0) to that state.

    if ($TestDNS) {write-output “1”} else {write-output “0”}

    Then just use the direct output value rather than having to get it as a key/value pair.  For output:

    • write-output “string”
    • write-host “string”
    • “string”

    all behave the same in dataSources, but write-output is what I use to indicate a final push of data as opposed to write-host which is for display while running (in my head - so don’t feel you need to change yours).  I also explicitly define strings in my output to prevent weirdness from happening in the interpretation.  I usually do this at the write-output by including quotes around the output.