Forum Discussion

Mariusz_B's avatar
Mariusz_B
Icon for Nimbostratus rankNimbostratus
Jan 16, 2015

GTM iRule - answering DNS based on some criteria.

Hi, I need some help with developing an iRule for DNS queries. Requirements:

 

  • check IP range a request came from (this is the easy bit which I have done already)

     

  • check monitor status - if specific IP is responding (on the client site - over VPN, MPLS, or any other private connection), answer the query with host (member) A, if the IP is not responding answer with host (member) B (this is the bit I am straggling with).

     

Any help much appreciated.

 

Regards Mariusz

 

11 Replies

  • Have you thought about using a wideIP with two different pools with monitors attached? Setup your wideIP with global availibility with host A being in the pool with order 0.

     

  • Thanks Brad.

    At the moment I have one pool per wide IP which contains one server from DC1 and one server from DC2, with global fail-over as LB method so it's something similar to your suggestion. This works fine for one client, but I need to have a separate monitor for every single client. I don't want to re-direct all my MPLS and VPN clients if only one line fails. The idea is for GTM in DC2 to response with DC1 wide IP only, if the primary line (to DC1) fails. The problem is related to Linux BIND forwarder which does round-robin instead of global fail-over.

    I hope that make more sense now.

    Is it possible to refer to a monitor status in iRule?

    So far I have the following:

    when DNS_REQUEST 
     if { [IP::addr [IP::client_addr] equals 10.1.10.136/29] or [IP::addr [IP::client_addr] equals 10.10.10.64/27] or [IP::addr [IP::client_addr] equals 10.1.10.96/28] } {
          if {monitor status which pings client IP is up } {
            host 1.1.1.1
            else
            host 1.1.1.2
    

    So I am just trying to find the missing function.

  • How about somthing like this:

    when DNS_REQUEST {
        if { [IP::addr [IP::client_addr] equals 10.1.10.136/29] or [IP::addr [IP::client_addr] equals 10.10.10.64/27] or [IP::addr [IP::client_addr] equals 10.1.10.96/28] } {
            if {LB::status vs   up} {
                host 1.1.1.1
            }
            else {
                host 1.1.1.2
            }
        }
    }
    

    You may also try using a data group if you ever decide to expand or change the IPs your are checking for.

  • Thanks for suggestion with the data group.

     

    I'll test this on Monday and let you know the outcome.

     

    Many thanks!

     

  • Hi Brad,

    I have now developed this:

    when DNS_REQUEST {
      if { [IP::addr [IP::remote_addr] equals $::All_Client_IPs] } {
          if {[LB::status vs Client_VPN_1] eq "up" } {     
            host 1.1.1.1
          } else {
            host 2.2.2.2
        }
      }
    }
    

    but it doesn't work. Looks like is not possible to use data groups from the GSLB level.

    I have successfully tested this instead:

    when DNS_REQUEST {
      if { [IP::addr [IP::remote_addr] equals 10.10.10.10] } {
          if {[LB::status vs Client_VPN_1] eq "up" } {     
            host 1.1.1.1
          } else {
            host 2.2.2.2
        }
      }
    }
    

    it's ok, but bit painful to use multiple "or" statements for multiple network ranges/IPs

    Is there any workaround for that?

    Many thanks

    Mariusz

  • Hi Mariusz,

    you can use a jump table (aka "switch") command to evaluate multiple conditions:
    switch [IP::remote_addr] {
    "10.10.10.10" if {[LB::status vs Client_VPN_1] eq "up" } {     
          host 1.1.1.1
       } else {
          host 2.2.2.2
       }
    "20.20.20.20" if {[LB::status vs Client_VPN_2] eq "up" } {     
          host 3.3.3.3
       } else {
          host 4.4.4.4
       }
    }
    

    I´m not aware of another shortcut to simplify the VS availability check.

    Thanks, Stephan
  • Are you using BigIP 11.x? If so, you can't use $::All_Client_IPs. Try this:

    when DNS_REQUEST {
      if { class match [IP::remote_addr] equals All_Client_IPs } {
          if {[LB::status vs Client_VPN_1] eq "up" } {     
            host 1.1.1.1
          } else {
            host 2.2.2.2
        }
      }
    }
    
  • Hi guys,

    Thank you both for your suggestions.

    @Stephan

    I just did a small tweak to get this working, as it was complaining about a missing statement:

    when DNS_REQUEST {
      switch [IP::remote_addr] {   
      "10.10.100.0/24" {
        if {[LB::status vs LInk_Test_GTM] eq "up" } {     
            host 1.1.1.1
          } else {
            host 2.2.2.2
          }
       }
      "10.10.200.0/24" {
       if {[LB::status vs LInk_Test_GTM] eq "up" } {  
            host 1.1.1.1
          } else {
            host 2.2.2.2
          }
      } 
       "10.10.10.10" {
        if {[LB::status vs LInk_Test_GTM] eq "up" } {  
            host 1.1.1.1
          } else {
            host 2.2.2.2
          }
       }
     }
    }
    

    @Brad

    Tried this way as well, but I get "invalid IP address" error. With the "$" sign syntax is accepted, but I am observing errors in the GTM log (this is probably valid for predefined variables within the iRule only). Data groups option is only available from DNS>Delivery>iRules>Data Group List, but I need the iRule to be created/applied on GSLB section where DGL is missing (there is only GSLB>iRules available). Unless there is a way to create them "on the fly" within the iRule...

    • Brad_Parker's avatar
      Brad_Parker
      Icon for Cirrus rankCirrus
      If the switch method is working that's all that matters, its more than ok to do it that way. I think with the small list you are working with here it would actually be a little more efficient using the switch, though it would probably be a negligible performance difference.
  • We use separate pools for each answer and just base it off whether the pool has any active members.

                        if {[active_members pool1] < 1 }{
                           DNS::disable all
                           pool pool2
                        } else {
                           DNS::disable all
                           pool pool1
                        }