Outlook Anywhere Persistence with Cookie Backup

Problem this snippet solves:

The deployment guide for Microsoft Exchange Server 2007 (http://www.f5.com/pdf/deployment-guides/f5-exchange07-dg.pdf)) specifies that Universal persistence is required for the proper functioning of Outlook Anywhere, and it provides a iRule for this purpose. If the same virtual server is being used for Outlook Web Access, however, you cannot apply a standard cookie persistence profile at the same time.

Therefore, the following iRule expands upon the iRule provided in the deployment guide to reproduce basic cookie persistence behavior. This cookie persistence is not as complete as the built-in cookie persistence feature, but it is functional when load balancing to the default pool.

Code :

when RULE_INIT {
  # see SOL6917 for cookie encoding details: https://tech.f5.com/home/solutions/sol6917.html        
  set ::debug 0
} 

when HTTP_REQUEST {
  set reselect_retries 0
  set persistCookieNeeded 0
  if { [HTTP::header exists "Authorization"] } {
    # If we detect this header, do Universal persistence as specified in the deployment document
    persist uie [HTTP::header "Authorization"]
    if {$::debug != 0}{log local0. "Outlook client detected at [IP::client_addr]:[TCP::client_port]"}
  }
  else
  {
    # Implement cookie persistence manually. Will only work with the default pool.
    if { [HTTP::cookie exists "BIGipServer[LB::server pool]"] }
    {
      if { [catch {
        scan [HTTP::cookie "BIGipServer[LB::server pool]"] "%d.%d.%d" myIpE myPortE unused
        if {$::debug != 0}{log local0. "myIpD=$myIpE   myPortE=$myPortE  unused=$unused"}
        # calculate IP
        set myIpH [format %08x $myIpE]
        if {$::debug != 0}{log local0. "myIpH=$myIpH"}
        set myIpD "[expr 0x[substr $myIpH 6 2]].[expr 0x[substr $myIpH 4 2]].[expr 0x[substr $myIpH 2 2]].[expr 0x[substr $myIpH 0 2]]"
        if {$::debug != 0}{log local0. "myIpD=$myIpD"}
        # calculate port
        set myPortH [format %x $myPortE]
        if {$::debug != 0}{log local0. "myPortH=$myPortH"}
        set myPortD [string trimleft [expr 0x[substr $myPortH 2 2]][expr 0x[substr $myPortH 0 2]] 0]
        if {$::debug != 0}{log local0. "myPortD=$myPortD"}
    
        # Send the request to the indicated pool member, cheating to use only port 80
        pool [LB::server pool] member $myIpD $myPortD
        } ] }
      { 
        set persistCookieNeeded 1
        if {$::debug != 0}{log local0. "We could not decipher a cookie with name BIGipServer[LB::server pool]"}
      }
    }
    else
    {
      set persistCookieNeeded 1
      if {$::debug != 0}{log local0. "We do not detect a cookie with name BIGipServer[LB::server pool]"}
    }
  } 
}

when LB_FAILED {
  if { ( $reselect_retries == 0 ) and ( [active_members [LB::server pool]] > 0 ) }
  {
    LB::detach
    LB::reselect [LB::server pool]
    set reselect_retries 1
    if { not ( [HTTP::header exists "Authorization"] ) } {set persistCookieNeeded 1}
    if {$::debug != 0}{log local0. "[LB::server pool]/[LB::server addr]:[LB::server port] down, reselecting"}
  }
}

when HTTP_RESPONSE {
  if { $persistCookieNeeded }
  {
    # calculate IP section
    scan [LB::server addr] "%d.%d.%d.%d" poolIP1 poolIP2 poolIP3 poolIP4 
    set poolIPE [expr $poolIP4 * 16777216 + $poolIP3 * 65536 + $poolIP2 * 256 + $poolIP1 ]
    if {$::debug != 0}{log local0. "poolIPE=$poolIPE"}
    # calculate port section
    set poolPortE [expr 0x[substr [format %04x [LB::server port]] 2 2][substr [format %04x [LB::server port]] 0 2]]
    if {$::debug != 0}{log local0. "poolPortE=$poolPortE"}

    # Insert cookie
    HTTP::cookie insert name "BIGipServer[LB::server pool]" value "$poolIPE.$poolPortE.0000"
    if {$::debug != 0}{log local0. "BIGipServer[LB::server pool] value is $poolIPE.$poolPortE.0000"}
  }
}
Published Mar 18, 2015
Version 1.0
No CommentsBe the first to comment