For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Hostname based Load balancing (prior to 11.6.0)

Problem this snippet solves:

This code is initially developed to provide a forward proxy to Apple Push Notification Services. This code can easily be customized to load balance requests to any resolved FQDN.

Several issues are solved here :

  • Forward proxy for several Apple APNs services like gateway.push.apple.com and feedback.push.apple.com
  • Hostname based loadbalancing for BIG-IP under version 11.6.0
  • Source address persistence using tables (because when using the node command, persistence settings doesn't works)

How to use this snippet:

Installation

This irule can be installed on multiple VS at the same time or on a wilcard VS.

During several tests, we configured the following Virtual Server settings :

ltm virtual vs_wildcard_apns {
    description *.push.apple.com
    destination 192.168.20.200:any
    ip-protocol tcp
    mask 255.255.255.255
    profiles {
        fastL4 { }
    }
    rules {
        irule_apns
    }
    source 0.0.0.0/0
    source-address-translation {
        type automap
    }
    translate-address enabled
    translate-port disabled
    vs-index 9
}

Code :

when RULE_INIT {
    set static::nameserver "8.8.8.8"
    set static::max_age 1800
}
 
when CLIENT_ACCEPTED {
  switch [TCP::local_port] {
    "2195" {
        set host "gateway.push.apple.com"
    }
    "2196" {
        set host "feedback.push.apple.com"
    }
    default {
        log local0. "virtual=[virtual], src=[IP::client_addr], dst=$dest:[TCP::local_port], action=reject, reason=\"Request not allowed\""
        reject
        return
    }
  }
  
  # resolve the hostname using table or dns lookup
  if { [table lookup "$host.[IP::client_addr]"] ne "" } {
    set dest [table lookup "$host.[IP::client_addr]"]
    log local0. "virtual=[virtual], src=[IP::client_addr], dst=$dest:[TCP::local_port], action=resolve, reason=\"from table\""
    node $dest [TCP::local_port]
  
  } else {
    set dest [lindex [RESOLV::lookup @$static::nameserver -a $host] 0]
    log local0. "virtual=[virtual], src=[IP::client_addr], dst=$dest:[TCP::local_port], action=resolve, reason=\"from dns\""
    
    if { $dest ne "" } {
        table set "$host.[IP::client_addr]" "$dest" indefinite $static::max_age
        node $dest [TCP::local_port]
        log local0. "virtual=[virtual], src=[IP::client_addr], dst=$dest:[TCP::local_port], action=forward"
  
    } else {
        log local0. "virtual=[virtual], src=[IP::client_addr], dst=$dest:[TCP::local_port], action=reject, reason=\"DNS resolution failed\""
        reject
        return
    }
  }
}
 
when CLIENT_CLOSED {
   table delete conn:[IP::client_addr]:[TCP::client_port]
}

Tested this on version:

11.3
Updated Jun 06, 2023
Version 2.0
No CommentsBe the first to comment