iRule to take POST arguments named "SESSION" and use the numeric value as a universal persistence key
iRule designed by Matt Jannusch of FishNet Security
when RULE_INIT {
set ::debug 1
set ::term "\""
log local0. "persist_SESSION_postarg iRule initialized."
}
when HTTP_REQUEST {
See if we've got an incoming ASPSESSIONID cookie, if so - try to find a persistence record to match.
set ::postMethod 0
set cli [IP::remote_addr]:[TCP::remote_port]
set SessionID ""
set SessionID [findstr [HTTP::cookie names] "ASPSESSIONID" 12 8]
if {$::debug}{log local0. "Client: $cli Request SessionID: >$SessionID<"}
if { $SessionID != "" } { persist uie $SessionID 6000 }
Determine if the incoming request is a form POST - if it is, flag it for later when we are watching server responses.
POSTs need to be scanned for our SESSION argument value for persistence, and the server replies must be
watched for them embedded in the form as well.
if {[HTTP::method] equals "POST" } {
If it is a POST, grab all the packet data of the response, it could be multiple packets
set ::postMethod 1
if { [HTTP::header exists "Content-Length"] } {
set content_length [HTTP::header "Content-Length"]
} else {
set content_length 1000000000
}
if { $content_length > 0 } {
if {$::debug}{log local0. "POST method detected, collecting $content_length bytes" }
HTTP::collect $content_length
}
else {
pool pool_www.xxxxxxx.com
}
}
}
when HTTP_REQUEST_DATA {
We have the whole request, now parse it to look for the SESSION postarg's value, if it exists.
if {$::debug}{log local0. "POST Data: [HTTP::payload]"}
set namevals [split [HTTP::payload] "&"]
for {set i 0}{$i < [llength $namevals]} {incr i} {
set params [split [lindex $namevals $i] "="]
if {$::debug}{log local0. " [lindex $params 0] : [lindex $params 1]"}
if {[lindex $params 0] equals "SESSION"} {
Found it! Persist on the value of SESSION
if {$::debug}{log local0. "Param length is [string length [lindex $params 1]]"}
First response from login .dll is a blank SESSION arg, don't try to persist on that!
if { [string length [lindex $params 1]] > 12 } {
persist uie [lindex $params 1]
}
}
}
}
when HTTP_RESPONSE {
set cli [IP::remote_addr]:[TCP::remote_port]
set SessionID [findstr [HTTP::cookie names] "ASPSESSIONID" 12 8]
if {$::debug}{log local0. "Client: $cli Response SessionID: >$SessionID<"}
if { $SessionID != "" }{ persist add uie $SessionID 6000 }
if {$::postMethod} {
First entry on application is a POST request with a blank SESSION argument (no value).
if {$::debug}{log local0. "POST response from server, collecting [HTTP::header Content-Length] bytes."}
if { [HTTP::header exists "Content-Length"] } {
set content_length [HTTP::header "Content-Length"]
} else {
set content_length 1000000000
}
if { $content_length > 0 } {
if {$::debug}{log local0. "Response to post, collecting $content_length bytes" }
HTTP::collect $content_length
}
HTTP::collect $content_length
}
}
when HTTP_RESPONSE_DATA {
Locate all SESSION postargs in the HTML response - there could be multiples, in the case of the course list
page where each course has a unique SESSION id set for some reason. Create a persistence record for each.
set session_indices [regexp -all -inline -indices {"SESSION" VALUE="[0-9]*"} [HTTP::payload]]
foreach session_idx $session_indices {
set session_start [lindex $session_idx 0]
set session_end [lindex $session_idx 1]
set session_len [expr {$session_end - $session_start +1}]
set session_string [string range [HTTP::payload] $session_start $session_end]
set session_id [findstr $session_string "VALUE=" 7 $::term]
persist add uie $session_id 6000
if {$::debug}{log local0. "Session ID in server reply: $session_id"}
}
}
when LB_FAILED {
pool pool_www.xxxxxxx.com
LB::reselect
if {$::debug}{log local0. "Selected server [LB::server] did not respond. Reselected from pool."}
}