iRule resulting in too many redirects
I have two requirements with my virtual server. 1. A redirect to /pc/service/SSOLogin 2. 24 hour persistence based on the JSESSIONID cookie in the request header. The first one was accomplished early on with a policy that redirects to location '/pc/service/SSOLogin' at request time. This has worked without any issues until I tried to implement the JSESSIONID persistence. To accomplish the second, I created an iRule to be used with the Universal persistence profile. When I implemented this persistence profile, the redirect policy no longer worked. My assumption was that the iRule and the policy were conflicting with each other. To resolve this, I created a single iRule to handle both of these requirements. Now, I am getting too many redirects. The iRule is below. when HTTP_RESPONSE { ## PERSISTENCE # If the JSESSIONID exists, we'll pass the cookie along if { [HTTP::cookie exists "JSESSIONID"] } { persist add uie [HTTP::cookie "JSESSIONID"] 86400 } } when HTTP_REQUEST { ## PERSISTENCE # If the JSESSIONID exists, we'll maintain that persistence if { [HTTP::cookie exists "JSESSIONID"] } { persist uie [HTTP::cookie "JSESSIONID"] } ## REDIRECT # This grabs the base url from the incoming request # For Example, https://my.site.com/some/path the base_url is set to https://my.site.com set base_url "https://[HTTP::host]" # Defining the new path set new_path "/pc/service/SSOLogin" # Construct the new URL # For example, https://my.site.com/pc/service/SSOLogin set new_url "$base_url$new_path" # Redirect to the new URL HTTP::redirect $new_url }120Views0likes6CommentsPool round Robin not working with standard virtual server
I have a standard HTTPS virtual server configured with two nodes in the pool. There is no persistence setting enabled and the load balancing method is round robin. For some reason, after I browse to the site and establish a connection with a backend server in the pool, all my future requests go to the same server and it behaves in a way that indicates some persistence is enabled. For example, when I refresh my browser, open the site in a new browser, and open the site in an incognito browser, all my requests keep going to the same node. You can see below that I tried this multiple times and kept getting connected to one server and the number of connections on that server was increasing. According to my research, because there is no persistence profile setting, the load balancing method is round robin, and both servers are available and able to accept traffic, every time I refresh or open the site in a new tab or browser, I should be randomly assigned to a server for that connection via round robin load balancing. But this is not what I observe. Is there a reason that my virtual servers are showing persistence by default? Any ideas? Here are some images of my config:Solved232Views0likes6CommentsRatio (Session) and Least Sessions
Hello, I wanted to fully understand the Ratio(Session) load balancing method. I was reading the description of load balancing methods here and about the Least Session here. I came across this question in the forums, but the links are old and it doesn't provide a clear answer, I want to know what exactly is considered a session in the Ratio(session), it's mentioned for the Least sessions that it depends on a Persistence profile (least number of entries in the persistence table) to determine the sessions for each pool member, for example HTTP cookie determines the session in this case, is it the same case for Ratio(Session)? What is meant by a session exactly in the Ratio(Session) and is there a real-world example for this case? In this article, it's mentioning that Ratio(Session) is used for protocols that transmit multiple messages over the same connection, is this the same case for HTTP for example using Cookie persistence like Least Sessions? It's not very clear to me how the system will count sessions if it's not based on persistence like the Least Sessions. When I applied this load balancing method to a pool with multiple members, I noticed the requests where going to one member only. Thanks869Views0likes4CommentsMultiple method persistence
Hello. I need to setup load-balancing for a visio application, which is quite complex, as I don't need just to ensure session persistence for a single user, but for multiple users participating to the same conference. According to my understanding of reference documentation, I need to use an universal persistence profile (or eventually hash persistence profile, as it only differs by hashing lookup value), and write an iRule, such as: when HTTP_REQUEST { # extract roomID from room parameter in query string set roomID [getfield [URI::query [HTTP::uri] room] "@" 1 ] if { $roomID != "" } { persist uie $roomID 3600 log local0. "Using Jitsi room ID $roomID for persistence: [persist lookup uie $roomID]" } } Once a corresponding persistence profile assigned to the virtual server, it works as expected. However, I also have to ensure persistence for authentication requests, this time with more classical requirements, ie every authentication requests for a given user must reach the same pool node. I first considered the use of a fallback persistence profile (either cookie, ssl, or source address), so as to keep the irule simple. However, documentation discourage using fallback persistence for this purpose: If Fallback persistence becomes the chosen persistence method, a Default persistence entry will not be created for the client connection until the Fallback persistence idle timeout period expires. Because of this, Fallback persistence may appear to override Default persistence and may not be a good choice. See Recommendations, following, for additional information. So I added another clause in my iRule, still using uie method, but with client address as lookup key, hence reinventing simple persistence: if { [HTTP::path] starts_with "/Shibboleth.sso" } { persist uie [IP::client_addr] 3600 log local0. "Using client IP adress for persistence: [persist lookup uie [IP::client_addr]]" } According to the documentation, I may be able to mix persistence methods in a single iRule (one of the example given here mixes source_addr and cookie methods), but some of those methods (ssl, msrdp, cookie) also requires a corresponding persistence profile assigned to the virtual server. Whereas I already use an universal persistence profile. So basically, I'm a bit lost among multiple options, especially the relation between persistence profiles and persistence methods, and I have a few questions: Is there any recommended practice for using multiples persistence methods in a single iRule ? if only ssl and cookie methods require a corresponding profile, what is the interest of using an universal persistence profile, instead of just assigning the persistence irule to the virtual server ? If I'm assigning a cookie persistence profile and a persistence irule using uie method to the same virtual server, how will persistence work ? I hope I have been clear enough 🙂 Thanks for your interest.851Views0likes3CommentsHow 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.3475Views0likes0Commentssource IP and source Port persistence using irule - Citrix - (carp vs uie)
Hi, We ran into an issue of uneven load-balancing due to using citrix. Clients end up using the same IP so we decided we need to start load-balancing using the source port as well. I have done my homework and search around until I came across multiple solutions of either to use uie or carp. I have multiple questions hopefully I will get answers for. I understand carp doesn't have a timeout so that leads to a question is it better to use in this situation? Also we are leaning towards load-balancing using the least connections. Would each algorithm limits to a specific load-balancing method? Per my irule below I don't add persist assuming it is done automatically. am I wrong with that assumption? Should I be adding each successful persistence records? what would be the best way to test such an implementation? Here is the irule I'm about to implement. when CLIENT_ACCEPTED { set client_ip_port "[IP::client_addr]:[TCP::client_port]" if {[TCP::client_port] and [IP::client_addr] !=0} { persist carp $client_ip_port } }461Views0likes1CommentWeblogic 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.4586Views0likes0CommentsXFF 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" } }460Views1like0Comments