Control recursive DNS queries

Hi all,
I’m wondering if/how in aFlex I might be able to allow or deny recursive DNS queries based off a source IP list. For example, if a remote IP not on the list has the recursive bit set in the query, the A10 will block the query outright instead of forwarding it to the DNS server.

Using an aFleX per your DNS requirements will not work. The A10 aFleX scripting does not have the capability to store any prior request by the same source IP into memory. I would suggest to contact your regional SE to discuss and post a feature request if no other option available.

Genard

Maybe I am simplifying or not fully understanding, but I don’t want to store previous requests in memory. I want to define something like a class list (F5 terminology) and have aFlex check requests against that list.

This aFlex can allow or deny recursive DNS queries based in one IPlist. This must have the source ip address.

You will need create a class-list (in this example the class list name is HOST_LIST)
You will need change the comments to do what you want, if you want to drop the connection you need change the comment by the command ‘drop’.

aFlex Code:

when RULE\_INIT \{
    set ::HOSTLIST HOST\_LIST ;\# Class List used for hosts and configured in partition
\}

when CLIENT\_ACCEPTED \{
    set ::IPADDR [IP::client\_addr] ;\# Ip address of client
\}

when DNS\_REQUEST \{
    if \{ [DNS::header rd] == 1 \} \{ \# verify if is a recursive DNS
       if \{ not [CLASS::match $::IPADDR $::HOSTLIST ip] \} \{
          \# do something if IP isn't in the class\_list, could be drop
       \} else \{
          \# do other thing if IP is in the class\_list
       \}
    \} else \{

# do something if query is not recursive

    \}
\}

Thanks for the response. I ended up opening a ticket with A10 and they helped me create a script:

when DNS_REQUEST {
        if {!([DNS::question name] equals ".")} {
        set fqdn .[DNS::question name]
        }
        if { ([CLASS::match $fqdn ends_with auth_dns]) and not ([CLASS::match [IP::client_addr] local-ips ip]) } {
        forward
        } elseif { [CLASS::match [IP::client_addr] local-ips ip] } {
        forward 
        } elseif { [DNS::header rd] equals "1" } {
                if { not [CLASS::match [IP::client_addr] local-ips ip] } {
                DNS::header qr 1
                DNS::header rcode 5
                DNS::return
                }
        }
}

I ended up having to create two class-lists, one with IP addresses that are allowed to recurse and one with locally-hosted zone files:

class-list auth_dns string 
 str .foo.com forward
 str .bar.com forward
class-list local-ips  
 192.168.103.0 /24
 172.19.52.0 /24
 172.21.31.0 /24

The locally hosted zone file list is required because by default, normal DNS queries have the RD bit set, so we needed to allow those requests through, even though they are locally hosted zone files. I also needed to create a pretty much exact copy for IPv6 addresses, too. I wasn’t sure if I’d be able to add both v4 and v6 into the same aFlex script, given that the script is applied on a per-VIP basis.