Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

I have a need to be able to identify which public DNS servers machines in internal networks are using for queries. To clarify, I do not want IPs or names of internal DNS servers or network devices. I need a scriptable way to identify what public servers they are calling to when queries are forwarded. For instance, I'm on a home network and my router's address is 172.16.1.1 - and it is programmed to used 4.2.2.1 and 4.2.2.2 for name resolution. I need to be able to capture these addresses. Parsing out of ip/ifconfig or logging into routers etc. are not options.

I've tried getting info out of nslookups and dig but I don't seem to be able to get the servers that are actually getting the queries at first before they start recursing. The internal DNS servers get identified but I'm not seeing the next hops.

Any ideas ? Unix or Dos or Windows etc, any solutions welcome.

share|improve this question

3 Answers 3

up vote 1 down vote accepted

There is really no way to accomplish your task, because the DNS server can resolve queries in any way it feels is appropriate, and it's a black box to the client. However, it is possible to get close to answering your question.

The trick is to set up a subdomain with a special nameserver whose response to any A query simply echoes the IP address of the host that issued the query. Such a nameserver can be implemented in Perl using the Net::DNS::Nameserver module:


#!/usr/bin/perl

use Net::DNS::Nameserver;

Net::DNS::Nameserver->new(
    # w.x.y.z is the IP address of the host where this code is running
    LocalAddr => ['w.x.y.z'],
    ReplyHandler => sub {
        my ($qname, $qclass, $qtype, $peerhost, $query) = @_;
        my ($rcode, @ans, @auth, @add) = ('NXDOMAIN');
        print "Received query for $qname from $peerhost\n";

        if ($qtype eq 'A') {
            $rcode = 'NOERROR';
            push @ans, Net::DNS::RR->new("$qname 1 $qclass $qtype $peerhost");
        }
        return ($rcode, \@ans, \@auth, \@add, { aa => 1});
    },
)->main_loop;

Next, configure some domain's NS record to point to this special nameserver. I've done this for a domain called resolverid.acrotect.com. (As a service to you, I'll leave the code running there for the next few days.)

Then, issue a few different DNS queries from a client inside your network:

dig +short cachebuster1.resolverid.acrotect.com
dig +short cachebuster2.resolverid.acrotect.com
dig +short cachebuster3.resolverid.acrotect.com

This will cause your nameserver to resolve the queries by contacting the rigged nameserver, which replies with the IP address of the machine that forwarded the query. In some cases, that address is the "public" side of your "private" nameserver, which is what you asked for.

In other cases, the infrastructure is more complicated. For example, if you are configured to use Google DNS servers 8.8.8.8 and 8.8.4.4, you are actually using a geographically distributed pool of nameservers. The Google server that makes the query to the rigged nameserver might not have an IP address anywhere near 8.8.8.8 or 8.8.4.4. However, you would be able to see that it belongs to Google by doing a reverse-IP or WHOIS lookup on the response. (Interestingly, if you do the reverse-IP lookup using Google DNS, you'll see that Google has optimized away the reverse-IP lookup based on the A lookup you just performed. The PTR that it returns will be something.resolverid.acrotect.com. To bust that optimization, you'll have to do dig +trace -x a.b.c.d.)

share|improve this answer
    
thanks very much! by doing nslookups and setting the NS to resolverid.acrotect.com it appears to return the public dns server that forwarded the query. in multiple tests these differed from what was hardcoded on my routers. for instance 4.2.2.1 and 4.2.2.2 come back with different dns servers in verizon/level3 in my locale. similar results with some ec2 machines, amazon dns servers other than what i hardcoded were returned. if you can leave the server up for a few days, much appreciated. looks like indeed it won't be possible to do what i'm after. –  Jason Jun 13 '12 at 9:00
    
200_success, can you mail me offline or reply here regarding your setup? Trying to replicate it. Yours was working fine and mostly returning what I expected....I implemented the code and it's returning only the public IPs of the networks i'm testing from (rather than dns servers like yours). Mail is jwm.forward@gmail.com –  Jason Jun 21 '12 at 6:22
    
Nevermind - got it. Was a matter of properly putting in the NS records with the registrar for the domain I'm using. Works well. Thanks again. –  Jason Jun 21 '12 at 9:55
    
@Jason Glad to hear that the solution works for you. I don't think you'll get any better method for probing the DNS setup that works in the general case, so would you mind accepting this as the answer to your question? –  200_success Jun 22 '12 at 11:51
    
Sorry for delay - accepted. –  Jason Nov 10 '12 at 4:16

You need to capture (think tcpdump on unix) the data flowing between the hosts in question and the Internet, looking for queries sent to port 53 (generally, udp but tcp may be used too) and parse the dump's output.

You'll need to run tcpdump either on the gateway system itself, or, if you've got a managed switch, from a port in monitor mode.

share|improve this answer
    
Thanks for the reply, but not an option - this type of data will need to be easily retrieved from client machines (mostly in fact on home networks using major ISPs with typical setups). The most typical use case would be a script running on a user's machine that can tell what DNS servers their ISP is providing...when their DHCP info points at their internal router address for dns. Ipconfig returns an internal address, dig and nslookup traces cite the internal router address, etc. –  Jason Jun 13 '12 at 7:28
    
so you need an agent to run on client's boxes then? Think WMI, netsh or parsing ipconfig /all on Windows, and /etc/resolv.conf et al. on unix variants. –  NekojiruSou Jun 13 '12 at 7:48
    
an agent yes, but those commands will often only yield me an internal address of a router, which is the problem. i want to know what servers my home router is using for external resolution - whether they are provided by the ISP or whether they are hard coded in by a user on the router. the problem is that all the results i get seem to leave these out. i know that often times people hard code on their machine which is fine but that's only part of the time. –  Jason Jun 13 '12 at 8:15
    
Research how iodine dns proxy works, create a specially crafted DNS zone with your nameserver logging every query, and have your host agent issue unique queries to your zone, then inspect the logs for the source IPs of the requests. Heck, you can even encode some data into the DNS requests. however, if the DNS infrastructure utilized by the users is multi-tiered (e.g. the clients query an inner ISP's caching server which in turn queries the outer recursive NS), you will see only the top layer DNS servers' addresses. –  NekojiruSou Jun 13 '12 at 8:27
    
thanks. it's definitely problematic and using an above example i've found that the source IPs that get identified are other dns servers on the same network (EG i hardcode 4.2.2.2 and get back a different dns server at verizon/level3). probably not possible to do what i'm after. really appreciate the feedback. i'll continue testing. –  Jason Jun 13 '12 at 9:33

I don't believe you can (through clever use of DNS from your client).

The whole point of a having a DNS resolver recurse for you, is that it is going to answer your queries on your behalf. Where it got them from are none of your business (as a mere DNS client).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.