You Can Do That: Test DNS

Background

A very common request I get from business units (and end users, even) is to be granted read access to internal Microsoft DNS servers. I completely understand the motivation: it could be very convenient to be able to review both the existence and resolution data of DNS records. I mean, you can grant read-only access to a file share and a database, so you should be able to do the same for DNS, right? Unfortunately, it's not that simple, and for one main reason: Microsoft DNS security sucks.

I'm not going to go into all the technical details here (may do a full post with all that later), but because of the way Microsoft has set up their default permissions, the security principal Authenticated Users can create and modify all records in any zone hosted by a Windows DNS server. This is to allow and enforce secure dynamic updates. However, the major takeaway for today's post is that anyone who is granted the ability to connect to a Windows DNS server via MMC can create and modify any record hosted in any zone on that server.

If you don't believe me, check the Advanced Security section of your server. Better yet, grant a test account just Read access in the standard Security section of that same server (the server, not the zone), then connect to test. It will be able to create and modify records, though you won't be able to delete them (small consolation).

Just like many other situations, there technically are ways to make this happen that involve lots of work (Deny ACL entries in this case) but as anyone who's managed enterprise-class infrastructure knows, creating that kind of one-off situation is very risky in both micro and macro terms. Micro in that future resources hosted on that server may not get the custom configuration applied to make them secure and macro in that you may be asked to replicate this configuration in dozens or hundreds of other environments, significantly amplifying the risk.

So what are users to do? Ask someone from Directory Services every time they want to check a record? Of course not. If you have access to a machine that can query the zone hosted on the target server (even through an intermediary), you can check the existence and resolution data of any record on it. Read on to find out how.

Don't Use Ping

A quick aside: don't use ping to test anything but ICMP connectivity. Long story short, ping references the local resolver cache before sending anything to the DNS server, so you could get stale record data if a query was previously done or bad data if the record you're querying is included in the computer's hosts file. Ping also lacks many of the features of a better tool, which is...

NSLookup

NSLookup is a command line tool that's been included in every version of Windows (server and workstation) since at least the Windows XP/Server 2003 days, probably back to 2000. It stands for "name server lookup," and it's the appropriate tool for testing DNS queries.

There are multiple ways to make use of the tool, but for the sake of brevity and clarity, I'll only describe the way I use it.

Being a command line tool, you'll need to open a command prompt. It does not need to be Admin or elevated. One launched, simply type "nslookup" and press Enter. This "launches" the tool and automatically uses the configured primary DNS server as the target. It'll look something like this:

Default Server:  DNSServer1.domain.local
Address:  192.168.0.1


>


If you don't have reverse zones set up in your environment (for shame), there will be a short timeout, and the name of the server won't show up. However, the target address always will always be listed.

NSLookup - Forward Lookup

A forward lookup is the resolution of a text string to an IP. After launching the NSLookup utility, simply enter the FQDN of the record you want to look up and hit Enter. It will look something like this:

> WebServer01.domain.local
Server:  DNSServer1.domain.local
Address:  192.168.0.1

Name:    WebServer01.domain.local
Addresses:  10.0.0.1


As you can see, there are two sections in the response text:
  1. The target server information (IP always, name if available in reverse DNS).
  2. The resolution data for the given record.
In this example, I looked up WebServer.domain.local, and the resolution data is a simple IP: 10.0.0.1. This is a standard A record, but if it were a CNAME, TXT, or other type of record, additional information appropriate to that type would be included.


NSLookup - Reverse Lookup

If you host reverse records in your environments, you can also query them using this utility. It's literally as simple as entering the IP; no need for in-addr.arpa formatting here.

> 10.0.0.2
Server:  DNSServer1.domain.local
Address:  192.168.0.1

Name:    WebServer02.domain.local
Addresses:  10.0.0.2


As you can see, the response text for this PTR record is the same as what is returned for a forward lookup on an A record. This is because they are the simplest/most common types of records and are basically the reverse of each other.

Common Parameters

You can find a list of all available switches/parameters for NSLookup here. However, I've found myself only really using two: server and set type.

You use the server parameter when you need to specify a target other than the primary DNS server on the machine you're using. Once you've launched the utility, type "server" and either the name or IP of the new target DNS server.

> server 192.168.100.1
Default Server:  DNSServer2.domain.local
Address:  192.168.100.1


>

You can then continue using the tool as normal. The only difference will be the queries will now be going to the new target DNS server.

You can use the set type parameter to change the type of record being queried. By default, some types of records are excluded from responses because they can cause confusion or add a bunch of unwanted text to the response (the most notable ones for me are NS and MX records). So if I want to look up an MX record, I'll need to specify that type before doing the lookup.

> set type=mx
> domain.local
Server:  DNSServer1.domain.local
Address:  192.168.0.1 


domain.local   MX preference = 10, mail exchanger = internalrelay.domain.local
internalrelay.domain.local        internet address = 10.101.0.1


It's easiest to do a step by step with this one.
  1. I issued the command to switch the type of queried record to MX (set type=mx). The system accepted this as a parameter and simply returned me to the prompt without listing the target server again.
  2. I entered the name of the record (domain.local) and hit Enter.
  3. The response text listed the target server before giving the resolution data. Because this is an MX record, it returned the type, preference, and target FQDN (internalrelay.domain.local). Helpfully, it even resolved the target A record for us (10.101.0.1).
The list of available types should be familiar to anyone who's done much DNS administration.

External Lookups

If your machine is in an environment that can resolve external records (outside your company on the internet), you can simply use nslookup to check them. You will query your internal server, it will query the outside world, then the results will be sent back to you.

However, you will often run into situations where you either can't do external queries from a secure internal environment or want to remove your infrastructure from the equation. For that, there are a number of publicly-available tools, but my favorite one is:

Network-Tools.com

That link will take you a GUI interface for nslookup that is set to query Google's primary public server. I've found it to be a reliable recursive resolver.

There you go. That's my quick primer for all the ways you can query internal and external DNS with zero elevated permissions. No, you won't be able to export a list of all records in a given zone, but if you know the basics, you can query for the existence and resolution data of any record on any DNS server to which you have the required network access.


Troubleshooting

Appended suffixes.

Depending on the configuration of your infrastructure and client DNS settings, your machine may append its primary DNS suffix to FQDN strings it interprets as being incomplete. In other words, it's going to think you're feeding it an unqualified query and do what it's supposed to do: append the configured suffix to the end of your query. It will look something like this:

> WebServer01.domain.local
Server:  DNSServer1.domain.local
Address:  192.168.0.1

*** DNSServer1.domain.local can't find WebServer01.domain.local.domain.local: Non-existent domain

Notice how the suffix is listed twice in the error.

"Fixing" this at its root is beyond the scope of this post, but working around it is incredibly easy. A trailing period on a DNS query string is an indicator of the end of the query, so just add one.

> WebServer01.domain.local.
Server:  DNSServer.domain.local
Address:  192.168.0.1

Name:    WebServer01.domain.local
Addresses:  10.0.0.1

That's it.

Incorrect results after extended use.

If you get somewhat deep in the tool and end up using several parameters, you may start seeing odd behavior, including resolution errors for records you know exist. This normally means something you did a few steps back may still be in effect without you knowing. The most common ones are switching the type to something (like MX), then querying another type (like A). Even though the A record exists, it won't return since the tool is looking exclusively for MX records.

My suggestion here is to simply start over. At any point, you can type the string "exit" and press Enter to exit the tool and go back to a normal command prompt. Then simply launch the tool again, and it will be back to the default settings.

Remember: there's nothing keeping you from opening multiple command prompts and applying different parameters to them. There's no reason to switch back and forth between configurations within the same window; that's asking for confusion.

Comments