cancel
Showing results for 
Search instead for 
Did you mean: 
Eric_Chen
F5 Employee
F5 Employee

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
Comments
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
Eric_Chen
F5 Employee
F5 Employee
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.
Chris_G_01_1415
Nimbostratus
Nimbostratus
Do we know if there is any way to get this working in 11.5.3 or 11.5.4?
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]]
mchaas
Nimbostratus
Nimbostratus

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_Chen
F5 Employee
F5 Employee

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_104974
Historic 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_372679
Nimbostratus
Nimbostratus

hello, is it possible to configure persistency based on the source IP captured via the eDNS header ?

 

Eric_Chen
F5 Employee
F5 Employee

@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_372679
Nimbostratus
Nimbostratus

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.

 

Nabarun
Nimbostratus
Nimbostratus

Hi ,

 

Is it require any extra license for EDNS ? Can support EDNS on 12.1.3.5 version ?

 

SWJO
Cirrostratus
Cirrostratus

Hi

 

Can I get sample VIP configuration which LTM i-Rule applied for?

 

with regards,

 

Thanks for the article. Actually it would be helpful to get the address familiy information as well to differentiate between IPv4 and IPv6 addresses provided in the EDNS0-ECS extension.

According to RFC7871 the client indicates the address family, the prefix lenght, scope and the part of the IP address matching the prefix length. Trailing zeros wont be transmitted. So a network of 64.64.64.0/24 would be send with an IP address familiy of x00 x01 (IPv4), a hex string of x18 (Prefix Len of 24) and a pattern of x40 x40 x40 indicating the network. Bits after the prefix wont be send as truncating according to prefix len is mandatory. Dumping the [DNS::edns0 subnet address] returns an address of 64.64.64.254, which is obviously wrong. Problems appear when trying to apply a binary scan to the result. To work around the issue I need to pad the missing zeros to convert the pattern into a proper IP address for further processing. Without information about the address family I cannot differentiate between IPv4 and IPv6. Is there a solution planned? Thanks in advance, Stephan

Eric_Chen
F5 Employee
F5 Employee

Stephan, it's been a long time since I looked at this code. Since this became a feature in 14.1.x I'd recommending using that version if possible. Otherwise I'm not sure the best way to pad the number to deal with the issue that you're describing.

Hi Eric,

thanks for the quick reply. My client is running v12 and the same behaviour with the fuction was observed in v14 unfortunately.

Actually my client needs to handle specific DNS requests in the listener iRule completely without forwarding them internally to gtmd/bind.

So we cannot use the built-in feature.

My concern is, that the function always parses 4 bytes even the query contains only the network address according to the prefix length.

This might result in bad memory allocation ...

To handle the EDNS0-ECS information properly for IPv4 I worked around as follows:

if {[DNS::edns0 exists] &! [catch { DNS::edns0 subnet address }]} { set ecs_prefix [DNS::edns0 subnet source] set ecs_scope [DNS::edns0 subnet scope] # generate a string equivalent to prefix length (expr (pow) not implemented); missing bits padded by zeros) and scan to vars binary scan [binary format B32 [string repeat 1 ${ecs_prefix}]] cccc maskd1 maskd2 maskd3 maskd4 #log local0. "\[DNS::edns0 subnet address\]: [DNS::edns0 subnet address] (\[DNS::edns0 subnet source\]: [DNS::edns0 subnet source])" # mask provided IPv4 address with prefix set ecs_subnet_masked [IP::addr [DNS::edns0 subnet address] mask [expr {${maskd1} & 0xff}].[expr {${maskd2} & 0xff}].[expr {${maskd3} & 0xff}].[expr {${maskd4} & 0xff}]] unset maskd1 maskd2 maskd3 maskd4 log local0. "masked EDNS0-ECS subnet: ${ecs_subnet_masked}/${ecs_prefix} ([whereis ${ecs_subnet_masked} country])" }

I will do some further testing with EDNS0-ECS providing IPv6 information.

As mentioned before, it would be great to get an extension to the DNS::edns0 subnet function to check the address family value.

Otherwise I need to implement an additional test for the address type.

(Perhaps its already there and just not documented?)

I will open a service request with the F5 support team and keep you posted.

Cheers, Stephan

 

 

In service request C3152801 the F5 support confirmed a bug (ID832769: [DNS::edns0 subnet address] printing random octets when edns client subnet mask is /24 or lower) for TMOS v12 which is fixed in TMOS v14.

In case you are using DNS::return in your TMOS v12 iRule, the EDNS0-ECS information will be inserted automatically. So there is no need to insert this information in the context of DNS_RESPONSE.

But in case the request is handled by gtmd or bind you will need to insert the EDNS0-ECS information the DNS_RESPONSE context.

TMOS v14 has changes in behaviour and fixes. In case you are upgrading, review your iRules, please.

Version history
Last update:
‎16-Jun-2015 05:28
Updated by:
Contributors