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.

Load balancing based on ASP SessionID

Problem this snippet solves:

The code separates into 2 irules, one for request and one for response. The app in question only issues out 1 cookie. The al_start.asp? starts the session adn teh session will end with al_stop.asp or with a timeout so this what the irules rotate around

Code :

#request irule

when RULE_INIT { 
        #initialize the arrays the first time the irule is called 
        array set ::sessiontrackingarray {} 
        array unset ::sessiontrackingarray 
    array set ::sessionlbarray {} 
        array unset ::sessionlbarray 
}   
 when HTTP_REQUEST { 
    set debug 0 
        #scan http header for asp session cookies if the cookie exists set sessionid to the cookie value 
        set sessioncookie [findstr [HTTP::cookie names] "ASPSESSION" 0 20] 
    set sessionid [HTTP::cookie $sessioncookie] 
        #set the time to current, set the idle time to current -121 seconds. 
    set currtime [clock seconds] 
    set expiredtime [expr {$currtime} - 121] 
    set poolname nameofpool 
    set server1lb 0 
    set server1ip "x.x.x.x"  #ip address omitted this would be the ip address of the first pool member
    set server2lb 0 
    set server2ip "x.x.x.x"  #ip address omitted this would be the ip address of the second pool member
    set server3lb 0 
    set server3ip "x.x.x.x"  #ip address omitted this would be the ip address of the third pool member
    set server4lb 0 
    set server4ip "x.x.x.x"  #ip address omitted this would be the ip address of the fourth pool member 
        # Search for ASP Session Cookie 
    if { not ([HTTP::cookie exists "$sessioncookie"])} { 
                # If request is not "al_start.asp?", exit iRule and follow default pool and LB Method 
        if { not ([HTTP::uri] contains "al_start.asp?") } { 
                  return 
                } 
        else { 
                # if there are no values in the sessionlbarray - i.e al_start.asp? seen, exit irule and just use the lb method for the pool 
        #  if {not [array names ::sessionlbarray]} { 
                #                pool $poolname 
        #        return 
                #        } 
        #    else { 
                                # Scan array and delete old/hung sessions.  Any session that has a timestamp in the sessiontracking array older than the $expiredtime variable will be deleted 
                                # from both the session tracking array and lbtracking array so that it is not considered when making the lb decision 
                foreach sesskey [array names ::sessiontrackingarray] { 
                    set sessiontime $::sessiontrackingarray($sesskey) 
                   if { $debug }{ log local0.info "for session $sesskey sessiontime is $sessiontime and expiredtime is $expiredtime" }
                                        if { $sessiontime < $expiredtime } {   
                                       if { $debug }{   log local0.info "session last touched time of $sessiontime for session $sessionid is over 121 seconds old. removing session from tracking arrays" }
                        unset ::sessiontrackingarray($sesskey) 
                        unset ::sessionlbarray($sesskey) 
                    } 
                } 
                                # Session on each server count 
                              if { $debug }{  log local0.info "array sessionlbarray [array size ::sessionlbarray]" }
                foreach lbentry [array names ::sessionlbarray] { 
                                        if { $debug }{log local0.info "lbentry is $lbentry sessionarraylb is $::sessionlbarray($lbentry)"} 
                    switch $::sessionlbarray($lbentry) { 
# masking ip addresses at customer request
                        "x.x.x.x" {set server1lb [expr {$server1lb} + 1]} 
                        "y.y.y.y" {set server2lb [expr {$server2lb} + 1]} 
                        "z.z.z.z" {set server3lb [expr {$server3lb} + 1]} 
                        "w.w.w.w" {set server4lb [expr {$server4lb} + 1]} 
                    } 
                                } 
                                # Set Count Array to hold session count and server IP. 
                                
                                set counterarray($server1ip)  $server1lb 
                                set counterarray($server2ip)  $server2lb 
                                set counterarray($server3ip)  $server3lb 
                                set counterarray($server4ip)  $server4lb 
                                if { $debug }{  log local0.info "server1count is $server1lb, server2count is $server2lb, server3count is $server3lb, server4count is $server4lb" }
                                #test the pool member status.  If a pool member is down, remove it from the temporary array counterarray so that is 
                                #is not considered when making the lb decision 
                                foreach membercheck [array names counterarray] { 
                                        if { $debug }{log local0.info "membercheck is $membercheck, array element value is $counterarray($membercheck)"} 
                                        if { not ([LB::status pool $poolname member $membercheck 80] eq "up") }{ 
                                                if { $debug }{log local0.info "pool status is [LB::status pool $poolname member $membercheck 80]"} 
                                                  unset counterarray($membercheck) 
                                                if { $debug }{ log local0.info "removing server $membercheck from the counterarray"}   
                                                  } 
                                        }   
                                        set lbholder 1000000000 
                                        foreach lbcounter [ array names counterarray ] { 
                                                if { $lbholder > $counterarray($lbcounter) }{ 
                                                        set lbholder $counterarray($lbcounter) 
                                                        set ipholder $lbcounter 
                                                } 
                                        } 
                                # set the variable winner to the lowest value of the server session counters         
                        #        set winner [lindex [lsort -integer { array get counterarray }] 0] 
                                if { $debug }{ log local0.info " load balancing to $ipholder"} 
        #                        persist cookie insert cookie_cco 
                                if { $debug }{log local0.info "setting pool $poolname to lb to member $ipholder"} 
                                pool $poolname member $ipholder 80 
                                if { $debug }{ log local0.info "pool member $ipholder status is [LB::status]"} 
                                                return 
                                        } 
                #} 
        } 
        else { 
                pool $poolname 
                persist uie [HTTP::cookie "$sessioncookie"] 1200   
                # When cookie exists and it's NOT "AL_STOP.asp", reset session timestamp 
                if { not ([string tolower [HTTP::uri]] contains "al_stop.asp")} { 
                        set ::sessiontrackingarray($sessionid) $currtime 
                        if { $debug }{  log local0.info "new timestamp for session $sessionid is $::sessiontrackingarray($sessionid)" }
                } 
                else { 
                 if { $debug }{  log local0.info "al_stop seen.  removing $sessionid entries from both arrays" }
                unset ::sessiontrackingarray($sessionid) 
                unset ::sessionlbarray($sessionid) 
                } 
        } 
} 

#response irule

when HTTP_RESPONSE { 
        set debug 0 
        set currtime [clock seconds] 
        set sessioncookie [findstr [HTTP::cookie names] "ASPSESSION" 0 20] 
        set sessionid [HTTP::cookie $sessioncookie] 
        if { $debug } { log local0.info "sessionid is $sessionid"} 
        if { $debug }{ log local0.info "asp session cookie name is $sessioncookie " } 
        # test to see if the IIS server is setting a cookie 
    if { not [HTTP::header exists "Set-Cookie"] } {     
                if { $debug }{log local0.info "no set cookie in http response, exiting"} 
                return } 
    else { 
                        if { [HTTP::cookie exists "$sessioncookie"] } { 
                       persist add uie [HTTP::cookie "$sessioncookie"] 1200 
                } 
                #  add sessionid and time to the session time tracking array 
                set ::sessiontrackingarray($sessionid) $currtime 
                        if { $debug }{log local0.info "adding sessionid [HTTP::cookie "$sessioncookie"] to sessiontracking array with clock value $currtime"} 
                        # add sessionid and lb server to the array tracking sessions to server 
            set ::sessionlbarray($sessionid) [LB::server addr] 
                        if { $debug }{log local0.info "adding session [HTTP::cookie "$sessioncookie"] to array sessionlbarray with server value [LB::server addr]"} 
    } 

}
Published Mar 18, 2015
Version 1.0
No CommentsBe the first to comment