GSLB Split DNS by iRule

Code is community submitted, community supported, and recognized as ‘Use At Your Own Risk’.

Short Description

An iRule based solution for GSLB with Split DNS (that is,  one answer for internal users,  one for external users).  

Problem solved by this Code Snippet

Split DNS GSLB can be achieved iRule-free using Topology Records as per AskF5 K14421.   However,  using Topology load balancing requires a Topology Record per pool, so two per Wide IP.  This iRule instead selects pools based on pool naming convention, so removes the need for Topology Records.   

If the iRule is attached to a Wide IP which does not have a pool named suitably for the location of the client, we fallback to dropping queries from external clients.  Internal clients will get normal GSLB behaviour.

How to use this Code Snippet

Config required:

  • One Topology-Region object defining ‘internal’ client IPs  
tmsh create gtm region private region-members add { subnet 10.0.0.0/8  subnet 192.168.0.0/16 }
  • Wide IP(s) with this iRule attached,  these should have an internal and an external pool as the Wide IP members.   The LB algorithm for the Wide IP can be anything. 
  • For the pools,  whatever LB Method your application requires, e.g. Least Connections.  You will probably want a Fallback Load Balancing Method configured on the pools, either Fallback IP or Drop Packet, to catch the scenario where all the pool members are down.  Otherwise,  GSLB will choose from the alternate pool,  leaking internal IPs to external clients.
  • Configure the iRule to reflect the naming convention of pools and the name of the Region object. The pool naming requires that pools for external clients includes some fixed string e.g. _EXT_,  and internal clients some other string e.g. _INT_.
  • You can enable debug logging in the iRule either globally or for selected Wide IPs.

Code Snippet Meta Information

  1. Version:  1.0
  2. Coding Language: TCL iRule

Full Code Snippet

# pool_region_select
# attach to Wide IP to modify pool selection behaviour
# for internal clients: select the internal pool (based on name), fallback to regular GSLB
# for external clients: select the external pool (based on name), fallback to drop packet
# internal clients are determined based on a Topology Region object
# logs warnings to /var/log/ltm on fallback so don't attach to Wide IP unless there are internal and external pools configured
# do not use Return to DNS on the pools, as that will expose IPs from both pools in responses; for a fallback when pool members are down, use Fallback IP

when DNS_REQUEST {
# set debug to 1 for global debug logging (no recommended in production)
set debug 0
# add a Wide IP to the debugwideips list to enable debug for specific Wide IP(s)
set debugwideips { /Common/app1.pri /Common/app2.pri }
# set the name of the Topology Region object
set intregion private
# set the string that must be in a Internal pool object name
set intpoolstr _INT_
# set the string that must be in a External pool object name
set extpoolstr _EXT_

# enable debug if Wide IP is selected for debug
if { [lsearch $debugwideips "[wideip name]" ] >= 0 } { set debug 1 }

if { $debug } { log local0. "Client [IP::client_addr] query for [wideip name]" }

# get list of pools for the Wide IP
set pools [pools -list]

# is the client internal based on topology region (error if an issue like no topology region defined)
if { [catch {matchregion [IP::client_addr] $intregion} isinternal] } {
log local0. "ERROR matching internal region $intregion: $isinternal, treating as external"
set isinternal 0
}

if { $debug } { log local0. "Wide IP [wideip name] has pools: {$pools} ; Is [IP::client_addr] internal? $isinternal " }

if { !($isinternal) } {
# external client - search for external pool
set foundpool [lsearch -inline $pools *$extpoolstr*]
# if we found external pool. use it
if { $foundpool != "" } {
if { $debug } { log local0. "Using external pool $foundpool for client [IP::client_addr] query for [wideip name]" }
pool $foundpool
return
}
# there was no external pool, so drop packet
log local0. "WARNING drop packet from external client to [wideip name] as we have no external ($extpoolstr) pool"
drop
return
}

# internal client - search for internal pool
set foundpool [lsearch -inline $pools *$intpoolstr*]
if { $foundpool != "" } {
pool $foundpool
if { $debug } { log local0. "Using internal pool $foundpool" }
return
}
# there was no internal pool so warn and do nothing
log local0. "WARNING defaulting to regular WideIP GSLB behaviour for internal client to [wideip name] as we have no internal ($intpoolstr) pool"
}

 

 

Published Oct 04, 2022
Version 1.0
  • if clients sends dns A request not directly to f5 gtm, then we can use multiple cname method below which doesnt need irules.

    as example for A hostname www.mycompany.com:
    a. make external/public dns server to cname www.mycompany.com to www.externalgtm.company.com.
    b. make internal/private/intranet dns server to cname www.mycompany.com to www.internalgtm.company.com.
    c. in the external and internal dns servers: make f5 gtm as name servers for both domains externalgtm.company.com. and internalgtm.company.com.
    d. add externalgtm.company.com and internalgtm.company.com into gtm zone runner's zone list.
    e. create manual gtm vserver with public ip address (dependency can be set to relevant ltm vserver)

    f. create 2 gtm wideip (www.externalgtm.company.com and www.internalgtm.company.com) then bind proper pools and pool members for them, i.e:
    www.externalgtm.company.com gets pool members on public ip addresses,
    while www.internalgtm.company.com gets pool members on private ip addresses