How to generate the persistence cookie with an iRule
Problem this snippet solves: When you configure a cookie persistence profile to use the HTTP Cookie Insert or HTTP Cookie Rewrite method, the BIG-IP system inserts a cookie into the HTTP response. The cookie value contains the encoded IP address and port of the destination server. Exemple of a cookie value : 1677787402.36895.0000 (See SOL6917 for more information about this topic) Let's assume that you want your pool member to receive a copy of this cookie value in an HTTP header. Because for example you want your application to forge an url where the cookie value is in a GET parameter. (NOTE : I cannot modify the behavior of the application, I can only play with headers) Retrieving the cookie value is pretty easy with iRule : [HTTP::cookie value $cookie_name] But you'll notice that there is a little issue with this feature: when you are a new visitor, the persistence cookie is inserted in the HTTP response ... Meaning that for the very first hit made by the visitor, there will be NO cookie value to retrieve ... In my scenario it was an issue to miss this cookie value on the first hit, so I had to come up with a solution to forge the cookie value based on pool member IP and port when the persistence cookie is missing. I chose to adapt the code found here and there (thanks !) EDIT : Well I figured out that if you are not using a default route-domain the persistence cookie value will be different (see https://support.f5.com/csp/article/K6917 ) Here is the alternative code bloc to use IPv4 non-default route domains: set ADDR "[format %02x $a][format %02x $b][format %02x $c][format %02x $d]" set PORT [LB::server port] set COOKIE "rd2o00000000000000000000ffff${ADDR}o${PORT}" How to use this snippet: To summarize what the iRule does : if the persistence cookie doesn't exist (most likely because it's the very first hit), then calculate it from member IP and PORT (it obviously has to be after the "When LB_SELECTED" statement) ; else just read the existing cookie. You can set the $cookie_name parameter manually, or let the iRule identify it Code : when LB_SELECTED { #set cookie_name SERVERID # following function could determine persistence cookie name being used if not manually set by the previous line if {not [info exists cookie_name]} { if { [set cookie_name [PROFILE::persist mode cookie cookie_name]] eq "" } { set cookie_name "BIGipServer[getfield [LB::server pool] "/" 3]" } #Default cookie name requires the getfield "/" 3 purge otherwise it's /Common/pool_name } if { [set COOKIE [HTTP::cookie value $cookie_name]] == "" } { scan [LB::server addr] {%d.%d.%d.%d} a b c d set ADDR [expr { $a + $b * 256 + $c * 65536 + $d * 16777216 }] set PORT [ntohs [LB::server port]] set COOKIE "${ADDR}.${PORT}.0000" ## Following bloc must be used instead if you are using non-default route domains, see K6917 #set ADDR "[format %02x $a][format %02x $b][format %02x $c][format %02x $d]" #set PORT [LB::server port] #set COOKIE "rd2o00000000000000000000ffff${ADDR}o${PORT}" ######### unset a b c d ADDR PORT #log local0. "$cookie_name = $COOKIE created for [HTTP::uri]" } else { #log local0. "$cookie_name = $COOKIE already exists for [HTTP::uri]" } HTTP::header insert X-F5-persist $COOKIE } Tested this on version: 11.52.3KViews2likes1CommentHostname 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.3476Views0likes0CommentsWeblogic Persistence done right ;=)
Problem this snippet solves: You want to use your Weblogic issued JSESSIONID session cookie to control persistence. A sensible option would be to employ a Cookie Hash persistence profile but then you find it to be deficient in these respects: Mishandling of stale session cookies: A client making a request with a stale session cookie will cause the LTM to insert that stale session identifier into the persistence table. No support for cookie-less User-Agents whereby the session id is encoded in the URL. No tcl commands to query the cookie persistence table (e.g. for debug purposes). As opposed to other Weblogic Persistence iRules found in Codeshare this irule will also allow for: Minimizing the number of persistence records by persisting on the JVMID alone. That means there will be as many records as there are Weblogic Application Server instances. Treating JSESSIONID value as opaque (i.e. no tolower thank you very much :)). Greater control of debug logging. How to use this snippet: If your Virtual Server services more than one application and/or pool, don't forget to employ a one-connect profile or attach an iRule that does LB::detach in then response event (see SOL7964). It is assumed pool-selection is done in a LTM Policy otherwise, if done by iRule, take care of the order of iRule execution. Code : # Weblogic Persist iRule, Version 0.93 # Mars, 2012 # Last update: Aug, 2012 # Updated v11.6.0: 15/02/2015 # Created by Opher Shachar (contact me through devcentral.f5.com) # Purpose: # This iRule persists requests based on the JSESSIONID cookie issued by the # Weblogic server. Since Weblogic appends its JVMID to the cookie, it affords # us the chance to persist on just the JVMID minimizig the size of the # persistence table. # If not in a cookie the JSESSIONID will be searched for in the request uri. when RULE_INIT { # Set debug level to: 0, 1 or 2 set static::Weblogic_debug 1 # Persist on JVMID only (e.g., to minimize the persist-record table) set static::Weblogic_JVMID 0 # Set the name and length of the Weblogic session cookie set static::Weblogic_CookieName "JSESSIONID" set static::Weblogic_PathName "jsessionid=" set static::Weblogic_PathLen [string length $static::Weblogic_PathName] # Set a timeout of 12 hours (43,200 seconds) set static::Weblogic_timeout 43200 } when CLIENT_ACCEPTED { set log_prefix "Client [IP::client_addr]:[TCP::client_port]" } when HTTP_REQUEST { # Log details for the request if {$static::Weblogic_debug > 1} { log local0. "$log_prefix: Request to [HTTP::uri] with cookie: [HTTP::cookie value $static::Weblogic_CookieName]" } # Check if there is a session cookie set pkey [HTTP::cookie $static::Weblogic_CookieName] if {$pkey eq ""} { # Perhaps there's a jsessionid in the request uri. The jsessionid, # when included is in the path: /path/to/file.ext;jsessionid=abcd!1234 set pkey [findstr [HTTP::path] $static::Weblogic_PathName $static::Weblogic_PathLen] } # Did we find a session id? if {$pkey ne ""} { # Extract the JVMID, if none then pkey is unchanged set jvmid [findstr $pkey ! 1] if {$static::Weblogic_JVMID and ($jvmid ne "")} { set pkey $jvmid } # Persist off of the session id value with the set timeout if {[persist lookup uie $pkey] ne ""} { persist uie $pkey $static::Weblogic_timeout if {$static::Weblogic_debug > 1} { log local0. "$log_prefix: Used persistence record from cookie or path: [persist lookup uie $pkey]" } } else { # Client gave stale session id -- don't persist persist none if {$static::Weblogic_debug > 0} { log local0. "$log_prefix: No persistence record found for key: $pkey" } } } else { # Client gave no session id -- don't persist persist none if {$static::Weblogic_debug > 1} { log local0. "$log_prefix: No session id given in cookie or path." } } } when HTTP_RESPONSE { # Check if there is a session cookie in the response set pkey [HTTP::cookie $static::Weblogic_CookieName] if {$pkey eq "" and [HTTP::is_redirect]} { # Perhaps there's a jsessionid in the redirect uri. The jsessionid, # when included is in the path: /path/to/file.ext;jsessionid=abcd!1234 set pkey [findstr [URI::basename "[HTTP::header Location]"] $static::Weblogic_PathName $static::Weblogic_PathLen] } # Did we find a session id? if {$pkey ne ""} { # Extract the JVMID, if none then pkey is unchanged set jvmid [findstr $pkey ! 1] if {$static::Weblogic_JVMID and ($jvmid ne "")} { set pkey $jvmid } # Persist the session id value with the set timeout persist add uie $pkey $static::Weblogic_timeout if {$static::Weblogic_debug > 0} { set val [persist lookup uie $pkey] log local0. "$log_prefix: Added persistence record from cookie or redirect: $pkey -> $val" } } } Tested this on version: 11.4589Views0likes0CommentsXFF Universal Persistence iRule
Problem this snippet solves: Simple iRule to read the XFF header on an incoming HTTP Request and use a Universal Persistence ID. Orginal iRule found to have an issue with multiple IP addresses in the XFF header for changed to only pass the first XFF IP. I have updated the iRule line to account for systems where multiple 'X-Forwarded-For' headers have been added. persist uie [lindex [ split [HTTP::header X-Forwarded-For] "," ] 0] to persist uie [lindex [ split [lindex [HTTP::header values X-Forwarded-For] 0] "," ] 0] thanks to the advice from Yann Desmarest. This could also be done with the 'getfield' command see Yann's comments below. How to use this snippet: Create iRule using following code (mine is named 'persist_xff_uie') Create Universal Persistence Profile with iRule set to 'persist_xff_uie' (or what ever name you assign to the iRule) Assign Universal Persistence Profile to Virtual Server (ensure virtual server has HTTP profile assigned) Code : # Name: persist_xff_uie # # To be used with UIE Persistence Profile # # Checks HTTP Request for 'X-Forwarded-For' header and if exists takes the first 'X-Forwarded-For' IP address as sets as # Persist identifier. # If the 'X-Forwarded-For' header does not exist then the client IP address is set as Persist identifier. when HTTP_REQUEST { if {[HTTP::header X-Forwarded-For] != ""} then { persist uie [lindex [ split [lindex [HTTP::header values X-Forwarded-For] 0] "," ] 0] } else { persist uie [IP::client_addr] } } Tested this on version: 11.52.3KViews1like7CommentsPersistence on HTTP Response only (also DDoS and off-loading assistence)
Problem this snippet solves: Working with web traffic I see a common issue with persistence iRules, the following is common iRule: when HTTP_RESPONSE { if { [HTTP::cookie exists "JSESSIONID"] } { persist add uie [HTTP::cookie "JSESSIONID"] } } when HTTP_REQUEST { if { [HTTP::cookie exists "JSESSIONID"] } { persist uie [HTTP::cookie "JSESSIONID"] } } The problem with this is we only really want to add persistence records for valid traffic where this allows any HTTP Request with a JSESSIONID cookie to create a peristence record. Think about this, if I had 1000 clients which I got to make HTTP Requests all with the same JSESSIONID cookie value then the first would create a persistence record on the F5 then the other 999 requests would all go to the same backend web server even if the JSESSIONID value is not valid on the applicaiton. Also we could end up with many more peristence enties as client request with invalid JSESSIONID values will still create enties. This all leads to a possible DoS style attacks but a simple change can prevent. The following iRule does a simple lookup first before using any persistence record in a HTTP Request, if the lookup fails but a JSESSIONID value exists then we can remove the JSESSIONID cookie from the request. This second part is optional but can also be used to only send valid traffic to a back end web server. How would we do that? We could have a list (or data group) of valid HTTP paths we accept without a valid JSESSIONID cookie (valid being in the request and has a valid persistence record) if not redirect uses to a login page or home page or some other valid location. This allows us to use persistence records as a way to apply validation to HTTP Requests and block/redirect invalid ones. How to use this snippet: HTTP Response is standard checking for a value, in this case the JSESSIONID cookie, and adds a persistence record. Should be applied as part of a persistence profile so you can control timeout and Match Across Virtual Server/Service/Pool outside of the iRule when HTTP_RESPONSE { if { [HTTP::cookie exists "JSESSIONID"] } { persist add uie [HTTP::cookie "JSESSIONID"] } } The Request part does a validation check first preventing persistence records being added and only used in a Reqeust and even removing the JSESSIONID cookie from the request. See the description above about using this to provide even great blocking of invalid requests. when HTTP_REQUEST { if {[HTTP::cookie "JSESSIONID"] ne "" and [persist lookup uie [HTTP::cookie "JSESSIONID"]] ne ""} { persist add uie [HTTP::cookie "JSESSIONID"] } elseif {[HTTP::cookie "JSESSIONID"] ne ""} { HTTP::cookie remove "JSESSIONID" } } Code : when HTTP_RESPONSE { if { [HTTP::cookie exists "JSESSIONID"] } { persist add uie [HTTP::cookie "JSESSIONID"] } } when HTTP_REQUEST { if {[HTTP::cookie "JSESSIONID"] ne "" and [persist lookup uie [HTTP::cookie "JSESSIONID"]] ne ""} { persist add uie [HTTP::cookie "JSESSIONID"] } elseif {[HTTP::cookie "JSESSIONID"] ne ""} { HTTP::cookie remove "JSESSIONID" } }460Views1like0CommentsWeblogic JSessionID Persistence
Problem this snippet solves: Contributed by: unRuleY, Summarized by: deb Note: The previous version of this iRule contained escaped newlines following the session command, which in versions 10.0 - 10.2.0 causes TMM to core as documented in CR135937 / SOL11427. This was fixed in 10.2.1. See this related Codeshare example for details on how to take advantage of session replication on the WebLogic servers with targeted node failover in an iRule. Provides persistence on the jsessionid value found in either the URI or a cookie. When a request is received, the iRule first looks for a "jsessionid" cookie, and if not found, for a "jsessionid" parameter in the requested URI. If either is found, a persistence record is created if it doesn't already exist, or followed if it does. If neither is found, the request is load balanced according to the load balancing method applied to the virtual server and persisted based on the client's IP address. In order to ensure the second and subsequent requests follow the first, LTM must create a persistence record indicating the pool member to which the first request was load balanced. If the server is setting the jsessionid in a cookie, the persistence key value may be extracted from the server response to create the persistence record. If the server is setting the jsessionid in the URLs, source address persistence with a short timeout is recommended to track the original destination until the jsessionid is sent. How to use this snippet: To ensure a new persistence record is followed when a request is re-load balanced in a client-side Keep-Alive connection, apply a OneConnect profile to the virtual server. The iRule assumes the jsessionid is in upper case when used as a cookie name. If this isn't the case, please update the example. To persist on jsessionid, create the iRule below and create a custom Universal persistence profile, with Match Across Services enabled, that uses the iRule. Then use this custom Universal persistence profile as the Default Persistence profile on your Virtual Server. Applying a Fallback Persistence profile of type Source Address Affinity with a host mask and a short timeout (the default source_addr persistence profile will do the trick) to your Virtual Server is also recommended. Attention, if you are running firmware 11.0 - 11.2.1 and enabled "Match Across Services"! There is a bug inside. SOL14061 This iRule requires LTM v10. or higher. Code : when HTTP_REQUEST { # Log details for the request set log_prefix "[IP::client_addr]:[TCP::client_port]" log local0. "$log_prefix: Request to [HTTP::uri] with cookie: [HTTP::cookie value JSESSIONID]" # Check if there is a JSESSIONID cookie if { [HTTP::cookie "JSESSIONID"] ne "" }{ # Persist off of the cookie value with a timeout of 1 hour (3600 seconds) persist uie [string tolower [HTTP::cookie "JSESSIONID"]] 3600 # Log that we're using the cookie value for persistence and the persistence key if it exists. log local0. "$log_prefix: Used persistence record from cookie. Existing key? [persist lookup uie [string tolower [HTTP::cookie "JSESSIONID"]]]" } else { # Parse the jsessionid from the path. The jsessionid, when included in the URI, is in the path, # not the query string: /path/to/file.ext;jsessionid=1234?param=value set jsess [findstr [string tolower [HTTP::path]] "jsessionid=" 11] # Use the jsessionid from the path for persisting with a timeout of 1 hour (3600 seconds) if { $jsess != "" } { persist uie $jsess 3600 # Log that we're using the path jessionid for persistence and the persistence key if it exists. log local0. "$log_prefix: Used persistence record from path: [persist lookup uie $jsess]" } } } when HTTP_RESPONSE { # Check if there is a jsessionid cookie in the response if { [HTTP::cookie "JSESSIONID"] ne "" }{ # Persist off of the cookie value with a timeout of 1 hour (3600 seconds) persist add uie [string tolower [HTTP::cookie "JSESSIONID"]] 3600 log local0. "$log_prefix: Added persistence record from cookie: [persist lookup uie [string tolower [HTTP::cookie "JSESSIONID"]]]" } }4.9KViews1like7CommentsSingle Node Persistence
Problem this snippet solves: A really slick & reliable way to stick to one and only one server in a pool. Requirement: Direct traffic to only a single node in a pool at a time. Initially, traffic should always go to node A. If Node A fails, then traffic will go to Node B. When Node A comes back online, traffic should continue to go to Node B. When Node B fails, then the traffic should go to Node A. To send traffic to only 1 pool member at a time, you can use an iRule and Universal Persistence to set a single persistence record that applies to all connections. Create a virtual server. Create a pool with the real servers in it. Create an iRule like this: Create a Persistence profile of type Universal which uses the iRule you just created. Set the timeout high enough so it will never expire under typical traffic conditions. In the virtual server definition, apply pool as the default pool, and the new persistence profile as the default persistence profile (both on the virtual server "resources" screen). The first connection will create a single universal persistence record with a key of "1". All subsequent connections will look up persistence using "1" as the key, resulting in truly universal persistence for all connections. (Use 1 or any constant value. 0 will have the same affect as using 1. One of my customers uses "persist uie TCP__local_port" When one node fails, the other is persisted to by all comers. When the 2nd node fails, the 1st again becomes the preferred node for all, ad infinitum. Doesn't offer the capability of manual resume after failure, or true designation of a "primary" and "secondary" instance (sometimes required for db applications), but it sure does solve the problem of "only use one node at a time, I don't care which one, please" (You can use priority to gravitate towards the top of a list...) Note: Priority-based load balancing with or without dynamic persistence doesn't quite address this requirement. Priority load balancing allows you to set a preferred server to which traffic should return once it recovers. With just Priority, and with dynamic persistence of any kind enabled, when a higher priority nodes come back up after failing, you will see traffic distributed across multiple pool members until old connections/sessions die off. With just Priority and no persistence, existing sessions will break once the preferred node again becomes available. Code : rule PriorityFailover { when CLIENT_ACCEPTED { persist uie 1 } }3.4KViews0likes25CommentsPersistence Cookie Logging
Problem this snippet solves: Cookie Persistence Logging Adapted and Simplified for TMOS 10.0.0 or greater cookie format. Extracts the cookie value from a persistence cookie inserted by LTM's "cookie insert" persistence method, logs cookie, logs virtual iRule is applied to, logs virtual's default pool iRule is applied to, decodes cookie to get pool member ip and destination port also including the requesting client's ip address and source port. If no cookie is found that's logged along with the virtual irule is applied to, virtual's default pool irule is applied to and pool member assignment ip and destination port. Useful for troubleshooting cookie persistence. Explained Further - On the LB_SELECTED event automatically grabs the Virtual Name the iRule is applied to, Virtual Default Pool Name the iRule is applied to. Determines what the Cookies Name should be by Default and sets this information to varibles. Executes the guts TCL Script to query if a cookie exists & decodes the cookie if so while logging to via syslog-ng to /var/log/ltm; if no cookie exists logs that information also to /var/log/ltm. Credit: deb for the idea and a very small portion of this code sol6917: Overview of BIG-IP persistence cookie encoding How to use this snippet: This iRule requires LTM v10. or higher. Example Logging Entries Sep 28 11:43:14 local/tmm1 info tmm1[4875]: Rule persist_cookie_logger : Request from client: 172.20.66.224%10:53566 contains no persistence cookie on vip https-vip-12; request was assigned to pool https-pool-12 and member 10.11.101.211%10:443 Sep 28 11:47:10 local/tmm1 info tmm1[4875]: Rule persist_cookie_logger : Request from client: 172.20.66.224%10:53618 contains persistence cookie rd10o00000000000000000000ffff0a0b65d3o443 referencing vip https-vip-12; pool https-pool-12; member 10.11.101.211:443 Code : # Cookie Persistance Logging Adapted and Simplified for TMOS Version 10.0.0 Cookies # - RJ Wilke when LB_SELECTED { # grab Virtual Server Name Servicing this Request set Virtual [virtual name] # grab Pool (Default Pool for the Virtual Server) set Pool [LB::server pool] # grab Version TMOS 10.0.0 or greater Cookie (includes Route Domain) set Cookie BIGipServer$Pool # if {[HTTP::cookie exists $Cookie]}{ scan [HTTP::cookie $Cookie] {%*[^\f]%*4x%2x%2x%2x%2xo%i} a b c d e set Ip $a.$b.$c.$d set Port $e # log results out to /var/log/ltm log local0.info "Request from client: \ [IP::remote_addr]:[TCP::remote_port] contains persistence cookie [HTTP::cookie $Cookie]\ referencing vip $Virtual; pool $Pool; member $Ip:$Port" } else { log local0.info "Request from client: [IP::remote_addr]:[TCP::remote_port] contains\ no persistence cookie on vip $Virtual; request was assigned to pool $Pool and member\ [LB::server addr]:[LB::server port]" } } Tested this on version: 10.01.7KViews0likes5CommentsPersist client on response content with stream
Problem this snippet solves: Persist a client based on a string found in the response content using a stream profile. The goal is to find a string in the response payload which is unique to the client session. The rule requires a blank stream profile enabled on the virtual server. This example uses the jsessionid value, but it could be modified to search for any string in the content. The advantage over this rule using a stream profile versus collecting the response content is that the stream profile should be faster and require fewer resources. Code : when HTTP_RESPONSE { # Use persistence based on the same token that was added in a prior response # Need to parse $jsessionid from some portion of the request headers or payload # See this Codeshare entry for some examples of using cookie or path commands to do so # http://devcentral.f5.com/s/wiki/default.aspx/iRules/Weblogic_JSessionID_Persistence.html persist $my_jsessionid_parsed_from_the_request 3600 } when HTTP_RESPONSE { # Clear the jsessionid if it exists already on this TCP connection if {[info exists jsessionid]}{ unset jsessionid } # Only look for the jsessionid in text responses if {[HTTP::header value "Content-Type"] starts_with "text"}{ log local0. "[IP::client_addr]:[TCP::client_port]: Matched text, enabling stream filter" # Because TCL doesn't support lookaheads, match the jsessionid string and value # We'll parse out the value in STREAM_MATCHED # Assume the jsessionid is 1 to 100 characters (terminated by a non-alphanumeric character). STREAM::expression ;jsessionid=[A-Za-z0-9]{1,100} STREAM::enable # Enable the STREAM_MATCHED event as it could have been disabled if there was a prior # response on this TCP connection event STREAM_MATCHED enable } else { # Disable the stream filter as this wasn't a text response log local0. "[IP::client_addr]:[TCP::client_port]: No Content-Type match, disabling stream filter" STREAM::disable } } when STREAM_MATCHED { # Save the matched value (example: ;jsessionid=ABCDEF) set jsessionid [STREAM::match] log local0. "[IP::client_addr]:[TCP::client_port]: Matched: $jsessionid" # STREAM::match shouldn't match a null string with the defined regex, but check anyhow if {[string length $jsessionid]}{ # Get the jsessionid value (split ;jsessionid=ABCDEF on the equals sign) set jsessionid [getfield $jsessionid "=" 2] # The iRule parser doesn't allow the persist command in STREAM_MATCHED. # It works though, so hide the command from the parser # Add a persistence record with the jsessionid token and a one hour timeout set persist_cmd "persist add uie $jsessionid 3600" log local0. "[IP::client_addr]:[TCP::client_port]: Parsed: $jsessionid \$persist_cmd: $persist_cmd" eval $persist_cmd #persist add uie $jsessionid # Assume the first match is the same as any other jsessionids, so stop checking for them log local0. "[IP::client_addr]:[TCP::client_port]: Added persistence record. Exiting event for this response." event STREAM_MATCHED disable } }283Views0likes1CommentUniversal Persistence iRule based upon ASP.NET SessionId
Problem this snippet solves: This iRule was created to persist user sessions on the same web server based upon ASP.NET_SessionId cookie. Many of the samples on the site did not work effectively in our environment. The issues stemmed from the fact that the cookie was being grabbed and sesssion persisted only on the HTTP_Request and not on the initial HTTP_Response when the ASP.NET_SessionId cookie is first set. This caused issues allowing traffic to potentially jump servers between the 1st and 2nd request. I would welcome any/all feedback on this or if you think it can be made more efficient. Code : when HTTP_REQUEST { if { [HTTP::cookie exists "ASP.NET_SessionId"] } { LB::detach } set SessionId [HTTP::cookie ASP.NET_SessionId] if { $SessionId ne "" } { persist uie $SessionId } } when HTTP_RESPONSE { #log local0. "Response SessionId is: $SessionId from Set-Cookies: [HTTP::header values Set-Cookie]" if {[HTTP::header exists "Set-Cookie"]} { foreach cookievalue [HTTP::header values "Set-Cookie"] { if { $cookievalue contains "ASP.NET_SessionId" } { set SessionId [findstr $cookievalue "ASP.NET_SessionId" 18 ";"] if { $SessionId ne "" } { persist add uie $SessionId } #log local0. "Persist record [persist lookup uie $SessionId]" } } } }590Views0likes1Comment