DNS::question name - Modifying a DNS Suffix When Your Windows Client Appends It During Recursive Lookups

Quite some time ago I was asked about a 2-second delay when performing recursive lookups against the BIG-IP. My first thought was that there was an issue with transport. I then decided to deploy it in my own lab. To my surprise, I was experiencing the exact same issue though I know there were no transport problems in my own environment.

So to give a little more color to the use case at hand, my Windows domain controller is performing recursive lookups against my BIG-IP. My BIG-IP is configured as a recursive DNS server using a transparent cache. This simply means that I am forwarding the request to another upstream DNS server and caching its response. Pretty simple right? Well, there is a little more to it as we will get into.

My next step was to look at the DNS query to see what it looked like at the BIG-IP. After a quick search on DevCentral for an iRule to log it, I applied it to my DNS listener and tailed the log.

 
when DNS_REQUEST {     
 log local0. "my question name: [DNS::question name]"
}

Interesting enough I found that the DNS query from the DC was actually appending the DNS suffix using its actual domain name. Then I also ran a tcpdump from the BIG-IP to see the actual request which indeed confirmed the results of my logs.

I then logged into my DC to identify the network connection settings. Everything looked OK but I am of course no expert at Windows network settings. As far as I know, this is how every DC is configured by default as I have not modified any of these settings.

Now I am stuck and pretty sure the only way to modify the query is to go to the magical language of Tcl. I admit I am no expert so I did some DevCentral searches and reached out to my team who provided some great feedback. In the end, I applied the following iRule and DNS resolution is occurring without the appended DNS suffix.  Hope this helps!

when DNS_REQUEST { 
    if { [DNS::question name] ends_with "demo.lab" } { 
    set queryName [string trimright {“.demo.lab”} [DNS::question name] ] 
    log local0. "My new question name: $queryName"
    DNS::return      
    } 
}
Updated Jun 06, 2023
Version 2.0
  • if you don't want domain appended, you must end the request with a dot.

    nslookup www.google.com
    

    will first request with domain appended, then fallback to initial request

    nslookup www.google.com.
    

    will request only

  • Agreed and to be completely transparent, this article was really derived from a customers request that the user experience was not the same when performing manual lookups against the BIG-IP as it was when performing lookups against other name resolution providers. I can't say with 100% certainty though I believe they were only referring to AD which I agreed with them does not require a following . when performing a nslookup. Either way, if a customer feels there is a problem whether there is or isn't they have a solution. The basic iRule also provides some with an example of how to modify DNS queries if a particular suffix is matched. I appreciate the response Stanislas!

     

  • Hi Steve,

    your iRule does actually not rewrite the DNS request before sending it to your upstream DNS resolvers.

    Your iRule is more or less just DNS reponding on behalt of the DNS Server with an empty DNS response (a DNS response without any RRs) for every DNS request ending with "domain.lab". This will cause nslookup to skip slightly faster through your systems DNS-Suffix list resulting in a faster total response time...

    The provided rewrite part...

    set queryName [string trimright {".demo.lab"} [DNS::question name] ] 
    log local0. "My new question name: $queryName"
    DNS::return
    

    ... basically just extracts the

    [DNS::question name]
    , performs a
    [string trimright]
    and stores the new value it into the variable
    $queryName
    . The
    $queryName
    is then only be used for logging but not to overwrite the DNS query in progress. The empty DNS response is send by calling the
    DNS::return
    command (aka. you didn't defined any [DNS::answer] so the response will be empty) ...

    Additional Note: The command

    [string trimright]
    is not able to slice a given
    string
    from the right side of the provided
    input
    . The command will instead slice each single character specified in the
    char-map
    from the rigth side of the
    input
    as often as needed until a character appears in the
    input
    which is not defined in the
    char-map
    . Beside of this, your example has flipped the order of the
    char-map
    and
    input
    causing
    [string trimright]
    to remove the individual characters found in the
    char-map
    =
    [DNS::question name]
    from the hard coded
    input
    = "demo.lab".

    The shortcut of your iRule is basically this one:

    when DNS_REQUEST {
        if { [DNS::question name] ends_with ".demo.lab" } then {
             Send an empty DNS response
            DNS::return
        }
    }
    

    To rewrite DNS requests as proposed in your article you will need an iRule like this one...

    when DNS_REQUEST {
        if { [DNS::question name] ends_with ".demo.lab" } then {
             Remove ".demo.lab" DNS-Suffix from the DNS query name and forward the request
            set queryName [string range [DNS::question name] 0 end-9]
            DNS::question name $queryName
        }
    }
    

    Note: You may want to enable the debugging mode (aka.

    set d2
    ) within an interactive nslookup session, to see the differences of the individual iRules.

    Cheers, Kai

  • Kai, thanks for the feedback! Your comments are always very beneficial to the entire community.