Implementing Client Subnet DNS Requests

Problem this snippet solves:

Update 2018-10-23: As of BIG-IP DNS 14.0 there is now a checkbox feature for edns-client-subnet. Please see: Using Client Subnet in DNS Requests. The following is still useful if you want to customize your responses.

Original post:

Using an iRule and edns-client-subnet (ECS) we can improve the accuracy of F5 GTM’s topology load balancing.

How to use this snippet:

There are two different iRules. One is an LTM iRule and the second is a GTM iRule. These should be deployed separately.

Code :

#
# LTM iRule
#
# comply with draft to respond with ECS  
when DNS_REQUEST {  
  if { [DNS::edns0 exists] &! [catch { DNS::edns0 subnet address }] } {  
    set ecs_address [DNS::edns0 subnet address]  
    set ecs_source [DNS::edns0 subnet source]  
    set ecs_scope [DNS::edns0 subnet scope]  
    log local0. "Received EDNS request from [IP::client_addr]:$ecs_address/$ecs_source/$ecs_scope"  
  }  
}  
when DNS_RESPONSE {  
  if { [info exists ecs_address] } {  
  DNS::edns0 subnet address $ecs_address  
  DNS::edns0 subnet source $ecs_source  
  #DNS::edns0 subnet scope $ecs_scope  
  # hardcode the desired scope to be /24, not sure this is OK  
  DNS::edns0 subnet scope 24  
  }  
}
#
# GTM iRule
#  
when DNS_REQUEST {  
  set ldns [IP::client_addr]  
  log local0. "LDNS LOC: $ldns [whereis $ldns]"  
  
  if { [DNS::edns0 exists] &! [catch { DNS::edns0 subnet address }] } {  
    set gtm_ecs_address [DNS::edns0 subnet address]  
    set gtm_ecs_source [DNS::edns0 subnet source]  
    set gtm_ecs_scope [DNS::edns0 subnet scope]  
    set ldns  $gtm_ecs_address  
    log local0. "ECS LOC: $gtm_ecs_address [whereis $ldns]"  
  }  
  set loc [whereis $ldns]  
  
  if { $loc contains "NA" } {  
    log local0. "NA"  
  }  
  elseif { $loc contains "AS" } {  
    log local0. "Asia"  
  }  
  elseif { $loc contains "EU" } {  
    log local0. "Europe"  
  } else {  
    log local0. "All other"  
  }  
  
}

Tested this on version:

11.6
Published Jun 16, 2015
Version 1.0

Was this article helpful?

16 Comments

  • Matt, if you have a second LTM/GTM device it is possible to SNAT the connection to match the ecs_address. You end up with something like:

    when DNS_REQUEST {
    ...
      snat $ecs_address
    ...
    }
    

    This works by using a feature of LTM/GTM of auto last hop to route the snat'd traffic back to the original device that received the request. It assumes that both LTM/GTM devices are L2 adjacent.

    The config is

    Device 1: LTM listener with DNS profile/LTM iRule performing SNAT. Pool is GTM listener on Device 2. Device 2: GTM listener with DNS profile (vanilla GTM)

    Traffic flow:

    Internet (LDNS IP) -> Device 1 (SNAT to ECS IP) -> Device 2 -> Device 1 -> Internet

    Be warned that you are trusting the ECS records to intentionally spoof traffic to Device 2. I have only tested this in a lab environment and have noted that it does some weird things to the EDNS records that get passed along to Device 2.

  • mchaas's avatar
    mchaas
    Icon for Nimbostratus rankNimbostratus

    Hi,

     

    is there a way to tamper with the DNS response based on this information? We are running GTM. When the listener is receiving a DNS query, I would like to decide which virtual server out of the selected pool is used and posted back in the dns response depending on both location (based on the EDNS information) AND availability of the respective resource.

     

    So, ideally, in analogy to the GSLB "Topology Record Builder" settings, I would like to set the datacenter information, but not based on the Client-IP in the Layer3 Header, but based on the EDNS client information, as shown in the code snippet.

     

    Is this possible? Thanks!

     

    Regards, Matt

     

  • bodra_143113's avatar
    bodra_143113
    Historic F5 Account
    the whereis fails due to a bug As a workaround you can force a string interpretation of the IP i.e. set loc [whereis [string tolower $ldns]]
  • Hi, I'm seeing a similar result with using 11.5.3. I agree that the issue appears to be with passing the variable $gtm_ecs_address to whereis and getting back an empty response. When I created the iRule I had tested with 11.6.0, but not with 11.5.3. I'll update the codeshare to reflect that this works 11.6.0 and forward.
  • tiny_cloud_ninj's avatar
    tiny_cloud_ninj
    Historic F5 Account
    Testing this iRule in TMOS 11.5.3 HF1 without success. It looks as if whereis is not returning a value. on test DNS ./bin/dig/dig @10.1.10.100 record.siterequest.com +client=8.8.8.8 A Dec 20 18:36:53 gtm info tmm1[12620]: Rule /Common/mvpn_EDNS_iRule : LDNS LOC: 10.1.10.222 Dec 20 18:36:53 gtm info tmm1[12620]: Rule /Common/mvpn_EDNS_iRule : ECS LOC: 8.8.8.8 Dec 20 18:36:53 gtm info tmm1[12620]: Rule /Common/mvpn_EDNS_iRule : defualt