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.
- DevCentral Article: Implementing Client Subnet DNS Requests
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- tiny_cloud_ninjHistoric F5 AccountTesting 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
- Eric_ChenEmployeeHi, 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.
- Chris_G_01_1415NimbostratusDo we know if there is any way to get this working in 11.5.3 or 11.5.4?
- bodra_143113Historic F5 Accountthe 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]]
- mchaasNimbostratus
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
- Eric_ChenEmployee
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.
- gbbaus_104974Historic F5 Account
As an FYI for anyone testing, using a recent DIG version (eg 9.10), the "+subnet" is used to send a ENDS0 request , eg:
$ dig @10.1.10.53 +subnet=205.168.2.3/32
The response should show
;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096
; CLIENT-SUBNET: 205.168.2.3/32/0
;; QUESTION SECTION:
- alex_372679Nimbostratus
hello, is it possible to configure persistency based on the source IP captured via the eDNS header ?
- Eric_ChenEmployee
@alex. Not sure if you saw that this is now a feature in BIG-IP DNS 14.0 (I just updated this post to mention that as well). Using Client Subnet in DNS Requests.
 
If you are not running BIG-IP DNS 14.0; then you could potentially use a custom persist method with an iRule: K7392 talks about using HTTP URI, but you could use the string value from eDNS in theory. I haven't thought it through fully, so not sure that would work.
 
- alex_372679Nimbostratus
hi Eric, i have the feeling version 14.0 + 14.1 are not stable and recommended versions yet. i am right to saythe irule in the K7392 only applies to LTM and not GTM ?
thanks in advance.