basic
539 TopicsiRules 101 - #12 - The Session Command
One of the things that makes iRules so incredibly powerful is the fact that it is a true scripting language, or at least based on one. The fact that they give you the tools that TCL brings to the table - regular expressions, string functions, even things as simple as storing, manipulating and recalling variable data - sets iRules apart from the rest of the crowd. It also makes it possible to do some pretty impressive things with connection data and massaging/directing it the way you want it. Other articles in the series: Getting Started with iRules: Intro to Programming with Tcl | DevCentral Getting Started with iRules: Control Structures & Operators | DevCentral Getting Started with iRules: Variables | DevCentral Getting Started with iRules: Directing Traffic | DevCentral Getting Started with iRules: Events & Priorities | DevCentral Intermediate iRules: catch | DevCentral Intermediate iRules: Data-Groups | DevCentral Getting Started with iRules: Logging & Comments | DevCentral Advanced iRules: Regular Expressions | DevCentral Getting Started with iRules: Events & Priorities | DevCentral iRules 101 - #12 - The Session Command | DevCentral Intermediate iRules: Nested Conditionals | DevCentral Intermediate iRules: Handling Strings | DevCentral Intermediate iRules: Handling Lists | DevCentral Advanced iRules: Scan | DevCentral Advanced iRules: Binary Scan | DevCentral Sometimes, though, a simple variable won't do. You've likely heard of global variables in one of the earlier 101 series and read the warning there, and are looking for another option. So here you are, you have some data you need to store, which needs to persist across multiple connections. You need it to be efficient and fast, and you don't want to have to do a whole lot of complex management of a data structure. One of the many ways that you can store and access information in your iRule fits all of these things perfectly, little known as it may be. For this scenario I'd recommend the usage of the session command. There are three main permutations of the session command that you'll be using when storing and referencing data within the session table. These are: session add: Stores user's data under the specified key for the specified persistence mode session lookup: Returns user data previously stored using session add session delete: Removes user data previously stored using session add A simple example of adding some information to the session table would look like: when CLIENTSSL_CLIENTCERT { set ssl_cert [SSL::cert 0] session add ssl $ssl_cert 90 } By using the session add command, you can manually place a specific piece of data into the LTM's session table. You can then look it up later, by unique key, with the session lookup command and use the data in a different section of your iRule, or in another connection all together. This can be helpful in different situations where data needs to be passed between iRules or events that it might not normally be when using a simple variable. Such as mining SSL data from the connection events, as below: when CLIENTSSL_CLIENTCERT { # Set results in the session so they are available to other events session add ssl [SSL::sessionid] [list [X509::issuer] [X509::subject] [X509::version]] 180 } when HTTP_REQUEST { # Retrieve certificate information from the session set sslList [session lookup ssl [SSL::sessionid]] set issuer [lindex sslList 0] set subject [lindex sslList 1] set version [lindex sslList 2] } Because the session table is optimized and designed to handle every connection that comes into the LTM, it's very efficient and can handle quite a large number of items. Also note that, as above, you can pass structured information such as TCL Lists into the session table and they will remain intact. Keep in mind, though, that there is currently no way to count the number of entries in the table with a certain key, so you'll have to build all of your own processing logic for now, where necessary. It's also important to note that there is more than one session table. If you look at the above example, you'll see that before we listed any key or data to be stored, we used the command session add ssl. Note the "ssl" portion of this command. This is a reference to which session table the data will be stored in. For our purposes here there are effectively two session tables: ssl, and uie. Be sure you're accessing the same one in your session lookup section as you are in your session add section, or you'll never find the data you're after. This is pretty easy to keep straight, once you see it. It looks like: session add uie ... session lookup uie Or: session add ssl ... session lookup ssl You can find complete documentation on the session command here, in the iRules, as well as some great examplesthat depict some more advanced iRules making use of the session command to great success. Check out Codeshare for more examples.3.4KViews0likes8CommentsIntermediate iRules: Nested Conditionals
Conditionals are a pretty standard tool in every programmer's toolbox. They are the functions that allow us to decided when we want certain actions to happen, based on, well, conditions that can be determined within our code. This concept is as old as compilers. Chances are, if you're writing code, you're going to be using a slew of these things, even in an Event based language like iRules. iRules is no different than any other programming/scripting language when it comes to conditionals; we have them. Sure how they're implemented and what they look like change from language to language, but most of the same basic tools are there: if, else, switch, elseif, etc. Just about any example that you might run across on DevCentral is going to contain some example of these being put to use. Learning which conditional to use in each situation is an integral part to learning how to code effectively. Once you have that under control, however, there's still plenty more to learn. Now that you're comfortable using a single conditional, what about starting to combine them? There are many times when it makes more sense to use a pair or more of conditionals in place of a single conditional along with logical operators. For example: if { [HTTP::host] eq "bob.com" and [HTTP::uri] starts_with "/uri1" } { pool pool1 } elseif { [HTTP::host] eq "bob.com" and [HTTP::uri] starts_with "/uri2" } { pool pool2 } elseif { [HTTP::host] eq "bob.com" and [HTTP::uri] starts_with "/uri3" } { pool pool3 } Can be re-written to use a pair of conditionals instead, making it far more efficient. To do this, you take the common case shared among the example strings and only perform that comparison once, and only perform the other comparisons if that result returns as desired. This is more easily described as nested conditionals, and it looks like this: if { [HTTP::host] eq "bob.com" } { if {[HTTP::uri] starts_with "/uri1" } { pool pool1 } elseif {[HTTP::uri] starts_with "/uri2" } { pool pool2 } elseif {[HTTP::uri] starts_with "/uri3" } { pool pool3 } } These two examples are logically equivalent, but the latter example is far more efficient. This is because in all the cases where the host is not equal to "bob.com", no other inspection needs to be done, whereas in the first example, you must perform the host check three times, as well as the uri check every single time, regardless of the fact that you could have stopped the process earlier. While basic, this concept is important in general when coding. It becomes exponentially more important, as do almost all optimizations, when talking about programming in iRules. A script being executed on a server firing perhaps once per minute benefits from small optimizations. An iRule being executed somewhere in the order of 100,000 times per second benefits that much more. A slightly more interesting example, perhaps, is performing the same logical nesting while using different operators. In this example we'll look at a series of if/elseif statements that are already using nesting, and take a look at how we might use the switch command to even further optimize things. I've seen multiple examples of people shying away from switch when nesting their logic because it looks odd to them or they're not quite sure how it should be structured. Hopefully this will help clear things up. First, the example using if statements: when HTTP_REQUEST { if { [HTTP::host] eq "secure.domain.com" } { HTTP::header insert "Client-IP:[IP::client_addr]" pool sslServers } elseif { [HTTP::host] eq "www.domain.com" } { HTTP::header insert "Client-IP:[IP::client_addr]" pool httpServers } elseif { [HTTP::host] ends_with "domain.com" and [HTTP::uri] starts_with "/secure"} { HTTP::header insert "Client-IP:[IP::client_addr]" pool sslServers } elseif {[HTTP::host] ends_with "domain.com" and [HTTP::uri] starts_with "/login"} { HTTP::header insert "Client-IP:[IP::client_addr]" pool httpServers } elseif { [HTTP::host] eq "intranet.myhost.com" } { HTTP::header insert "Client-IP:[IP::client_addr]" pool internal } } As you can see, this is completely functional and would do the job just fine. There are definitely some improvements that can be made, though. Let's try using a switch statement instead of several if comparisons for improved performance. To do that, we're going to have to use an if nested inside a switch comparison. While this might be new to some or look a bit odd if you're not used to it, it's completely valid and often times the most efficient you’re going to get. This is what the above code would look like cleaned up and put into a switch: when HTTP_REQUEST { HTTP::header insert "Client-IP:[IP::client_addr]" switch -glob [HTTP::host] { "secure.domain.com" { pool sslServers } "www.domain.com" { pool httpServers } "*.domain.com" { if { [HTTP::uri] starts_with "/secure" } { pool sslServers } else { pool httpServers } } "intranet.myhost.com" { pool internal } } } As you can see this is not only easier to read and maintain, but it will also prove to be more efficient. We've moved to the more efficient switch structure, we've gotten rid of the repeat host comparisons that were happening above with the /secure vs /login uris, and while I was at it I got rid of all those examples of inserting a header, since that was happening in every case anyway. Hopefully the benefit this technique can offer is clear, and these examples did the topic some justice. With any luck, you'll nest those conditionals with confidence now.5.7KViews0likes0CommentsDescription of HTTP caching profile statistics
Hi F5'ers, within bpsh: profile http my-optimized-caching ramcache entry all show Host: 10.80.0.1 URI: / | 1 hits Size: 364 Rank: 1 Source: 0/0 Owner: 0/3 | Received: 2012-03-13 03:55:57 Last sent: 2012-03-13 04:02:41 | Expires: 2012-03-14 14:14:22 Vary: accept encoding Vary count: 1 | Vary user agent: none Vary encoding: none what do "Vary", "Vary count", "Vary user agent" and "Vary encoding" show? R's, Alex213Views0likes1CommentHow many times to reboot for install software?
Hi How many times to reboot for install software images? From this information ------------------------------------------------------- Sys::Software Status Volume Product Version Build Active Status -------------------------------------------------------- HD1.1 BIG-IP 10.2.1 511.0 yes complete HD1.2 BIG-IP 10.2.1 511.0 no complete HD1.3 none none none no complete I want to upgrade into 10.2.4 HF5 on HD1.2 volume (or must both volume??) First I install 10.2.4 Final into HD1.2 and reboot into HD1.2 , and then reboot again into HD1.1 to install 10.2.4 HF5 into HD1.2 and reboot into HD1.2 to use 10.2.4 , Am I correct? (Reboot 3 times) Do you have better solutions ? like install 10.2.4 and install HF5 respectively and then reboot only once times. (Reboot 1 times) Another questions is what impact if I backup ucs from 11.2.1 HF1 and restore in 11.2.1 HF2 ? thank you380Views0likes6Commentsb interface show: unpopulated vs down ?
Hi there. I couldn't find this in the Big-IP System and Network Management nor the Ask F5. Hoping someone here can help me When I type in a "b interface show" I get the below: [root@secondary:Standby] config b interface show interface speed pkts pkts pkts pkts bits bits errors trunk Mb/s in out drop coll in out mgmt DN 100 FD 0 0 0 0 0 0 0 1.1 UP 1000 FD 454.9M 490.7M 13650 0 596.0G 469.3G 0 1.2 UP 1000 FD 256.5M 249.9M 2.384M 0 293.2G 158.2G 0 1.3 UP 100 FD 32.19M 4.161M 2.894M 0 26.84G 25.79G 0 1.4 DN 1000 FD 0 0 0 0 0 0 0 2.1 MS 1000 FD 0 0 0 0 0 0 0 2.2 MS 1000 FD 0 0 0 0 0 0 0 What is the "DN" vs the "MS" ? When I look on the gui, it says 1.4 is "DOWN" and 2.1 and 2.2 are "UNPOPULATED"? The longer version is that we are adding another VLAN to our network and my manager asked me if we had any free interfaces to do so. Physically there are no cables plugged in to 1.4, 2.1, and 2.2. I'm guessing we can use 1.4. I was just curious what those statuses meant. Can someone explain what that column means? Thanks, Ben984Views0likes1CommentWebException in GetResponse
Please excuse and redirect me if I'm posting in the wrong area but I'm hoping someone here at F5 can be some help. I have a web application which uses a class library I created which, among other things, reads an XML file on the web host (an IIS 6 server/cluster). When I run the app locally in VS2010 or on my testing platform, also an IIS 6 server, it works fine. When I publish to my BIG-IP load-balanced 2 server Veritas Cluster, the code executes fine as long as I use each nodes' name but if I use the cluster's friendly name I get the following exception: The underlying connection was closed: An unexpected error occurred on a receive. at System.Net.HttpWebRequest.GetResponse() at System.Xml.XmlDownloadManager.GetNonFileStream(Uri uri, ICredentials credentials) at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn) at System.Xml.XmlTextReaderImpl.OpenUrlDelegate(Object xmlResolver) at System.Threading.CompressedStack.runTryCode(Object userData) at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) at System.Threading.CompressedStack.Run(CompressedStack compressedStack, ContextCallback callback, Object state) at System.Xml.XmlTextReaderImpl.OpenUrl() at System.Xml.XmlTextReaderImpl.Read() at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace) at System.Xml.XmlDocument.Load(XmlReader reader) at System.Xml.XmlDocument.Load(String filename) at Symantec.DataFactories.AdomdClientDataFactory.GetStoredProcedure() There is more to the stack but that's the gyst of it. I had previously gone at the file more directly with HttpWebRequest.GetResponse() and switched to using XmlDocument.Load() in the hopes that I'd been doing something wrong. No joy. The server is running DotNET 3.5 so the abundance of articles directing me to a fix for 1.0 aren't useful. I did attempt to fix it by setting the HttpWebRequest's KeepAlive to false. Again, no joy. I'm guessing that either we have something mis-configured on the servers or I need to modify my code to better deal with the load balancing. Here's the code I'm trying to run: // Request and read the file. try { // Read and cache the file XmlDocument xmlFile = new XmlDocument(); xmlFile.Load(AbsoluteUrlUsingAuthority); string fileContents = xmlFile.InnerXml; HttpContext.Current.Cache.Insert(cacheKey, fileContents, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, CacheSlidingExpirationMinutes, 0)); } catch { // Fall back to using WebResponse methodology for debugging try { // Ask the web server for the file HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AbsoluteUrlUsingAuthority); request.KeepAlive = false; using (WebResponse response = request.GetResponse()) using (TextReader reader = new StreamReader( response.GetResponseStream(), Encoding.GetEncoding("utf-8"))) { // Read the contents of the file. string file = reader.ReadToEnd(); // Close the stream. reader.Close(); // Add the file to the cache, sliding expiration. HttpContext.Current.Cache.Insert(cacheKey, file, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, CacheSlidingExpirationMinutes, 0)); } } catch (WebException webException) { if (webException.Status == WebExceptionStatus.NameResolutionFailure) throw new Exception("Bad domain name", webException); if (webException.Status == WebExceptionStatus.ProtocolError) { HttpWebResponse response = (HttpWebResponse)webException.Response; if (response.StatusCode == HttpStatusCode.NotFound) { throw new Exception( string.Format("Requested file, {0}.xml, not found. {1}", _command.CommandText, response), webException); } if (response.StatusCode == HttpStatusCode.Forbidden) { throw new Exception( string.Format("403 (Access denied) error accessing {0}. {1}", AbsoluteUrlUsingAuthority, response), webException); } if (response.StatusCode == HttpStatusCode.Unauthorized) { throw new Exception( string.Format("401 (Authentication required) error accessing {0}. {1}", AbsoluteUrlUsingAuthority, response), webException); } } throw; } } I've been pulling my hair out on this for weeks now so any guidance on debugging and/or troubleshooting from a coder's perspective, considering I have to work through a (human) proxy to take any actions on the server would be appreciated.521Views0likes0CommentsPlaying a flv video through Firepass
Hello ! In our company, our internal website often shows videos, interviews. I can't make it work when I access the website through Firepass. Here's the code I'm using : <script type="text/javascript"> script><br><br><div id="myplayer">div> It gets translated by Firepass to : <script type="text/javascript"> script><script>try{F5_flush(document);}catch(e){}script><br><br><div id="myplayer">div> The flvplayer is loaded but the video won't show. I don't know why the addVariable remains and is not translated to a F5_Invoke_addVariable ( I don't know if that exists) Any help ? TIA !183Views0likes0CommentsiRule Security 101 - #1 - HTTP Version
When looking at securing up your web application, there are a set of fairly standard attack patterns that application firewalls make use of to protect against those bad guys out there who are trying exploit your website. A good reference for web application attacks is the Open Web Application Security Project (OWASP). In this series of blog posts, I'm going to highlight different attacks and how they can be defended against by using iRules. In the first installment of this series I will show how to only allow valid HTTP requests to your application server.The most common HTTP versions out there are 1.0 and 1.1 although version0.9 is still used in places. A common attempt to fool an application is by passing an invalid HTTP Version causing the server to not interpret the request correctly. The "HTTP version" iRules command contains the request version and you can ensure that only valid requests are processed and allowed to your app servers with this iRule: when RULE_INIT { set INFO 0 set DEBUG 0 #------------------------------------------------------------------------ # HTTP Version #------------------------------------------------------------------------ set sec_http_version_enabled 0 set sec_http_version_block 1 set sec_http_version_alert 1 set sec_http_versions [list \ "0.9" \ "1.0" \ "1.1" \ ] } when HTTP_REQUEST { #============================================================================ # HTTP Version #============================================================================ if { $::INFO } { log local0. "ASSERTION: http_version" } if { $::sec_http_version_enabled } { if { $::DEBUG } { log local0. " HTTP Version: [HTTP::version]" } if { ! [matchclass [HTTP::version] equals $::sec_http_versions ] } { if { $::sec_http_version_alert } { log local0. " SEC-ALERT: Invalid HTTP Version found: '[HTTP::version]'" } if { $::sec_http_version_block } { reject } } else { if { $::DEBUG } { log local0. " PASSED" } } } } In the RULE_INIT method I've created a few global variablesenabling one to turn on or off theverification. Without all the extraconditionals, the iRule can be stripped down to the following couple of lines: when RULE_INIT { set sec_http_versions [list "0.9" "1.0" "1.1" ] } when HTTP_REQUEST { if { ! [matchclass [HTTP::version] equals $::sec_http_versions ] } { reject } } Stay tuned for the next installment of iRules Security 101 where I'll show how to validate HTTP methods. -Joe554Views0likes2Comments