Elsewhere

Continuing with my previous post … as part of configuring it I went to “Advanced” > “DNS” in the VPN connection and put in my remote end DNS server and domain name to search. On Windows 10 I didn’t even have to do this – remote DNS and domains were automatically configured as part of connecting. Anyways, once I put these in though I thought it should just work out of the box but it didn’t.

So turns out many others have noticed and complained about this. I couldn’t find a solution as such to this but learnt about scutil --dns in the process. Even though the Mac OS has a /etc/resolv.conf file it does not seem to be used; rather, the OS has its own way of DNS resolution and scutil --dns lets you see what is configured. (I am very very sketchy on the details and to be honest I didn’t make much of an effort to figure out the details either). In my case the output of this command showed that the VPN provided resolver for my custom domain was being seen by scutil and yet it wasn’t being used – no idea why.

I would like to point out this post though that shows how one can use scutil to override the DHCP or VPN assigned DNS servers with another. Good to know the kind of things scutil can do.

And while on this confusing topic it is worth pointing out that tools like nslookup and dig use the resolver provided in /etc/resolv.conf so these are not good tools if you want to test what an average Mac OS program might be resolving a particular name to. Best to just ping and see what IP a name resolves to.

Anyways, I didn’t want to go down a scripting route like in that nice blog post so I tried to find an alternative.

Oh, almost forgot! Scoped queries. If you check out this SuperUser post you can see the output of scutil --dns and come across the concept of scoped queries. The idea (I think) is that you can say domain xyz.com should be resolved using a particular name server, domain abc.com should be resolved via another, and so on. From that post I also got the impression you can scope it per interface … so the idea would be that you can scope the name server for my VPN interface to be one, while the name server for my other interfaces to be another. But this wasn’t working in my case (or I had configured something wrong – I dunno. I am a new Mac OS user). Here was my output btw so you can see my Azure hosted domain rakhesh.net has its own name server, while my home domain rakhesh.local has its own (and don’t ask me where the name server for general Internet queries is picked up from … I have no idea!).

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

DNS configuration

resolver#1

search domain[0]:rakhesh.local

nameserver[0]:2001:8f8:002d:20eb::1

nameserver[1]:192.168.1.1

if_index:6(en0)

flags:RequestArecords,Request AAAA records

reach:0x00020002(Reachable,Directly Reachable Address)

resolver#2

domain:local

options:mdns

timeout:5

flags:RequestArecords,Request AAAA records

reach:0x00000000(Not Reachable)

order:300000

<snip>

resolver#7

domain:b.e.f.ip6.arpa

options:mdns

timeout:5

flags:RequestArecords,Request AAAA records

reach:0x00000000(Not Reachable)

order:301000

DNS configuration(forscoped queries)

resolver#1

search domain[0]:rakhesh.local

nameserver[0]:2001:8f8:002d:20eb::1

nameserver[1]:192.168.1.1

if_index:6(en0)

flags:Scoped,RequestArecords,Request AAAA records

reach:0x00020002(Reachable,Directly Reachable Address)

resolver#2

search domain[0]:rakhesh.net

nameserver[0]:10.0.0.4

if_index:12(ipsec0)

flags:Scoped,RequestArecords

reach:0x00000002(Reachable)

Anyways, here’s a link to scutil for my future reference. And story 1 and story 2 on mDNSResponder, which seems to be the DNS resolver in Mac OS. And while on mDNSResponder, if you want to flush you local DNS cache you can do the following (thanks to this help page):

Each DNS client is configured using the contents of a single configuration file of the format described below, or from a property list supplied from some other system configuration database. Note that the /etc/resolv.conf file, which contains configuration for the default (or “primary”) DNS resolver client, is maintained automatically by Mac OS X and should not be edited manually. Changes to the DNS configuration should be made by using the Network Preferences panel.

Mac OS X uses a DNS search strategy that supports multiple DNS client configurations. Each DNS client has its own set of nameserver addresses and its own set of operational parameters. Each client can perform DNS queries and searches independent of other clients. Each client has a symbolic name which is of the same format as a domain name, e.g. “apple.com”. A special meta-client, known as the “Super” DNS client acts as a router for DNS queries. The Super client chooses among all available clients by finding a best match between the domain name given in a query and the names of all known clients.

Queries for qualified names are sent using a client configuration that best matches the domain name given in the query. For example, if there is a client named “apple.com”, a search for “www.apple.com” would use the resolver configuration specified for that client. The matching algorithm chooses the client with the maximum number of matching domain components. For example, if there are clients named “a.b.c”, and “b.c”, a search for “x.a.b.c” would use the “a.b.c” resolver configuration, while a search for “x.y.b.c” would use the “b.c” client. If there are no matches, the configuration settings in the default client, generally corresponding to the /etc/resolv.conf file or to the “primary” DNS configuration on the system are used for the query.

If multiple clients are available for the same domain name, the clients ordered according to a search_order value (see above). Queries are sent to these resolvers in sequence by ascending value of search_order.

The configuration for a particular client may be read from a file having the format described in this man page. These are at present located by the system in the /etc/resolv.conf file and in the files found in the /etc/resolver directory. However, client configurations are not limited to file storage. The implementation of the DNS multi-client search strategy may also locate client configurations in other data sources, such as the System Configuration Database. Users of the DNS system should make no assumptions about the source of the configuration data.

If I understand this correctly, what it is saying is that:

The settings defined in /etc/resolv.conf is kind of like the fall-back/ default?

Each domain (confusingly referred to as “client”) in the man-page can have its own settings. You define these as files in /etc/resolver/. So I could have a file called /etc/resolver/google.com that defines how I want the “google.com” domain to be resolved – what name servers to use etc. (these are the typical options one finds in /etc/resolv.conf).

The system combines all these individual definitions, along with dynamically created definitions such as when a VPN is established (or any DHCP provided definitions I’d say, including wired and wireless) into a configuration database. This is what scutil can query and manipulate.

What this means for me though is that I can create a file called /etc/resolvers/rakhesh.net (my Azure domain is rakhesh.net) with something like these:

1

nameserver10.0.0.4

Thus any requests for rakhesh.net will go via this name server. When I am not connected to VPN these requests will fail as the DNS server is not reachable, but when connected it will work fine.

What if I want to take this one step further though? As in I want DNS requests for rakhesh.net to go to its proper external DNS server when I am not on VPN but go via the internal DNS server when I am on VPN? That too is possible. All I have to do is have multiple files – since I can’t call all of them /etc/resolvers/rakhesh.net – and within each specify the domain name via the domain parameter and also define the preference via a search_order parameter. The one with the lower number gets tried first.

So I now have two files. For internal queries I have /etc/resolvers/rakhesh.net.azure (the name doesn’t matter):

1

2

3

4

domain rakhesh.net

nameserver10.0.0.4

search_order1

timeout5

For external queries I have /etc/resolvers/rakhesh.net.inet:

1

2

3

4

domain rakhesh.net

nameserver162.159.24.178

nameserver162.159.25.191

search_order2

The internal file has higher priority. I also added a timeout of 5 seconds so it doens’t spend too much time trying to contact the name server if the VPN is not connected. Easy peasy. This way my queries work via the internal DNS servers if I am connected to VPN, and via external DNS servers if I am not on VPN.

If I now look at the output of scutil --dns I see all this info captured:

Just thought I’d put these here for my own easy reference. I keep forgetting these records and when there’s an issue I end up Googling and trying to find them! These are DNS records you can query to see if clients are able to lookup the PDC, GC, KDC, and DC of the domain you specify via DNS. If this is broken nothing else will work. :)

PDC

_ldap._tcp.pdc._msdcs.<DnsDomainName>

GC

_ldap._tcp.gc._msdcs.<DnsDomainName>

KDC

_kerberos._tcp.dc._msdcs.<DnsDomainName>

DC

_ldap._tcp.dc._msdcs.<DnsDomainName>

You would look this up using nslookup -type=SRV <Record>.

As a refresher, SRV records are of the form _Service._Proto.Name TTL Class SRV Priority Weight Port Target. The _Service._Proto.Name is what we are looking up above, just that our name space is _msdcs.<DnsDomainName>.

No point to this post except as a reference for my future self. I wanted to mention some of the links here to a colleague of mine today but couldn’t remember them. Finally had to search through my browser history. Easier to just put them here for later reference. :)

Via this Pi-Hole page – OpenNIC and DNS.Watch. Both are for uncensored results etc., with the former having additional TLDs too. Sadly neither supports edns-client-subnet so I can’t really use it. :( If I query www.google.com via one of these I get results that are 150-220ms away. Same query via Google DNS or OpenDNS gives me results that are 8ms away!

I hope to implement DNSCrypt-proxy on my Asus router this weekend (time permitting). Seems to be straight-forward to setup on Asus Merlin as there’s an installer and also available via AMTM. My colleague is currently using DNSCrypt.nl as the upstream resolver, but he also mentioned an alternative he hopes to try.

It’s funny there’s a lot more talk about DNS encryption these days. I happened to get on it coz I got the Asus Merlin running at home again recently and also coz of the CloudFlare DNS announcement. I’ve generally been in a geeky mode since then and checking out things like Pi-Hole etc. And just the other day I read an Ars Technica article about DNS encryption and today it turns out my colleague implemented DNSCrypt at his home just today morning.

Lastly, totally unrelated but as a reference to myself – I didn’t know there was an open source version of the Synology OS called XPEnology, and I didn’t know of these picoPSU power supplies. So cool! Also, Netgear R7800 seems to be a good router to keep in mind for the future.

So CloudFlare announced the 1.1.1.1 DNS resolver service the other day. Funny, coz I had been looking into various DNS options for my home network recently. What I had noticed at home was that when I use the Google DNS or OpenDNS resolvers I get a different (and much closer!) result for google.com while with other DNS servers (e.g. Quad9, Yandex) I get a server that’s farther away.

I was aware that using 3rd party DNS resolvers like this could result in me getting not ideal results, because the name server of the service I am querying would see my queries coming from this 3rd party resolver and hence give me a result from the region of this resolver (e.g. if Google.com has servers in UAE and US, and I am based in UAE, Google.com’s name servers will see that the request from www.google.com is coming from a server in the US and hence give me a result from the US thinking that’s where I am located). But that didn’t explain why Google DNS and OpenDNS were actually giving me good results.

Reading about that I came across this performance page from the Google DNS team and learnt about the edns-client-subnet (ECS) option (also see this FAQ entry). This is an option that name servers can support wherein the client can send over its IP/ subnet along with the query and the name server will look at that and modify its response accordingly. And if the DNS resolver support this, then it can send along this info to the name servers being queried and thus get better results. Turns out only Google DNS and OpenDNS support this and Google actually queries the name servers it knows with ECS queries and caches the results to keep track of which name servers support ECS. This way it can send those servers the ECS option. That’s pretty cool, and a good reason to stick with Google DNS! (I don’t think CloudFlare DNS currently does this, because I get non-ideal results with it too).

Today, if you’re using OpenDNS or Google Public DNS and visiting a website or using a service provided by one of the participating networks or CDNs in the Global Internet Speedup then a truncated version of your IP address will be added into the DNS request. The Internet service or CDN will use this truncated IP address to make a more informed decision in how it responds so that you can be connected to the most optimal server. With this more intelligent routing, customers will have a better Internet experience with lower latency and faster speeds. Best of all, this integration is being done using an open standard that is available for any company to integrate into their own platform.

While on DNS, I came across DNS Perf via the CloudFlare announcement. Didn’t know of such a service. Also useful, in case you didn’t know already, is this GRC tool.

Lastly, I came across Pi-Hole recently and that’s what I use at home nowadays. It’s an advertisement black hole. Got a good UI and all. It uses DNS (all clients point to the local Pi-Hole install for DNS) and is able to block advertisements and malware this way.

A while ago I was reading up on the Domain Controller process to confirm some stuff before changes I was making at work. Found a couple of good links, still got them open in my browser but before closing them out I thought I should paste them here as a reference to myself. I know most of the info, but occasionally you forget what you know or need a quick confirmation.

Our Citrix chaps logged a call with our vendor etc and they gave some bull about the DNS server not responding to TCP queries etc. Yours truly wasn’t looking after Citrix or NetScalers back then, so the change was quietly rolled back as no one had any clue why it broke Citrix.

Fast forward to yesterday, I had to do the change again coz now we want our DNS servers to resolve external names too – i.e. use root hints and all that goodness! I did the change, and Citrix broke! Damn.

But luckily now Citrix has been rolled into our team and I know way more about how Citrix works behind the scenes. Plus I keep dabbling with NetScalers, so I am not totally clueless (or so I’d like to think!).

I went into the DNS section of the NetScaler to see what’s up. Turns out the DNS virtual server was marked as down. Odd, coz I could SSH into the NetScaler and do name lookups against that DNS virtual server (which pointed to my internal DC basically). And yes, I could do dig +notcp to force it to do UDP queries only and nothing was broken. So why was the virtual server marked as down?!

I took a look at the monitor on the DNS service and it had the following:

Ok, so what exactly does this monitor do? Click “Edit Monitor” – nothing odd there – click on “Special Parameters” and what do I find?

Yup, it was set to query for the root zone. Doh! No wonder it broke.

I have no idea why the DNS monitor was assigned to this service. By default DNS-UDP has the ping-default monitor assigned to it while DNS-TCP has the tcp-default monitor assigned to it. Am guessing that since our firewall block ICMP from the NetScalers to the DCs, someone decided to use the DNS monitor instead and left it at the default values of monitoring for the root zone. When I removed the root zone that monitor failed, the DNS virtual server was marked as down, and the NetScaler could no longer resolve DNS names for the resources users were trying to connect to. Hence the STA error above. Nice, huh!

Fix is simple. Change the query in the DNS monitor to a zone your DNS servers. Preferably the zone your resources are in. Easy peasy. Made that change, and Citrix began working.

As might be noticeable from the tone of the post, I am quite pleased at having figured this out. Yes, I know it’s not a biggie … but just, it makes me happy at having figured it coz I went down a logical path instead of just throwing up my hands and saying I have no idea why the DNS service is down or why the monitor is red etc. So I am pleased at that! :)

I must begin with a link to this forum post where someone explains the various DNS types on a NetScaler. A must-read.

Now on to a bunch of screenshots and notes from me as I was just looking around with NetScalers and DNS. I have realized over time that my way of picking up stuff is by just doing it. A typical approach of reading about something and then trying it out doesn’t seem to work for me. (a) I get sleepy during reading and (b) that results in me never getting to the trying out stage. Instead, I seem to work better by just trying to begin with, succeed or break stuff in the process, and then go back and read or blog etc. about it. No hubris here that I am one of a kind :) am sure there’s more people who work this way – just that I too am like them.

A negative with this approach is that I must have a test lab where I can try things out. So there’s the additional effort required from me in terms of having a place where I can just break stuff. That’s probably the only negative thing I can think of about my approach. Oh, and it also takes up additional time when I want to pick up something – because first I have to set the environment up (e.g. when I was trying to pick up NSX last month) and then spend time just doing things and making/ breaking stuff in the process.

Anyways – end of digression. Back to NetScalers and DNS.

On a NetScaler, under the Traffic Management > DNS > NameServers is where you define DNS servers.

You create names servers by clicking on the “Add” button. That gives a new screen like thus:

I’ll start off the with the “Local” checkbox because it’s a very important one. Funny how it’s just there as a checkbox but it completely changes everything else!

If you tick “Local” what it means is that the NetScaler acts as a DNS server responding to queries from clients.

Thus the IP address you specify will be a Virtual IP on the NetScaler, where you can query for DNS replies.

The records you can query are what will be defined on the NetScaler, under the Records section.

The NetScaler can only act as a UDP based nameserver.

If you don’t tick “Local” then the NetScaler acts as a client. It won’t respond to any DNS queries.

Thus the IP address you specify are what the NetScaler will contact for its own DNS queries.

From the forum post I linked to above: NetScaler will monitor this IP address via ping from the NSIP (and not the SNIP).

Note: These IP address do not belong to the NetScaler.

The IP addresses + DNS port combo cannot be defined on the NetScaler in the Load Balancing > Services section. You’ll get a “Resource already exists” error in that case.

The IP addresses + DNS port combo can be defined in Service Groups. And can thus be used in load balancing etc. But as pointed out above, they cannot be defined as services.

When creating a name server it is possible to use an existing DNS virtual server if one is already defined. The caveat with this is that only UDP is allowed. It is not possible to add a TCP or UDP/ TCP entry. In fact, the only options one gets in the drop down menu are UDP only DNS load balancer virtual services. (From the forum post: in this case the NetScaler will monitor the virtual server from its SNIP).

It’s good to have TCP (or UDP/ TCP) servers in case of larger responses. In fact, when the NetScaler is acting as a load balancer for other DNS servers (this mode is called DNS proxy) it’s pretty much recommended to have TCP as an option too.

If, say, the NetScaler is defined with only a UDP based DNS server (as in the screenshot below) then queries will fail if the DNS responses are large and require a TCP connection.

1

2

3

root@ns10-01# dig NS tcpzone.com

;;Truncated,retrying inTCP mode.

;;communications error to127.0.0.2#53: connection reset

This brings me to one more point. If we are creating a virtual server DNS just for the NetScaler’s internal use, we don’t need to define an IP address for it. The Name Server I have above actually does not have any virtual IP on the NetScaler.

So – to summarize:

In the Name Servers section we can set the NetScaler to act as a DNS server for a zone it has.

This is UDP only.

This is not load balancing. i.e. not a virtual server.

In the Name Servers section we can also point the NetScaler to other DNS servers the NetScaler itself can use.

If an IP address is specified, it can be both UDP and TCP, and the NetScaler monitors it via ping from the NSIP.

If a virtual server (see next point) is specified, it is UDP only, and the NetScaler monitors it via ping from the SNIP.

The virtual server created for such internal use can be set in non-addressable mode (i.e. not IP address).

In the Virtual Servers section it is possible to define a DNS service. The NetScaler will then act as a DNS server.

This is load balancing. The NetScaler doesn’t host any zones.

The NetScaler will cache results though and serve from those if required.

The NetScaler does not use this internally. But it can be set to use this internally, if thus defined in the Name Servers section.

This is for both UDP and TCP.

This is also known as a DNS proxy.

I think that’s about the gist of it. I have skipped GSLB for now. Once again, pointing to the useful forum post. It’s a great one!

A colleague at work mentioned a Server 2016 DNS zone delegation bug he had found. I found just one post on the Internet when I searched for this. According to my colleague Microsoft has now confirmed this as a bug in the support call he raised.

DNS being an area of interest I wanted to replicate the issue and post it – so here goes. Hopefully it makes sense. :)

Imagine a split-DNS scenario for a zone rockylabs.zero.

This zone is hosted externally by a DNS server (doesn’t matter what OS/ software) called data01.

This zone is hosted internally by two DNS servers: a Server 2012R2 (called DC2012-01), and a Server 2016 (called DC2016-01).

Now say there’s a record rakhesh.rockylabs.zero that is the same both internally and externally. As in, we want both internal and external users to get the same (external) IP address for this record.

What you would typically do is add this record to your external DNS server and create a delegation from your two internal DNS servers, for this record, to the external DNS server. Here’s some screenshots:

The zone on my external DNS server. Notice I have an A record for rakhesh.rockylabs.zero.

Ignore the rakhesh2.rockylabs.zero record for now. That comes in later. :)

Here’s a look at the delegation from my Server 2012R2 internal DNS server to the external DNS server for the rakhesh.rockylabs.zero record. Basically I create a delegation within the rockylabs.zero zone on the internal server, for the rakhesh domain, and point it to the external DNS server. On the external DNS server rakhesh.rockylabs.zero is defined as an A record so that will be returned as an answer when this delegation chain is followed.

In my case both the internal DNS servers are also DCs, and the rockylabs.zero zone is AD integrated, so a similar delegation is automatically created on the other DNS server too.

As would be expected, I am able to resolve this A record correctly from both internal DNS servers.

Now for the fun part!

Notice the rakhesh2.rockylabs.zero record on my external DNS server? Unlike rakhesh.rockylabs.zero this one is a CNAME record. This too should be common for both internal and external users. Shouldn’t be a problem really as it should work similarly to the A record. Following the chain of delegation when I resolve rakhesh2.rockylabs.zero to a CNAME record called rakhesh.com, my DNS server should automatically resolve the A record for rakhesh.com and give me its address as the answer for rakhesh2.rockylabs.zero. It works with the Server 2012R2 internal DNS server as expected –

But breaks for the 2016 internal DNS server!

And that’s it! That’s the bug basically.

Here’s the odd bit though. If I were to query rakhesh.com (the domain to which the CNAME record points to), and then try to resolve the delegated record, it works!

If I go ahead and clear the cache on that 2016 internal server and try the name resolution again, it’s broken as before.

So the issue is that the 2016 DNS Server is able to follow the delegation for rakhesh2.rockylabs.zero to the external DNS server and resolve it to rakhesh.com, but it is doesn’t then go ahead and lookup rakhesh.com to get its A record. But if the A record for rakhesh.com is already cached with it, it is sensible enough to return that address.

I dug a bit more into this by enabling debug logging on the 2016 server. Here’s what I found.

Now it queries the external DNS server (data01 – 10.10.1.11) asking for the A record of rakhesh.com! That’s two wrong things: 1) Why ask the external DNS server (who as far as the internal DNS server knows is only delegated the rakhesh2.rockylabs.zero zone and has nothing to do with rakhesh.com) and 2) why ask it for the A record instead of the NS record so it can find the name servers for rakhesh.com and ask those for the IP address of rakhesh.com?

Until this is fixed one workaround would be to create a CNAME record directly in the internal DNS server to whatever the external DNS server points to. That is, don’t delegate to external – just create the same record internally too. Only for CNAME records; A is fine. Here’s an example of it working with a record called rakhesh3.rockylabs.zero where I simply made a CNAME on the internal 2016 DNS server.

Only reason I am creating this post is coz I Googled for the above and didn’t find any relevant hits

I know I can use the Add-DnsServerZoneDelegation cmdlet to create a new delegated zone (basically a sub-domain of a zone hosted by our DNS server, wherein some other DNS server hosts that sub-domain and we merely delegate any requests for that sub-domain to this other DNS server). But I wasn’t sure how I’d add multiple name servers. The switches give an option to give an array of IP addresses, but that’s just any array of IP addresses for a single name server. What I wanted was to have an array of name servers each with their own IP.

Anyways, turns out all I had to do was run the command for each name server.

Consider the following multiple A records for a DNS record proxy.mydomain.com:

proxy.mydomain.com IN A 192.168.10.5

proxy.mydomain.com IN A 10.136.53.5

proxy.mydomain.com IN A 10.136.52.5

proxy.mydomain.com IN A 10.136.33.5

proxy.mydomain.com IN A 192.168.15.5

These records are defined on a DNS server. When a client queries the DNS server for the address to proxy.mydomain.com, the DNS server returns all the addresses above. However, the order of answers returned keeps varying. The first client asking for answers could get them in the following order for instance:

proxy.mydomain.com IN A 192.168.10.5

proxy.mydomain.com IN A 10.136.53.5

proxy.mydomain.com IN A 10.136.52.5

proxy.mydomain.com IN A 10.136.33.5

proxy.mydomain.com IN A 192.168.15.5

The second client could get them in the following order:

proxy.mydomain.com IN A 10.136.53.5

proxy.mydomain.com IN A 10.136.52.5

proxy.mydomain.com IN A 10.136.33.5

proxy.mydomain.com IN A 192.168.15.5

proxy.mydomain.com IN A 192.168.10.5

The third client could get:

proxy.mydomain.com IN A 10.136.52.5

proxy.mydomain.com IN A 10.136.33.5

proxy.mydomain.com IN A 192.168.15.5

proxy.mydomain.com IN A 192.168.10.5

proxy.mydomain.com IN A 10.136.53.5

This is called round-robin. Basically it rotates between the various IP addresses. All IP addresses are offered as answers, but the order is rotated so that as long as clients choose the first answer in the list every client chooses a different IP address.

Notice I said clients choose the first answer in the list. This needn’t always be the case though. When I said clients above, I meant the client computer that is querying the DNS server for an answer. But that’s not really who’s querying the server. Instead, an application on the client (e.g. Chrome, Internet Explorer) or the client OS itself is the one looking for an answer. These ask the DNS resolver which is usually a part of the OS for an answer, and it’s the resolver that actually queries the server and gets the list of answers above.

The DNS resolver can then return the list as it is to the requesting application, or it can apply a re-ordering of its own. For instance, if the client is from the 192.168.10.0 network, the resolver may re-order the answers such that the 192.168.10.5 answer is always first. This is called Subnet prioritization. Basically, the resolver prioritizes answers that are from the same subnet as the client. The idea being that client applications would prefer reaching out to a server in their same subnet (it’s closer to them, no need to go over the WAN link for instance) than one on a different subnet.

Subnet prioritization can be disabled on the resolver side by adding a registry key PrioritizeRecordData (link) with value 0 (REG_DWORD) at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DnsCache\Parameters. By default this key does not exist and has a default value of 1 (subnet prioritization enabled).

Subnet prioritization can also be set on the server side so it orders the responses based on the client network. This is controlled by the registry key LocalNetPriority (link) under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DNS\Parameters\ on the DNS server. By default this is 0, so the server doesn’t do any subnet prioritization. Change this to 1 and the server will order its responses according to the client subnet.

By default the server also does round-robin for the results it returns. This can be turned off via the DNS Management tool (under server properties > advanced tab). If round-robin is off the server returns records in the order they were added.

Consider a server who has round-robin and subnet prioritization enabled. Now consider the DNS records from above:

proxy.mydomain.com IN A 192.168.10.5

proxy.mydomain.com IN A 10.136.53.5

proxy.mydomain.com IN A 10.136.52.5

proxy.mydomain.com IN A 10.136.33.5

proxy.mydomain.com IN A 192.168.15.5

The first and last records are from class C networks. The other three are from Class A networks. In reality though thanks to CIDR these are all class C addresses.

Now say there’s a client with IP address 10.136.50.2/24 asking the server for answers. On the face of it the client network does not match any of the answer record networks so the server will simply return answers as per round-robin, without any re-ordering. But in reality though the client 10.136.50.2/24 is in the same network as 10.136.52.5/24 and both are part of a larger 10.136.48.0/20 network that’s simply been broken into multiple /24 networks (to denote clients, servers, etc). What can we do so the server correctly identifies the proxy record for this client?

This is where the LocalNetPriorityNetMask registry key under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DNS\Parameters\ on the DNS server comes into play. This key – which does not exist by default – tells the server what subnet mask to assume when it’s trying to subnet prioritize. By default the server assumes a /24 subnet, but by tweaking this key we can tell the server to use a different subnet in its calculations and thus correctly return an answer.

The LocalNetPriorityNetMask key takes a REG_DWORD value in a hex format. Check out this KB article for more info, but a quick run through:

A netmask can be written as xxx.xxx.xxx.xxx. 4 pairs of numbers. The LocalNetPriorityNetMask key is of format 0xaabbccdd – again, 4 pairs of hex numbers. This is a mask that’s applied on the mask of 255.255.255.255 so to calculate this number you subtract the mask you want from 255.255.255.255 and convert the resulting numbers into hex.

For example: you want a /8 netmask. That is 255.0.0.0. Subtracting this from 255.255.255.255 leaves you with 0.255.255.255.255. What’s that in hex? 00ffffff. So LocalNetPriorityNetMask will be 0x00ffffff. Easy?

So in the example above I want a /20 netmask. That is, I am telling the server to assume the clients and the record IPs it has to be in a /20 network, so subnet prioritize accordingly. A /20 netmask is 255.255.240.0. Subtract from 255.255.255.255 to get 0.0.15.255. Which in hex is 00000fff (15 decimal is F hex). So all I have to do is put this value as LocalNetPriorityNetMask on the DNS server, restart the service, and now the server will correctly return subnet prioritized answers for my /20 network.

Update: Some more links as I did some more reading on this topic later.

A subnet calculator (also gives you the wildcard, which you can use for calculating the LocalNetPriorityNetMask key)

I am not very clear on what happens if you disable RoundRobin but there are multiple entries from the same subnet. What order are they returned in? Here’s a link to the RoundRobin setting, doesn’t explain much but just linking it in case it helps in the future.

More as a note to myself (and any others if they wonder the same) – the subnet mask you specify is applied on the client. That is to say if you client has an IP address of say 10.136.20.10, by default the DNS server will assume a subnet mask of /24 (Class C is the default) and assume the client is in a 10.136.20.0/24 network. So any records from that range are prioritized. If you want to include other records, you specify a larger subnet mask. Thus, for example, if you specify a /20 then the client is assumed to have an IP address 10.136.20.10/20, so its network range is considered to be 10.136.16.1 – 10.136.31.254 (don’t wrack your brain – use the subnet calculator for this). So any record in this range is prioritized over records not in this range.

The Windows calculator can be used to find the LocalNetPriorityNetMask key value. Say you want a subnet mask of /19. The subnet calculator will tell you this has a wildcard of 0.0.31.255 – i.e. 00011111.11111111. Put this (13 1’s) into the Windows calculator to get the hex value 3FFF.

Just a quick post on how to use the dig command. Had to troubleshooting some DNS issues today and nslookup just wasn’t cutting it so I downloaded BIND for Windows and ran dig from there. (For anyone else that’s interested – if you download BIND (it’s a zip file), extract the contents, and copy dig.exe and all the .dll files elsewhere that’s all you need to run dig).

Here’s the simple way of running dig:

1

dig@server name type

A bit confusing when you come from nslookup where you type the name server first and then the name and type. Here’s the nslookup syntax for reference:

1

nslookup-type=typename server

Although all documentation shows the dig syntax as above I think the order can be changed too. Since the name server is identified by the @ sign you can specify it later on too:

1

dig name@server type

I will use this syntax everywhere as it’s easier for me to remember.

You can complicate the simple syntax by adding options to dig. There’s two sort of options: query options and domain options (I made the names up). These are usually placed after the type but again the order doesn’t really matter:

1

dig name@server typeoptions

Query options start with a - (dash) and look like the switches you have in most command line tools. These are useful to control the behavior of dig when making the query.

For instance: say I want to for dig to only use IPv4. I can add the option -4. Similarly for only IPv6 it is -6.

If I want to specify the port of the name server (i.e. apart from 53) the -p option is for that.

(Very useful) If I want to specify a different source port for the client (i.e. the port from which the outgoing request is made and to which the reply is sent, in case you want to eliminate any issues with that) the -b switch is for that. It takes as argument address#port, if you don’t care about the address leave it as 0.0.0.0#port.

Apart from specifying the name and type as above it is also possible to pass these as query options via -n and -t.

There are some more query options. Above are just the common ones I can remember.

Domain options start with a + (plus). These pertain to the name lookup you are doing.

For instance: typically DNS queries are performed using UDP. To use TCP instead do +tcp. Most of these options can be prefixed with a “no”, so if you explicitly want to not use TCP then you can do +notcp instead.

To specify the default domain name do +domain=xxx.

To turn off or on recursive mode do +norecurse or +recurse. (This is similar to the -recurse or -norecurse switch in nslookup).

Note: By default recursion is on.

A quick note on recursion: When recursion is on dig asks the name server you supply (or that used by the OS) for an answer and if that name server doesn’t have an answer the name server is expected ask other name servers and get back with an answer. Hence the term “recursive”. The name server will send a recursive query to the name server it knows of, who will send a recursive query to the name server it knows of, until an answer is got down the chain of delegation.

A quick note on iterative (non-recursive queries): When recursion is off dig gets an answer from the first name server, then it queries the second name server, gets an answer and queries the third name server, and so on … until dig itself gets an answer from a server who knows.

The output from dig is usually verbose and shows all the sections. To keep it short use the +short option.

This doesn’t show the name of the server that dig got an answer from. To print this too use the +identify option.

To list all the authoritative name servers of a domain along with their SOA records use the +nssearch option. This disables recursion.

To list a trace of the delegation path use the +trace option. This too disables recursion. The delegation path is listed by dig contacting each name server down the chain iteratively.

Couple of output modifying options. Most of these require no changing:

By default the first line of the output shows the version of dig, the query, and some extra bits of info. To hide that use +nocmd.

By default the answer section of replies is shown. To hide it do +noanswer.

By default the additional sections of a reply are shown. To hide it do +noadditional.

By default the authority section of a reply is shown. To hide it do +noauthority.

By default the question asked is shown as a comment (this is useful because you might type something like dig rakhesh.com which dig interprets as dig rakhesh.com A so this makes the question explicit). To hide this do +noquestion.

Note that this is not same as the query that is sent. The query is the question plus other flags like whether we want a recursive query etc. By default the query that is sent is not shown. To show that do +qr.

By default comments are printed. To hide it do +nocomments.

By default some stats are printed. To hide these do +nostats.

To change the timeout use +time=X. Default is 5 seconds. This is equivalent to nslookup -timeout=X.

To change the number of retries use +retry=X. Default is 3. This is equivalent to nslookup -retry=X.

There are some more domain options. Above are just the common ones I can remember.

An interesting thing about dig (since BIND 9) is that it can do multiple queries (the brackets below are not part of the command, I put them to show the multiple queries):

1

dig(name@server typeoptions)(name@server typeoptions)...

Each of these queries can take its own options but in addition to that you can also provide global options. So the full command when you have multiple queries and global options is as below (again, without the brackets):

blah.com to fileC:\Windows\system32\dns\blahexport.txt on the DNS server

Command completed successfully.

Importing too is easy but the commands aren’t so obvious. Again you use dnscmd, with the /zoneadd switch as though you are creating a new zone. The help page for this misses out on an important switch though – /load – which lets you load the zone from an exported or pre-existing file.

You can find this switch in the dnscmd help:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

C:\>dnscmd/zoneadd

Usage:DnsCmd<ServerName>/ZoneAdd<ZoneName><ZoneType>[<Options>]

<ZoneName>--FQDNofzone

<ZoneType>:

/DsPrimary[/dp<FQDN>]

--DSintegratedprimaryzone

/Primary/file<filename>

--standardfilebackedprimary;MUSTincludefilename.

/Secondary<MasterIPAddress>[<MasterIPAddress>]..][/file<filename>]

--standardsecondary,MUSTincludeatleastonemasterIP;

filenameisoptional.

/Stub<MasterIPAddress>[<MasterIPAddress>]..][/file<filename>]

--stubsecondary,onlyreplicatesNSinfofromprimaryserver

/DsStub--as/StubbutDSintegrated-usesameoptions

/Forwarder<MasterIPAddress>[<MasterIPAddress>]..][/Timeout<Time>]

[/Slave]

--forwarderzone,queriesfornamesinzoneforwardedtomasters

/DsForwarder--as/ForwarderbutDSintegrated-usesameoptions

<Options>:

[/file<filename>]--filename,invalidforDSintegratedzones

[/load]--loadexistingfile;ifnotspecified,

non-DSprimarycreatesdefaultzonerecords

[/a<AdminName>]--zoneadminemailname;primaryzonesonly

[/DP<FQDN>]--fullyqualifieddomainnameofdirectorypartition

wherezoneshouldbestored;oruseoneof:

/DP/domain-domaindirectorypartition

/DP/forest-forestdirectorypartition

/DP/legacy-legacydirectorypartition

So the way to import a zone is as follows: first, copy the exported file into the c:\windows\system32\dns folder of the DNS server and preferably rename it so the extension is a .dns (not required, just a nice thing to do). Then run a command similar to below:

1

dnscmdDNS-SERVER/zoneadd"blah.com"/primary/fileblah.com.dns

That’s it. This will create a primary zone called “blah.com” and use the zone file that’s already in the location.

Note that you can’t use this technique for AD integrated zones. But that’s no issue. Simply import as above and then convert the zone to AD integrated via the GUI.

I was trying to create a conditional forwarder on my work DNS servers and kept hitting this cryptic error message:

I was trying to create a conditional forwarder called some.sub.zone.com. At first I thought maybe I had this as an existing zone or perhaps as a stub zone – but nope, I don’t have that. Some forum posts mentioned the lack of root hints could lead to this error, but that doesn’t make sense to me – why would I need root hints for this? Next I created a test conditional forwarder to some random domain name and that worked – so surely it wasn’t a server issue.

I recreated this in my test lab and found the problem. The issue is that I am trying to create a forwarder to some.sub.zone.com while zone.com already exists on the DNS server. I was under the impression you could have conditional forwarders even for zones you host, but nope that’s a no can do. From the official docs here’s a para of interest:

A DNS server cannot forward queries for the domain names in the zones it hosts. For example, the authoritative DNS server for the zone microsoft.com cannot forward queries according to the domain name microsoft.com. The DNS server authoritative for microsoft.com can forward queries for DNS names that end with example.microsoft.com, if example.microsoft.com is delegated to another DNS server.

The emphasis is mine and that’s the work-around to use here. You have two options – either delete the zone.com zone from your DNS servers and then create a conditional forwarder for some.sub.zone.com; or create a delegation for some.sub.zone.com – you could do that to yourself too – and then create the conditional forwarder.

Here’s a screenshot from my test lab –

The some.sub delegation is to my server itself. You don’t need to create a zone for the delegation to succeed. The delegation is just a one way pointer of sorts telling the server to ask the delegated server for any queries concerning this sub zone – it basically tells the server hosting zone.com that it is no longer responsible for some.sub.zone.com (even though the delegation points back to itself!). Once that is done the server will allow you to create a conditional forwarder for some.sub.zone.com.

This looks up the name servers for the zone and suspends the zone on each of those servers. If there are any servers that host this zone but aren’t specified as name servers for the zone (for example it could be an AD integrated zone but the NS records are incomplete) it misses out those servers. So it’s not a great script, there’s probably better ways to do this.

In my case the zone in question was being replicated to all DCs in the domain. So I got a list of all DCs in the domain and targeted those instead: