cancel
Showing results for 
Search instead for 
Did you mean: 

Pulse Secure vADC

Sort by:
Stingray Traffic Manager version 9.5 includes some important enhancements to the RESTful API.  These enhancements include the following:   A new API version The API version has moved to 2.0.  Versions 1.0 and 1.1 are still available but have been deprecated.   Statistics and Version Information A new resource, "status", is available that contains the child resources "information" and "statistics", under the host name.  Data can only be retrieved for these resources; no updates are allowed.  The URL for "information" is: http(s)://<host>:<port>/api/tm/2.0/status/<host>/information   and the URI for "statistics" is:   http(s)://<host>:<port>/api/tm/2.0/status/<host>/statistics   <host> can also be "local_tm", which is an alias for the Traffic Manager processing the REST request.  For this release, only statistics for the local Traffic Manager are available.   The "information" resource contains the version of the Stingray Traffic Manager, so for example the request:   http(s)://<host>:<port>/api/tm/2.0/status/local_tm/information   for version 9.5 would return:   tm_version9.5   The "statistics" resource contains the Stingray statistics that are also available with SNMP or the SOAP API.  The following child resources are available under "statistics":   actions, bandwidth, cache, cloud_api_credentials, connection_rate_limit, events, glb_services, globals, listen_ips, locations, network_interface, nodes, per_location_service, per_node_slm, pools, rule_authenticators, rules, service_level_monitors, service_protection, ssl_ocsp_stapling, traffic_ips, virtual_servers   The statistics that are available vary by resource.   Example:   To get the statistics for the pool "demo" on the Stingray Traffic Manager "stingray.example.com": https://stingray.example.com:9070/api/tm/2.0/status/local_tm/statistics/pools/demo { "statistics": { "algorithm": "roundrobin", "bytes_in": 20476976, "bytes_out": 53323, "conns_queued": 0, "disabled": 0, "draining": 0, "max_queue_time": 0, "mean_queue_time": 0, "min_queue_time": 0, "nodes": 1, "persistence": "none", "queue_timeouts": 0, "session_migrated": 0, "state": "active", "total_conn": 772 } } Resource Name Changes Some resources have been renamed to be more clear:   actionprogs-> action_programs auth-> user_authenticators authenticators-> rule_authenticators cloudcredentials-> cloud_api_credentials events-> event_types extra-> extra_files flipper-> traffic_ip_groups groups-> user_groups scripts-> monitor_scripts services-> glb_services settings.cfg-> global_settings slm-> service_level_monitors vservers-> virtual_servers zxtms-> traffic_managers   New Resource   One new resource, "custom" has been added to support the new Custom Configuration Sets feature.  This allows arbitrary name:value configuration pairs to be stored in the Traffic Manager configuration system. As part of the Traffic Manager configuration, this data is replicated across a cluster and is accessible using the REST API, SOAP API and ZCLI.  All data structures supported by the Stinray REST API are also supported for Custom Configuration Sets.  Please see the REST API Guide for more information.
View full article
In October 2014, Google published details of a vulnerability in the SSL 3.0 protocol - named "POODLE" - which makes it possible for an attacker to decrypt messages between client and server in some circumstances. Because this is a problem with the protocol itself, rather than with a specific implementation of the protocol, this means that any client-server transaction which supports SSL 3.0 is at risk. Even if the client-server supports higher levels of security (such as TLS 1.2), it is possible for an attacker to force a downgrade to SSL 3.0 using a man-in-the-middle attack - which means that systems should disable SSL 3.0 to protect against this kind of attack, and use more recent security handshake protocols such as TLS.   How to Disable SSL 3.0 Completely   With Traffic Manager, it is easy to disable SSL v3.0 completely from the system console. Navigate to System->Global settings->SSL Configuration, and you can control how Traffic Manager manages SSL transactions:     How to Trap SSL Requests:   So we can disable SSL 3.0 completely, but some browsers will show an unhelpful error message: ideally, we would provide some extra feedback to the user to show what the problem is, and how to resolve it. Attach this TrafficScript rule to your virtual server: if you leave SSL 3.0 enabled, this rule permits any transaction using TLS, but traps SSL requests and returns a custom error message to the user:   $cipher = ssl.clientCipher(); if (string.len($cipher) > 0) { if (string.contains($cipher, "version=TLS")) { # this is the good case, incrementing the user SNMP counter counter64.increment(1,1); break; } else { # logic for the SSL (insecure) cases counter64.increment(2,1); # increment a counter for bad cases event.emit ("ssl request", "IP: ".request.getRemoteIP()." User-agent: ".http.getHeader("User-Agent")); http.sendResponse( "400 Bad request", "text/plain", "This service requires TLS security, and is using SSL security. \ Please verify your SSL/TLS settings and try again", "" ); } }   This TrafficScript rule will write an event message to the Traffic Manager log file, identifying the client IP and User Agent, and we also increment a user-defined counter to help track how often attempts are made to open an SSL transaction. These counters can be graphed on the Traffic Manager Activity Monitor, or retrieved remotely as user-defined SNMP variables, (use index 1 for good TLS requests, and index 2 for SSL requests that were rejected). The rule also raises a custom event named "ssl request" which can be used to trigger external actions if needed.   To test the script using Firefox, go to the "about:config" page, and change the value "security.tls.version.max" from the default of "3" to "0" This will force SSL 3.0 to be used instead of TLS. In newer versions of Firefox, you may also need to set "security.tls.version.min" to "0" - but don't forget to set these values back to a secure setting after testing.   Poodle icon designed by http://www.thenounproject.com/edward from the http://www.thenounproject.com.
View full article
We have created dedicated installation and configuration guides for each type of deployment option, as part of the complete documentation set for Pulse vTM.
View full article
Distributed denial of service (DDoS) attacks are the worst nightmare of every web presence. Common wisdom has it that there is nothing you can do to protect yourself when a DDoS attack hits you. Nothing? Well, unless you have Stingray Traffic Manager. In this article we'll describe how Stingray helped a customer keep their site available to legitimate users when they came under massive attack from the "dark side".   What is a DDoS attack?   DDoS attacks have risen to considerable prominence even in mainstream media recently, especially after the BBC published a report on how botnets can be used to send SPAM or take web-sites down and another story detailing that even computers of UK government agencies are taken over by botnets.   A botnet is an interconnected group of computers, often home PCs running MS Windows, normally used by their legitimate owners but actually under the control of cyber-criminals who can send commands to programs running on those computers. The fact that their machines are controlled by somebody else is due to operating system or application vulnerabilities and often unknown to the unassuming owners. When such a botnet member goes online, the malicious program starts to receive its orders. One such order can be to send SPAM emails, another to flood a certain web-site with requests and so on.   There are quite a few scary reports about online extortions in which web-site owners are forced to pay money to avoid disruption to their services.   Why are DDoS attacks so hard to defend against?   The reason DDoS attacks are so hard to counter is that they are using the service a web-site is providing and wants to provide: its content should be available to everybody. An individual PC connected to the internet via DSL usually cannot take down a server, because servers tend to have much more computing power and more networking bandwidth. By distributing the requests to as many different clients as possible, the attacker solves three problems in one go:   They get more bandwidth to hammer the server. The victim cannot thwart the attack by blocking individual IP addresses: that will only reduce the load by a negligible fraction. Also, clever DDoS attackers gradually change the clients sending the request. It's impossible to keep up with this by manually adapting the configuration of the service. It's much harder to identify that a client is part of the attack because each individual client may be sending only a few requests per second.   How to Protect against DDoS Attacks?   There is an article on how to ban IP addresses of individual attackers here: Dynamic Defense Against Network Attacks.The mechanism described there involves a Java Extension that modifies Stingray Traffic Manager's configuration via a SOAP call to add an offending IP address to the list of banned IPs in a Service Protection Class. In principle, this could be used to block DDoS attacks as well. In reality it can't, because SOAP is a rather heavyweight process that involves much too much overhead to be able to run hundreds of times per second. (Stingray's Java support is highly optimized and can handle tens of thousands of requests per second.)   The performance of the Java/SOAP combination can be improved by leveraging the fact that all SOAP calls in the Stingray API are array-based. So a list of IP addresses can be gathered in TrafficScript and added to Stingray's configuration in one call. But still, the blocking of unwanted requests would happen too late: at the application level rather than at the OS (or, preferably, the network) level. Therefore, the attacker could still inflict the load of accepting a connection, passing it up to Stingray Traffic Manager, checking the IP address inside Stingray Traffic Manager etc. It's much better to find a way to block the majority of connections before they reach Stingray Traffic Manager.   Introducing iptables   Linux offers an extensive framework for controlling network connections called iptables. One of its features is that it allows an administrator to block connections based on many different properties and conditions. We are going to use it in a very simple way: to ignore connection initiations based on the IP address of their origin. iptables can handle thousands of such conditions, but of course it has an impact on CPU utilization. However, this impact is still much lower than having to accept the connection and cope with it at the application layer.   iptables checks its rules against each and every packet that enters the system (potentially also on packets that are forwarded by and created in the system, but we are not going to use that aspect here). What we want to impede are new connections from IP addresses that we know are part of the DDoS attack. No expensive processing should be done on packets belonging to connections that have already been established and on which data is being exchanged. Therefore, the first rule to add is to let through all TCP packets that do not establish a new connections, i.e. that do not have the SYN flag set:   # iptables -I INPUT -p tcp \! --syn -j ACCEPT   Once an IP address has been identified as 'bad', it can be blocked with the following command:   # iptables -A INPUT -s [ip_address] -J DROP   Using Stingray Traffic Manager and TrafficScript to detect and block the attack   The rule that protects the service from the attack consists of two parts: Identifying the offending requests and blocking their origin IPs.   Identifying the Bad Guys: The Attack Signature   A gift shopping site that uses Stingray Traffic Manager to manage the traffic to their service recently noticed a surge of requests to their home page that threatened to take the web site down. They contacted us, and upon investigation of the request logs it became apparent that there were many requests with unconventional 'User-Agent' HTTP headers. A quick web search revealed that this was indicative of an automated distributed attack.   The first thing for the rule to do is therefore to look up the value of the User-Agent header in a list of agents that are known to be part of the attack:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 sub isAttack()  {      $ua = http.getHeader( "User-Agent" );      if ( $ua == "" || $ua == " " ) {         #log.info("Bad Agent [null] from ". request.getRemoteIP());         counter.increment(1,1);         return 1;      } else {         $agentmd5 = resource.getMD5( "bad-agents.txt" );         if ( $agentmd5 != data.get( "agentmd5" ) ) {            reloadBadAgentList( $agentmd5 );         }         if ( data.get( "BAD" . $ua ) ) {            #log.info("Bad agent ".$ua." from ". request.getRemoteIP());            counter.increment(2,1);            return 1;         }      }      return 0;  }    The rule fetches the relevant header from the HTTP request and makes a quick check whether the client sent an empty User-Agent or just a whitespace. If so, a counter is incremented that can be used in the UI to track how many such requests were found and then 1 is returned, indicating that this is indeed an unwanted request.   If a non-trivial User-Agent has been sent with the request, the list is queried. If the user-agent string has been marked as 'bad', another counter is incremented and again 1 is returned to the calling function. The techniques used here are similar to those in the more detailed HowTo: Store tables of data in TrafficScript article; when needed, the resource file is parsed and an entry in the system-wide data hash-table is created for each black-listed user agent.   This is accomplished by the following sub-routine:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sub reloadBadAgentList( $newmd5 )  {      # do this first to minimize race conditions:      data.set( "agentmd5" , $newmd5 );      $badagents = resource.get( "bad-agents.txt" );      $i = 0;      data. reset ( "BAD" ); # clear old entries      while ( ( $j = string.find( $badagents , "\n" , $i ) ) != -1 ) {         $line = string.substring( $badagents , $i , $j -1 );         $i = $j +1;         $entry = "BAD" .string.trim( $line );         log .info( "Adding bad UA '" . $entry . "'" );         data.set( $entry , 1 );      }  }    Most of the time, however, it won't be necessary to read from the file system because the list of 'bad' agents does not change often (if ever for a given botnet attack). You can download the file with the black-listed agents here and there is even a web-page dedicated to user-agents, good and bad.   Configuring iptables from TrafficScript   Now that TrafficScript 'knows' that it is dealing with a request whose IP has to be blocked, this address must be added to the iptables 'INPUT' chain with target 'DROP'. The most lightweight way to get this information from inside Stingray Traffic Manager somewhere else is to use the HTTP client functionality in TrafficScript provided by the function http.request.get(). Since many such 'evil' IP addresses are expected per second, it is a good idea to buffer up a certain number of IPs before making an HTTP request (the first of which will have some overhead due to TCP's three-way handshake, but of course much less than forking a new process; subsequent requests will be made over the kept-alive connection).   Here is the rule that accomplishes the task:   1 2 3 4 5 6 7 8 9 10 11 12 13 if ( isAttack() ) {      $ip = request.getRemoteIP();      $iplist = data.get( "badiplist" );      if ( string.count( $iplist , "/" )+1 >= 10 ) {         data.remove( "badiplist" );         $url = "http://127.0.0.1:44252" . $iplist . "/" . $ip ;         http.request.get( $url , "" , 5);      } else {         data.set( "badiplist" , $iplist . "/" . $ip );      }      connection. sleep ( $sleep );      connection.discard();  }    A simple 'Web Server' that Adds Rules for iptables   Now who is going to handle all those funny HTTP GET requests? We need a simple web-server that reads the URL, splits it up into the IPs to be blocked and adds them to iptables (unless it is already being blocked). On startup this process checks which addresses are already in the black-list to make sure they are not added again (which would be a waste of resources), makes sure that a fast path is taken for packets that do not correspond to new connections and then listens for requests on a configurable port (in the rule above we used port 44252).   This daemon doesn't fork one iptables process per IP address to block. Instead, it uses the 'batch-mode' of the iptables framework, iptables-restore. With this tool, you compile a list of rules and send all of them down to the kernel with a single commit command.   A lot of details (like IPv6 support, throttling etc) have been left out because they are not specific to the problem at hand, but can be studied by downloading the Perl code (attached) of the program.   To start this server you have to be root and invoke the following command:   # iptablesrd.pl   Preventing too many requests with Stingray Traffic Manager's Rate Shaping   As it turned out when dealing with the DDoS attack that plagued our client, the bottleneck in the whole process described up until now was the addition of rules to iptables. This is not surprising as the kernel has to lock some of its internal structures before each such manipulation. On a moderately-sized workstation, for example, a few hundred transactions can be committed per second when starting from an empty rule set. Once there are, say, 10,000 IP addresses in the list, adding more becomes slower and slower, down to a few dozen per second at best. If we keep sending requests to the 'iptablesrd' web-server at a high rate, it won't be able to keep up with them. Basically, we have to take into account that this is the place where processing is channeled from a massively parallel, highly scalable process (Stingray) into the sequential, one-at-a-time mechanism that is needed to keep the iptables configuration consistent across CPUs.   Queuing up all these requests is pointless, as it will only eat resources on the server. It is much better to let Stingray Traffic Manager sleep on the connection for a short time (to slow down the attacker) and then close it. If the IP address continues to be part of the botnet, the next request will come soon enough and we can try and handle it then.   Luckily, Stingray comes with rate-shaping functionality that can be used in TrafficScript. Setting up a 'Rate' class in the 'Catalog' tab looks like this:     The Rate Class can now be used in the rule to restrict the number of HTTP requests Stingray makes per second:   1 2 3 4 5 6 if ( rate.getBackLog( "DDoS Protect" ) < 1 ) {      $url = "http://localhost:44252" . $iplist . "/" . $ip ;      rate. use ( "DDoS Protect" );      # our 'webserver' never sends a response      http.request.get( $url , "" , 5);  }    Note that we simply don't do anything if the rate class already has a back-log, i.e. there are outstanding requests to block IPs. If there is no request queued up, we impose the rate limitation on the current connection and then send out the request.   The Complete Rule   To wrap this section up, here is the rule in full:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 $sleep = 300; # in milliseconds  $maxbacklog = 1;  $ips_per_httprequest = 10;  $http_timeout = 5; # in seconds  $port = 44252; # keep in sync with argument to iptablesrd.pl       if ( isAttack() ) {      $ip = request.getRemoteIP();      $iplist = data.get( "badiplist" );      if ( string.count( $iplist , "/" )+1 >= $ips_per_httprequest ) {         data.remove( "badiplist" );         if ( rate.getBackLog( "ddos_protect" ) < $maxbacklog ) {            $url = "http://127.0.0.1:" . $port . $iplist . "/" . $ip ;            rate. use ( "ddos_protect" );            # our 'webserver' never sends a response            http.request.get( $url , "" , $http_timeout );         }      } else {         data.set( "badiplist" , $iplist . "/" . $ip );      }      connection. sleep ( $sleep );      connection.discard();  }       $rawurl = http.getRawURL();  if ( $rawurl == "/" ) {      counter.increment(3, 1);  # Small delay - shouldn't annoy real users, will at least slow down attackers      connection. sleep (100);      http.redirect( "/temp-redirection" );  # Attackers will probably ignore the redirection. Real browsers will come back  }       # Re-write the URL before passing it on to the web servers  if ( $rawurl == "/temp-redirection" ) {      http.setPath( "/" );  }       sub isAttack()  {      $ua = http.getHeader( "User-Agent" );           if ( $ua == "" || $ua == " " ) {         counter.increment(1,1);         return 1;      } else {         $agentmd5 = resource.getMD5( "bad-agents.txt" );         if ( $agentmd5 != data.get( "agentmd5" ) ) {            reloadBadAgentList( $agentmd5 );         }         if ( data.get( "BAD" . $ua ) ) {            counter.increment(2,1);            return 1;         }      }      return 0;  }       sub reloadBadAgentList( $newmd5 )  {      # do this first to minimize race conditions:      data.set( "agentmd5" , $newmd5 );      $badagents = resource.get( "bad-agents.txt" );      $i = 0;      data. reset ( "BAD" );      while ( ( $j = string.find( $badagents , "\n" , $i ) ) != -1 ) {         $line = string.substring( $badagents , $i , $j -1 );         $i = $j +1;         $entry = "BAD" .string.trim( $line );         data.set( $entry , 1 );      }  }   Note that there are a few tunables at the beginning of the rule. Also, since in the particular case of the gift shopping site all attack requests went to the home page ("/"), a small slowdown and subsequent redirect was added for that page.   Further Advice   The method described here can help mitigate the server-side effect of DDoS attacks. It is important, however, to adapt it to the particular nature of each attack and to the system Stingray Traffic Manager is running on. The most obvious adjustment is to change the isAttack() sub-routine to reliably detect attacks without blocking legitimate requests.   Beyond that, a careful eye has to be kept on the system to make sure Stingray strikes the right balance between adding bad IPs (which is expensive but keeps further requests from that IP out) and throwing away connections the attackers have managed to establish (which is cheap but won't block future connections from the same source). After a while, the rules for iptables will block all members of the botnet. However, botnets are dynamic, they change over time: new nodes are added while others drop out.   An useful improvement to the iptablesrd.pl process described above would therefore be to speculatively remove blocks if they have been added a long time ago and/or if the number of entries crosses a certain threshold (which will depend on the hardware available).   Most DDoS attacks are short-lived, however, so it may suffice to just wait until it's over.   The further upstream in the network the attack can be blocked, the better. With the current approach, blocking occurs at the machine Stingray Traffic Manager is running on. If the upstream router can be remote-controlled (e.g. via SNMP), it would be preferable to do the blocking there. The web server we are using in this article can easily be adapted to such a scenario.   A word of warning and caution: The method presented here is no panacea that can protect against arbitrary attacks. A massive DDoS attack can, for instance, saturate the bandwidth of a server with a flood of SYN packets and such an attack can only be handled further upstream in the network. But Stingray Traffic Manager can certainly be used to scale down the damage inflicted upon a web presence and take a great deal of load from the back-end servers.   Footnote   The image at the top of the article is a graphical representation of the distribution of nodes on the internet produced by the opte project. It is protected by the Creative Commons License.
View full article
This article describes how to inspect and load-balance WebSockets traffic using Stingray Traffic Manager, and when necessary, how to manage WebSockets and HTTP traffic that is received on the same IP address and port.   Overview   WebSockets is an emerging protocol that is used by many web developers to provide responsive and interactive applications.  It's commonly used for talk and email applications, real-time games, and stock market and other monitoring applications.   By design, WebSockets is intended to resemble HTTP.  It is transported over tcp/80, and the initial handshake resembles an HTTP transaction, but the underlying protocol is a simple bidirectional TCP connection.   For more information on the protocol, refer to the Wikipedia summary and RFC 6455.     Basic WebSockets load balancing   Basic WebSockets Load Balancing   Basic WebSockets load balancing is straightforward.  You must use the 'Generic Streaming' protocol type to ensure that Stingray will correctly handle the asynchronous nature of websockets traffic.   Inspecting and modifying the WebSocket handshake   A WebSocket handshake message resembles an HTTP request, but you cannot use the built-in http.* TrafficScript functions to manage it because these are only available in HTTP-type virtual servers.   The libWebSockets.rts library (see below) implements analogous functions that you can use instead:   libWebSockets.rts   Paste the libWebSockets.txt library to your Rules catalog and reference it from your TrafficScript rule as follows:   import libWebSockets.rts as ws;   You can then use the ws.* functions to inspect and modify WebSockets handshakes.  Common operations include fixing up host headers and URLs in the request, and selecting the target servers (the 'pool') based on the attributes of the request.   import libWebSockets.rts as ws; if( ws.getHeader( "Host" ) == "echo.example.com" ) { ws.setHeader( "Host", "www.example.com" ); ws.setPath( "/echo" ); pool.use( "WebSockets servers" ); }   Ensure that the rules associated with WebSockets virtual server are configured to run at the Request stage, and to run 'Once', not 'Every'.  The rule should just be triggered to read and process the initial client handshake, and does not need to run against subsequent messages in the websocket connection:   Code to handle the WebSocket handshake should be configured as a Request Rule, with 'Run Once'   SSL-encrypted WebSockets   Stingray can SSL-decrypt TCP connections, and this operates fully with the SSL-encrypted wss:// protocol: Configure your virtual server to listen on port 443 (or another port if necessary) Enable SSL decryption on the virtual server, using a suitable certificate Note that when testing this capability, we found that Chrome refused to connect to WebSocket services with untrusted or invalid certificates, and did not issue a warning or prompt to trust the certificate.  Other web browsers may operate similarly.  In Chrome's case, it was necessary to access the virtual server directly ( https:// ), save the certificate and then import it into the certificate store.   Stingray can also SSL-encrypt downstream TCP connections (enable SSL encryption in the pool containing the real websocket servers) and this operates fully with SSL-enabled origin WebSockets servers.   Handling HTTP and WebSockets traffic   HTTP traffic should be handled by an HTTP-type virtual server rather than a Generic Streaming one.  HTTP virtual servers can employ HTTP optimizations (keepalive handling, HTTP upgrades, Compression, Caching, HTTP Session Persistence) and can access the http.* TrafficScript functions in their rules.   If possible, you should run two public-facing virtual servers, listening on two separate IP addresses.  For example, HTTP traffic should be directed to www.site.com (which resolves to the public IP for the HTTP virtual server) and WebSockets traffic should be directed to ws.site.com (resolving to the other public IP): Configure two virtual servers, each listening on the appropriate IP address   Sometimes, this is not possible – the WebSockets code is hardwired to the main www domain, or it's not possible to obtain a second public IP address. In that case, all traffic can be directed to the WebSockets virtual server and then HTTP traffic can be demultiplexed and forwarded internally to an HTTP virtual server:   Listen on a single IP address, and split off the HTTP traffic to a second HTTP virtual server   The following TrafficScript code, attached to the 'WS Virtual Server', will detect if the request is an HTTP request (rather than a WebSockets one) and hand the request off internally to an HTTP virtual server by way of a special 'Loopback Pool':   import libWebSockets.rts as ws; if( !ws.isWS() ) pool.use( "Loopback Pool" );   Notes: Testing WebSockets   The implementation described in this article was developed using the following browser-based client, load-balancing traffic to public 'echo' servers (ws://echo.websocket.org/, wss://echo.websocket.org, ws://ajf.me:8080/).   testclient.html   At the time of testing: echo.websocket.org did not respond to ping tests, so the default ping health monitor needed to be removed Chrome24 refused to connect to SSL-enabled wss resources unless they had a trusted certificate, and did not warn otherwise If you find this solution useful, please let us know in the comments below.
View full article
This video is a demo of Elastic Application Delivery using the Stingray Services Controller. It shows how monitoring something like throughput or concurrent connections can be used as a trigger for the Services Controller to spin up new instances of Stingray. This type of model can be used when building a very dynamic datacenter. The Flexible Licensing of the Services Controller enables a pool of licensed bandwidth to "follow an application".   Imagine how in an enterprise data center, different workloads are busy at different times of the day. For instance, early in the morning, the VMware View servers may be busy as desktops are booted, but after that "boot storm" they are relatively idle. Then a half hour later something like Microsoft Exchange or Siebel become busy... Well now using the flexible licenses of the Stingray Services Controller, an ADC can spin up during the busy times for one application, then shut down and return its resources to the pool, then as the next application becomes busy, it can bring up a different instance with bandwidth assigned to it, then return its bandwidth when it is done.   This type of model is only available with the Stingray Services Controller.  
View full article
Installation   Unzip the download ( Stingray Traffic Manager Cacti Templates.zip ) Via the Cacti UI, “Import Templates” and import the Data, Host, and Graph templates.  * Included graph templates are not required for functionality. Copy the files for the Cacti folder in the zip file to their corresponding directory inn your cacti install. Stingray Global Values script query - /cacti/site/scripts/stingray_globals.pl Stingray Virtual Server Table snmp query - cacti/resource/snmp_queries/stingray_vservers. Assign the host template to Traffic Manager(s) and create new graphs.   * Due to the method used by Cacti for creating graphs and the related RRD files, it is my recommendation NOT to create all graphs via the Device Page.   If you create all the graphs via the “*Create Graphs for this Host” link on the device page, Cacti will create an individual data source (RRD file and SNMP query for each graph) resulting in a significant amount of wasted Cacti and Device resources. Test yourself with the Stingray SNMP graph.   My recommendation is to create a single initial graph for each Data Query or Data Input method (i.e. one for Virtual Servers and one for Global values) and add any additional graphs via the Cacti’s Graph Management using the existing Data Source Drop downs.   Data Queries   Stingray Global Values script query - /cacti/site/scripts/stingray_globals.pl * Perl script to query the STM for most of the sys.globals values Stingray Virtual Server Table snmp query - cacti/resource/snmp_queries/stingray_vservers.xml * Cacti XML snmp query for the Virtual Servers Table MIB   Graph Templates   Stingray_-_global_-_cpu.xml Stingray_-_global_-_dns_lookups.xml Stingray_-_global_-_dns_traffic.xml Stingray_-_global_-_memory.xml Stingray_-_global_-_snmp.xml Stingray_-_global_-_ssl_-_client_cert.xml Stingray_-_global_-_ssl_-_decryption_cipher.xml Stingray_-_global_-_ssl_-_handshakes.xml Stingray_-_global_-_ssl_-_session_id.xml Stingray_-_global_-_ssl_-_throughput.xml Stingray_-_global_-_swap_memory.xml Stingray_-_global_-_system_-_misc.xml Stingray_-_global_-_traffic_-_misc.xml Stingray_-_global_-_traffic_-_tcp.xml Stingray_-_global_-_traffic_-_throughput.xml Stingray_-_global_-_traffic_script_data_usage.xml Stingray_-_virtual_server_-_total_timeouts.xml Stingray_-_virtual_server_-_connections.xml Stingray_-_virtual_server_-_timeouts.xml Stingray_-_virtual_server_-_traffic.xml     Sample Graphs (click image for full size)           Compatibility   This template has been tested with STM 9.4 and Cacti 0.8.8.a   Known Issues   Cacti will create unnecessary queries and data files if the “*Create Graphs for this Host” link on the device page is used. See install notes for work around.   Conclusion   Cacti is sufficient with providing SNMP based RRD graphs, but is limited in Information available, Analytics, Correlation, Scale, Stability and Support.   This is not just a shameless plug; Brocade offers a MUCH more robust set of monitoring and performance tools.
View full article
Dynamic information is more abundant now than ever, but we still see web applications provide static content. Unfortunately many websites are still using a static picture for a location map because of application code changes required. Traffic Manager provides the ability to insert the required code into your site with no changes to the application. This simplifies the ability to provide users dynamic and interactive content tailored for them.  Fortunately, Google provides an API to use embedded Google maps for your application. These maps can be implemented with little code changes and support many applications. This document will focus on using the Traffic Manager to provide embedded Google Maps without configuration or code changes to the application.   "The Google Maps Embed API uses a simple HTTP request to return a dynamic, interactive map. The map can be easily embedded in your web page by setting the Embed API URL as the src attribute of an iframe...   Google Maps Embed API maps are easy to add to your webpage—just set the URL you build as the value of an iframe's src attribute. Control the size of the map with the iframe's height and width attributes. No JavaScript required. "... -- Google Maps Embed API — Google Developers   Google Maps Embedded API Notes   Please reference the Google Documentation at Google Maps Embed API — Google Developers for additional information and options not covered in this document.   Google API Key   Before you get started with the Traffic Script, your need to get a Google API Key. Requests to the Google Embed API must include a free API key as the value of the URL key parameter. Your key enables you to monitor your application's Maps API usage, and ensures that Google can contact you about your website/application if necessary. Visit Google Maps Embed API — Google Developers to for directions to obtain an API key.   By default, a key can be used on any site. We strongly recommend that you restrict the use of your key to domains that you administer, to prevent use on unauthorized sites. You can specify which domains are allowed to use your API key by clicking the Edit allowed referrers... link for your key. -- Google Maps Embed API — Google Developers   The API key is included in clear text to the client ( search nerdydata for "https://www.google.com/maps/embed/v1/place?key=" ). I also recommend you restrict use of your key to your domains.   Map Modes   Google provides four map modes available for use,and the mode is specified in the request URL.   Place mode displays a map pin at a particular place or address, such as a landmark, business, geographic feature, or town. Directions mode displays the path between two or more specified points on the map, as well as the distance and travel time. Search mode displays results for a search across the visible map region. It's recommended that a location for the search be defined, either by including a location in the search term (record+stores+in+Seattle) or by including a center and zoom parameter to bound the search. View mode returns a map with no markers or directions.   A few use cases:   Display a map of a specific location with labels using place mode (Covered in this document). Display Parking and Transit information for a location with Search Mode.(Covered in this document). Provide directions (between locations or from the airport to a location) using Directions mode Display nearby Hotels or tourist information with Search mode using keywords or "lodging" or "landmarks" Use geo location and Traffic Script and provide a dynamic Search map of Gym's local to each visitor for your fitness blog. My personal favorite for Intranets Save time figuring out where to eat lunch around the office and use Search Mode with keyword "restaurant" Improve my Traffic Script productivity and use Search Mode with keyword "coffee+shops"   Traffic Script Examples   Example 1: Place Map (Replace a string)   This example covers a basic method to replace a string in the HTML code. This rule will replace a string within the existing HTML with Google Place map iframe HTML, and has been formatted for easy customization and readability.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #Only process text/html content  if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;        $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;   $googleapikey = "YOUR_KEY_HERE" ;   $googlemapurl = "https://www.google.com/maps/embed/v1/place" ;   #Map height and width   $mapheight = "420" ;   $mapwidth = "420" ;        #String of HTML to be replaced   $insertstring = "<!-- TAB 2 Content (Office Locations) -->" ;        #Replacement HTML   $googlemaphtml = "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" " .   "frameborder=\"0\" style=\"border:0\" src=\"" . $googlemapurl . "?q=" .   "" . $nearaddress . "&key=" . $googleapikey . "\"></iframe>" .        #Get the existing HTTP Body for modification   $body = http.getResponseBody();        #Regex sub against the body looking for the defined string   $body = string.replaceall( $body , $insertstring , $googlemaphtml );   http.setResponseBody( $body );    Example 2: Search Map (Replace a string) This example is the same as Example 1, but a change in the map type (note the change in the $googlemapurl?q=parking+near). This rule will replace a string within the existing HTML with Google Search map iframe HTML, and has been formatted for easy customization and readability.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #Only process text/html content  if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;           $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;    $googleapikey = "YOUR_KEY_HERE" ;    $googlemapurl = "https://www.google.com/maps/embed/v1/search" ;    #Map height and width    $mapheight = "420" ;    $mapwidth = "420" ;           #String of HTML to be replaced    $insertstring = "<!-- TAB 2 Content (Office Locations) -->" ;           #Replacement HTML    $googlemaphtml = "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" " .    "frameborder=\"0\" style=\"border:0\" src=\"" . $googlemapurl . "?q=parking+near+" .    "" . $nearaddress . "&key=" . $googleapikey . "\"></iframe>" .           #Get the existing HTTP Body for modification    $body = http.getResponseBody();           #Regex sub against the body looking for the defined string    $body = string.replaceall( $body , $insertstring , $googlemaphtml );    http.setResponseBody( $body );    Example 3: Search Map (Replace a section)   This example provides a different method to insert code into the existing HTML. This rule uses regex to replace a section of the existing HTML with Google map iframe HTML, and has also been formatted for easy customization and readability. The change from Example 2 can be noted (See $insertstring and string.regexsub).   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #Only process text/html content       if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;           $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;    $googleapikey = "YOUR_KEY_HERE" ;    $googlemapurl = "https://www.google.com/maps/embed/v1/search" ;    #Map height and width    $mapheight = "420" ;    $mapwidth = "420" ;          #String of HTML to be replaced    $insertstring = "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ;          #Replacement HTML    $googlemaphtml = "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" " .    "frameborder=\"0\" style=\"border:0\" src=\"" . $googlemapurl . "?q=parking+near+" .    "" . $nearaddress . "&key=" . $googleapikey . "\"></iframe>" .          #Get the existing HTTP Body for modification    $body = http.getResponseBody();          #Regex sub against the body looking for the defined string    $body = string.regexsub( $body , $insertstring , $googlemaphtml );    http.setResponseBody( $body );     Example 3.1 (Shortened)   For reference a shortened version of the Example 3 Rule above (with line breaks for readability):   1 2 3 4 5 6 7 8 if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" ) ) break;                http.setResponseBody ( string.regexsub( http.getResponseBody(),      "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ,      "<iframe width=\"420\" height=\"420\" frameborder=\"0\" style=\"border:0\" " .      "src=\"https://www.google.com/maps/embed/v1/search?" .      "q=parking+near+680+Folsom+St.+San+Francisco,+CA+94107" .      "&key=YOUR_KEY_HERE\"></iframe>" ) );     Example 4: Search Map ( Replace a section with formatting, select URL, & additional map)   This example is closer to a production use case. Specifically this was created with www.riverbed.com as my pool nodes. This rule has the following changes from Example 3: use HTML formatting to visually integrate with an existing application (<div class=\"six columns\">), only process for the desired URL path of contact (line #3), and provides an additional Transit Stop map (lines 27-31).   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #Only process text/html content in the contact path  if (!string.startsWith(http.getResponseHeader( "Content-Type" ), "text/html" )       || http.getpath() == "contact" ) break;       $nearaddress = "680+Folsom+St.+San+Francisco,+CA+94107" ;  $mapcenter = string.urlencode( "37.784465,-122.398570" );  $mapzoom = "14" ;  #Google API key  $googleapikey = "YOUR_KEY_HERE" ;  $googlemapurl = "https://www.google.com/maps/embed/v1/search" ;  #Map height and width  $mapheight = "420" ;  $mapwidth = "420" ;       #Regex match for the HTML section to be replaced  $insertstring = "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ;       #Replacment HTML  $googlemapshtml =   #HTML cleanup (2x "</div>") and New Section title  "</div></div></a><h4>Parking and Transit Information</h4>" .  #BEGIN Parking Map. Using existing css for layout  "<div class=\"six columns\"><h5>Parking Map</h5>" .  "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" frameborder=\"0\" " .  "style=\"border:0\" src=\"" . $googlemapurl . "?q=parking+near+" . $nearaddress . "" .  "&key=" . $googleapikey . "\"></iframe></div>" .  #BEGIN Transit Map. Using existing css for layout  "<div class=\"six columns\"><h5>Transit Stop's</h5>" .  "<iframe width=\"" . $mapwidth . "\" height=\"" . $mapheight . "\" frameborder=\"0\" " .  "style=\"border:0\" src=\"" . $googlemapurl . "?q=Transit+Stop+near+" . $nearaddress . "" .  "&center=" . $mapcenter . "&zoom=" . $mapzoom . "&key=" . $googleapikey . "\"></iframe></div>" .  #Include the removed HTML comment  "<!-- TAB 2 Content (Office Locations) -->" ;       #Get the existing HTTP Body for modification  $body = http.getResponseBody();       #Regex sub against the body looking for the defined string  $body = string.regexsub( $body , $insertstring , $googlemapshtml );  http.setResponseBody( $body );    Example 4.1 (Shortened)   For reference a shortened version of the Example 4 Rule above (with line breaks for readability):   1 2 3 4 5 6 7 8 9 10 11 12 13 14 if ( !string.startsWith ( http.getResponseHeader( "Content-Type" ), "text/html" )         || http.getpath() == "contact" ) break;           http.setResponseBody( string.regexsub(  http.getResponseBody() ,    "</a>Parking</h4>(?s)(.*)<!-- TAB 2 Content \\(Office Locations\\) -->" ,     "</div></div></a><h4>Parking and Transit Information</h4><div class=\"six columns\">" .    "<h5>Parking Map</h5><iframe width=\"420\" height=\"420\" frameborder=\"0\" " .    "style=\"border:0\" src=\"https://www.google.com/maps/embed/v1/search" .    "?q=parking+near+680+Folsom+St.+San+Francisco,+CA+94107&key=YOU_KEY_HERE\"></iframe>" .  "</div><div class=\"six columns\"><h5>Transit Stop's</h5><iframe width=\"420\" " .  "height=\"420\" frameborder=\"0\" style=\"border:0\" " .  "src=\"https://www.google.com/maps/embed/v1/search?q=Transit+Stop+near+" .  "680+Folsom+St.+San+Francisco,+CA+94107&center=37.784465%2C-122.398570&zoom=14" .  "&key=YOUR_KEY_HERE\"></iframe></div><!-- TAB 2 Content (Office Locations) -->" ) );  
View full article
This Document provides step by step instructions on how to set up Brocade Virtual Traffic Manager in Skype for Business architectures.
View full article
Pulse Secure vADC solutions are supported on Google Cloud Platform, with hourly billing options for applications that need to scale on-demand to match varying workloads. A range of Pulse Secure Virtual Traffic Manager (Pulse vTM) editions are available, including options for the Pulse vTM Developer Edition and Pulse Secure Virtual Web Application Firewall (Pulse vWAF), available as both a virtual machine and as a software installation on a Linux virtual machine.   This article describes how to quickly  create  a new Pulse   vTM instance through the Google Cloud Launcher. For additional information about the use and configuration of your Pulse vTM instance, see the product documentation available at www.pulsesecure.net/vadc-docs.   Launching a  Pulse   vTM Virtual Machine Instance   To launch a new instance of the  Pulse   vTM virtual machine, use the GCE Cloud Launcher Web site. Type the following URL into your Web browser:   https://cloud.google.com/launcher Browse or use the search tool to locate the Pulse Secure package applicable to your requirements, then click the package icon to see the   package detail screen.       To deploy a new   Pulse  vTM instance   1.  To start the process of deploying a new instance, click Launch on Compute Engine.   2.  Type an identifying name for the instance, select the image version, then select the desired geographic zone and machine type. Individual zones might have differing computing resources available and specific access restrictions. Contact your support provider for further details. 3.  Ensure the boot disk correspond to your computing resource requirements. Pulse Secure recommends not changing the default disk size as this might affect the performance of your Pulse vTM.   4.  By default, GCE creates firewall rules to allow HTTP and HTTPS traffic, and to allow access to the Web-based Pulse vTM Admin UI on TCP port 9090. To instead restrict access to these services, untick the corresponding firewall checkboxes.   Note: If you disable access to TCP port 9090, you cannot access the Pulse vTM Admin UI to configure the instance.   5.  If you want to use IP Forwarding with this instance, click More and set IP forwarding to "On".   6.  Pulse  vTM needs access to the Google Cloud Compute API, as indicated in the API Access section. Keep this option enabled to ensure your instance can function correctly.   7.  Click Deploy  to launch the Pulse vTM instance.   The Google Developer Console confirms that your Pulse vTM instance is being deployed.     Next Steps   After your new instance has been created, you can proceed to configure your Pulse vTM software through its Admin UI.   To access the Admin UI for a successfully deployed instance, click Log into the admin panel.       When you connect to the Admin UI for the first time, Pulse vTM presents the  Initial Configuration wizard . This wizard captures the networking, date/time, and basic system settings needed by your Pulse vTM software to operate normally.   For full details of the configuration process, and for instructions on performing various other administrative tasks, see the Cloud Services Installation and Getting Started Guide .
View full article
Customers may occasionally need to install additional software on a Virtual Appliance, and this document shows how you can install the software in a way which will be supported. Examples of where this might be useful include:   Installing monitoring agents that customers use to monitor the rest of their infrastructure (e.g. Nagios) Installing other data collection tools (e.g. for Splunk or ELK) Note that for earlier versions of the Traffic Manager Virtual Appliance (before 9.7) we support customers installing software only via our standard APIs/interfaces (using extra files, custom action scripts). This "open access virtual appliance" support policy was introduced at version 9.7, to allow installation of additional software. However, we still do not support customers modifying the tested software shipped with the appliance.   Operating system   Traffic Manager virtual appliances use a customized build of Ubuntu, with an optimized kernel from which some unused features have been removed - check the latest release notes for details of the build included in your version.   What you may change   You may install additional software not shipped with the appliance, but note that some Ubuntu packages may rely on kernel features not available on the appliance.   You may modify configuration not managed by the appliance.   What you may not change   You may not install a different kernel.   You may not install different versions of any debian packages that were installed on the appliance as shipped, nor remove any of these packages (see the licence acknowledgements doc for a list).   You may not directly modify configuration that is managed from the traffic manager (e.g. sysctl values, network configuration).   You may not change configuration explicitly set by the appliance (usually marked with a comment containing ZOLD or  BEGIN_STINGRAY_BLOCK).   What happens when you need support   You should mention any additional software you have installed when requesting support, the Technical Support Report will also contain information about it. If the issue is found to be caused by interaction with the additional software we will ask you to remove it, or to seek advice or a remedy from its supplier.   What happens on reset or upgrade   z-reset-to-factory-defaults will not remove additional software but may rewrite some system configuration files.   An upgrade will install a fresh appliance image on a separate disk partition, and will not copy additional software or configuration changes across. The /logs partition will be preserved.   Note that future appliance versions may change the set of installed packages, or even the underlying operating system.
View full article
In many cases, it is desirable to upgrade a virtual appliance by deploying a virtual appliance at the newer version and importing the old configuration.  For example, the size of the Traffic Manager disk image was increased in version 9.7, and deploying a new virtual appliance lets a customer take advantage of this larger disk.  This article documents the procedure for deploying a new virtual appliance with the old configuration in common scenarios.   These instructions describe how to upgrade and reinstall Traffic Manager appliance instances (either in a cluster or standalone appliances). For instructions on upgrading on other platforms, please refer to Upgrading Traffic Manager.   Upgrading a standalone Virtual Appliance   This process will replace a standalone virtual appliance with another virtual appliance with the same configuration (including migrating network configuration). Note that the Traffic Manager Cloud Getting Started Guide contains instructions for upgrading a standalone EC2 instance from version 9.7 onwards; if upgrading from a version prior to 9.7 and using the Web Application Firewall these instructions must be followed to correctly back up and restore any firewall configuration.   Make a backup of the traffic manager configuration (See section "System > Backups" in the Traffic Manager User Manual), and export it. If you are upgrading from a  version prior to 9.7 and are using the Web Application Firewall, back up the Web Application Firewall configuration - Log on to a command line - Run /opt/zeus/stop-zeus - Copy /opt/zeus/zeusafm/current/var/lib/config.db off the appliance. Shut down the original appliance. Deploy a new appliance with the same network interfaces as the original. If you backed up the application firewall configuration earlier, restore it here onto the new appliance, before you restore the traffic manager configuration: - Copy the config.db file to /opt/zeus/stingrayafm/current/var/lib/config.db    (overwriting the original) - Check that the owner on the config.db file is root, and the mode is 0644. Import and restore the traffic manager configuration via the UI. If you have application firewall errors Use the Diagnose page to automatically fix any configuration errors Reset the Traffic Manager software.   Upgrading a cluster of Virtual Appliances (except Amazon EC2)   This process will replace the appliances in the cluster, one at a time, maintaining the same IP addresses. As the cluster will be reduced by one at points in the upgrade process, you should ensure that this is carried out at a time when the cluster is otherwise healthy, and of the n appliances in the cluster, the load can be handled by (n-1) appliances.   Before beginning the process, ensure that any cluster errors have been resolved. Nominate the appliance which will be the last to be upgraded (call it the final appliance).  When any of the other machines needs to be removed from the cluster, it should be done using the UI on this appliance, and when a hostname and port are required to join the cluster, this appliance's hostname should be used. If you are using the Web Application Firewall first ensure that vWAF on the final appliance in the cluster is upgraded to the most recent version, using the vWAF updater. Choose an appliance to be upgraded, and remove the machine from the cluster: - If it is not the final appliance (nominated in step 2),    this should be done via the UI on the final appliance - If it is the final appliance, the UI on any other machine may be used. Make a backup of the traffic manager configuration (System > Backups) on the appliance being upgraded, and export the backup.  This backup only contains the machine specific info for that appliance (networking config etc). Shut down the appliance, and deploy a new appliance at the new version.  When deploying, it needs to be given the identical hostname to the machine it's replacing. Log on to the admin UI of the new appliance, and import and restore the backup from step 5. If you are using the Web Application Firewall, accessing the Application Firewall tab in the UI will fail and there will be an error on the Diagnose page and an 'Update Configuration' button. Click the Update Configuration button once, then wait for the error to clear.  The configuration is now correct, but the admin server still needs to be restarted to pick up the configuration: # $ZEUSHOME/admin/rc restart Now, upgrade the application firewall on the new appliance to the latest version. Join into the cluster: For all appliances except the final appliance, you must not select any of the auto-detected existing clusters.  Instead manually specify the hostname and port of the final appliance. If you are using Web Application Firewall, there may be an issue where the config on the new machine hasn't synced the vWAF config from the old machine, and clicking the 'Update Application Firewall Cluster Status' button on the Diagnose page doesn't fix the problem. If this happens, firstly get the clusterPwd from the final appliance: # grep clusterPwd /opt/zeus/zxtm/conf/zeusafm.conf clusterPwd = <your cluster pwd> On the new appliance, edit /opt/zeus/zxtm/conf/zeusafm.conf (with e.g. nano or vi), and replace the clusterPwd with the final appliance's clusterPwd. The moment that file is saved, vWAF should get restarted, and the config should get synced to the new machine correctly. When you are upgrading the final appliance, you should select the auto-detected existing cluster entry, which should now list all the other cluster peers. Once a cluster contains multiple versions, configuration changes must not be made until the upgrade has been completed, and 'Cluster conflict' errors are expected until the end of the process. Repeat steps 4-9 until all appliances have been upgraded.   Upgrading a cluster of STM EC2 appliances   Because EC2 licenses are not tied to the IP address, it is recommended that new EC2 instances are deployed into a cluster before removing old instances.  This ensures that the capacity of the cluster is not reduced during the upgrade process.  This process is documented in the "Creating a Traffic Manager Instances on Amazon EC2" chapter in the Traffic Manager Cloud Getting Started Guide.  The clusterPwd may also need to be fixed as above.
View full article
 UPDATE January 2015: libDNS version 2.1 released! The new release is backward-compatible with previous releases and includes the following bug fixes: Fixed multiple bugs in parsing of DNS records   The libDNS.rts library (written by Matthew Geldert and enhanced by Matthias Scheler) attached below provides a means to interrogate and modify DNS traffic from a TrafficScript rule, and to respond directly to DNS request when desired.   You can use it to:   Modify DNS requests on the fly, rewriting a lookup for one address so that it becomes a lookup for a different one: HowTo: Modify DNS requests using libDNS.rts Intercept and respond directly to DNS requests, informed by TrafficScript logic: HowTo: Respond directly to DNS requests using libDNS.rts Implement a simple DNS responder (avoiding the need for a back-end DNS server) - particularly useful in a Global Server Load Balancing scenario: HowTo: Implement a simple DNS resolver using libDNS.rts   Note: This library allows you to inspect and modify DNS traffic as it is balanced by Stingray.  If you want to issue DNS requests from Stingray, check out the net.dns.resolveHost() and net.dns.resolveIP() TrafficScript functions for this purpose.   Overview   This rule can be used when Stingray receives DNS lookups (UDP or TCP) using a Virtual Server, and optionally uses a pool to forward these requests to a real DNS server:   Typically, a listen IP addresses of the Stingray will be published as the NS record for a subdomain so that clients explicitly direct DNS lookups to the Stingray device, although you can use Stingray software in a transparent mode and intercept DNS lookups that are routed through Stingray using the iptables configuration described in Transparent Load Balancing with Stingray Traffic Manager.   Installation     Step 1:   Configure Stingray with a virtual server listening on port 53; you can use the 'discard' pool to get started:   If you use 'dig' to send a DNS request to that virtual server (listening on 192.168.35.10 in this case), you won't get a response because the virtual server will discard all requests:   $ dig @192.168.35.10 www.zeus.com ; <<>> DiG 9.8.3-P1 <<>> @192.168.35.10 www.zeus.com ; (1 server found) ;; global options: +cmd ;; connection timed out; no servers could be reached   Step 2:   Create a new rule named libDNS.rts using the attached TrafficScript Source:   This rule is used as a library, so you don't need to associate it with a Virtual Server.   Then associate the following request rule with your virtual server:   import libDNS.rts as dns; $request = request.get(); $packet = dns.convertRawDataToObject($request, "udp"); # Ignore unparsable packets and query responses to avoid # attacks like the one described in CVE-2004-0789. if( hash.count( $packet ) == 0 || $packet["qr"] == "1" ) { break; } log.info( "DNS request: " . lang.dump( $packet ) ); $host = dns.getQuestion( $packet )["host"]; $packet = dns.addResponse($packet, "answer", $host, "www.site.com.", "CNAME", "IN", "60", []); $packet["qr"] = 1; log.info( "DNS response: " . lang.dump( $packet ) ); request.sendResponse( dns.convertObjectToRawData($packet, "udp"));   This request rule will catch all DNS requests and respond directly with a CNAME directing the client to look up 'www.site.com' instead:   $ dig @192.168.35.10 www.zeus.com ; <<>> DiG 9.8.3-P1 <<>> @192.168.35.10 www.zeus.com ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<     Documentation   This DNS library provides a set of helper functions to query and modify DNS packets.  Internally, a decoded DNS packet is represented as a TrafficScript datastructure and when you are writing and debugging rules, it may be useful to use log.info( lang.dump( $packet ) ) as in the rule above to help understand the internal structures.   Create a new DNS packet   $packet = dns.newDnsObject(); log.info( lang.dump( $packet ) );   Creates a data structure model of a DNS request/response packet. The default flags are set for an A record lookup. Returns the internal hash data structure used for the DNS packet.   Set the question in a DNS packet   $packet = dns.setQuestion( $packet, $host, $type, $class );   Sets the question in a data structure representation of a DNS packet.   $packet - the packet data structure to manipulate. $host - the host to lookup. $type - the type of RR to request.   Returns the modified packet data structure, or -1 if the type is unknown.     Get the question in the DNS packet   $q = dns.getQuestion( $packet ); $host = $q["host"]; $type = $q["type"]; $class = $q["class"];   Gets the question from a data structure representing a DNS request/response.  Returns a hash of the host and type in the data structure's question section.   Add an answer to the DNS packet   $packet = dns.addResponse($packet, $section, $name, $host, $type, $class, $ttl, $additional);   Adds an answer to the specified RR section:   $packet - the packet data structure to manipulate. $section - name of the section ("answer", "authority" or "additional") to add the answer to $name, $host, $type, $class, $ttl, $additional - the answer data   Returns the modified packet data structure.   Remove an answer from the DNS packet   $packet = dns.removeResponse( $packet, $section, $answer ); while( $packet["additionalcount"] > 0 ) { $packet = dns.removeResponse( $packet, "additional", 0); }   Removes an answer from the specified RR section.   $packet - the packet data structure to manipulate. $section - name of the section ("answer", "authority" or "additional") to remove the entry from $answer - the array position of the answer to remove (0 removes the first).   Returns the modified packet data structure, or -1 if the specified array key is out of range.   Convert the datastructure packet object to a raw packet   $data = dns.convertObjectToRawData( $packet, $protocol ); request.sendResponse( $data );   Converts a data structure into the raw data suitable to send in a DNS request or response.   $packet - data structure to convert. $protocol - transport protocol of data ("udp" or "tcp").   Returns the raw packet data.     Convert a raw packet to  an internal datastructure object   $data = request.get(); $packet = dns.convertRawDatatoObject( $data, $protocol );   Converts a raw DNS request/response to a manipulatable data structure.   $data - raw DNS packet $protocol - transport protocol of data ("udp" or "tcp")   Returns trafficscript data structure (hash).     Kudos   Kudos to Matthew Geldert, original author of this library, and Matthias Scheler, author of version 2.0.
View full article
This article describes how TrafficScript manages the memory needed when a rule executes, and how it references connection and global data that is stored outside of a rule's execution environment.  It will help you understand the differences between local variables in TrafficScript, connection-local variables ( connection.data.get/set ), resource data ( resource.get ) and global data ( data.get/set ). Overview TrafficScript is a very lightweight compiled language.  TrafficScript rules are compiled into a Stingray-internal bytecode with about a dozen simple stack-based instructions and are executed on an internal 'virtual machine' (code-named ' ichor ').  All of the 'heavy lifting' (i.e. all of the trafficscript functions) are implemented by internal Stingray procedures (not by the TrafficScript language) so the performance of TrafficScript is driven by native Stingray performance rather than the performance of the virtual machine bytecode. The biggest single determinant of performance in an optimized, lightweight virtual machine like ichor is the use of memory.  Ichor goes to great pains to minimize memory copies by use of references and region-based memory management where possible to reduce the overhead as far as possible. In this article, we'll consider how TrafficScript addresses memory via the String datatype.  Internally, Strings are implemented as references (pointer-and-length) to memory that is often managed outside of the Ichor runtime.  From Ichor's perspective, this memory is read-only; multiple strings can refer to the same memory area and memory is only copied when a new string with new contents is created.  This allows ichor to make assumptions that significantly improve execution speed and memory footprint. A model of memory The diagram below outlines five types of memory that TrafficScript can address. Constants TrafficScript constants (string, integer and double values) are stored with the compiled TrafficScript rule Stored with the compiled TrafficScript rule: String, integer and double values that are declared in a TrafficScript rule are stored with the rule bytecode and referenced directly.  They are deduped, simply to reduce the memory footprint of the compiled TrafficScript rule. Local variables and Temporary values Variables and other temporary values are stored in a temporary memory region that is discarded once the rule has finished executing. Stored for the scope of the rule execution: Local variables and temporary values that are created during the execution of a TrafficScript rule are stored on the execution stack and in the growable heap used by the TrafficScript virtual machine. Because string data uses references rather than private copies, code like the following is very efficient: $body = http.getResponseBody(); if( string.regexMatch( $body, "(.*?)(<body.*?>)(.*)" ) ) {   $head = $1;   $bodytag = $2;   $remainder = $3; } No memory copies are made during the regex search and the assignment of the results to $head , $bodytag and $remainder .  These variables simply contain references to substrings within Stingray's internal copy of the response body. TrafficScript variables and temporaries are only valid for the duration of the rule's execution; persistent data is copied out of the heap as a side-effect of the relevant TrafficScript operations and the heap is safely and quickly discarded in a single operation when the rule execution completes. Per-connection data Data can be stored with a connection using connection.data.set() , and retrieved by a later rule using connection.data.get() .  This is used when sharing state between the rules that process a connection. Stored for the duration of the connection: A connection that is processed by Stingray uses a variety of memory data structures for various data types. HTTP headers and other connection data is stored with the connection.  If a TrafficScript rule requests the value of the path or a header (for example), it is given a reference to the connection-local memory containing the path, so there are no memory copies.  If a TrafficScript rule updates the value of the path (for example, using http.setPath() ), then the connection-local copy is updated so that the value persists when the TrafficScript rule completes. In the example above where the TrafficScript rule used http.getResponseBody() , all of the strings refer to the connection-local copy of the body, and this single copy is used by all TrafficScript rules that need to access it in a read-only fashion. Note: Stingray's HTTP virtual server type abstracts an HTTP transaction from the underlying TCP connection.  Connection-local data is associated with the HTTP transaction and discarded when the transaction completes. connection.data.set(): You can explicitly store data with a connection-scope using the connection.data.set() trafficscript function.  This places a copy of the data in the connection's growable memory pool and this data can be retrieved by a later TrafficScript rule ( connection.data.get() ) or a transaction log macro.  The connection's memory pool is discarded in a single operation once the connection has completed. Per-process data Resource files are stored per-process and can be referenced efficiently using resource.get() and related functions. The most common per-process data that TrafficScript will address is the contents of resource files.  Resource files sit in the extra section of the Stingray configuration.  They are loaded into memory and stored persistently at startup, and whenever they change on disk. resource.get() returns a reference to the body of the already-loaded resource file.  In a similar fashion, resource.getMTime() and resource.getMD5() return the pre-calculated values so there is no disk or compute overhead from invoking these functions. Global data Data can be shared between all rules using the global key-value store.  Access the data using data.get(), data.set() and related functions. On a multi-core machine, Stingray will typically run one zeus.zxtm traffic manager process per core.  These processes share a fixed-size shared memory segment that is allocated at startup. This shared memory segment is used for a number of purposes - sharing session persistence data, bandwidth and rate data, the web content cache, etc.  It includes a key-value store called the Global Data Table that you address using TrafficScript functions such as data.set() and data.get() . The Global Data Table is the key memory resource to use if you want to share data between different connections (the alternative is an external solution accessed using a Java Extension or other external callout, or a client-side cookie).  Keys and values are stored as strings (other types are serialized and deserialized on demand), and the size of the table is fixed (trafficscript!data_size) so you must track and discard entries yourself.  Without locking, iterators or memory management, using the global data table effectively can be a challenge. data.set( $key, $value ) : put a copy of the key/value pair in the global data table, serializing non-string datastructures where necessary data.get( $key ) : return the corresponding value, de-serializing where necessary, or the empty string if $key is not recognised data.remove( $key ) : removes the key/value pair from the table, freeing the memory used by both data.reset( [$prefix] ) : removes every entry, or just entries where the key begins with $prefix, from the table, freeing memory data.getMemoryUsage() and data.getMemoryFree(): indicate memory usage and can be used to detect impending memory exhaustion Read more HowTo: TrafficScript Arrays and Hashes Investigating the performance of TrafficScript - storing tables of data (illustrates efficient use of the global data table)
View full article
What is SteelApp? SteelApp is a software Application Delivery Controller.  It's generally installed as a proxy, in front of groups of web servers, app servers and other networked applications. Stingray provides the core features of a Load Balancer or Application Delivery Controller, an Application Firewall and Web Content Optimization.  It also provides a rich data-plane programming environment called TrafficScript that lets you control how users interact with your services, letting you visualize, prioritize, rewrite, filter and debug all transactions. Read more: Check out the key Product Briefs for Stingray Traffic Manager. Download and Install SteelApp The quickest way to get started with Stingray is to begin with the Developer Edition.  Grab either the software (Linux or Solaris) or Virtual Appliance (VMware, Xen or OracleVM) installation and follow the instructions in the appropriate Getting Started guide. If you have a particular project in mind and you would like assistance from Riverbed's technical and sales team, you should register for a full Stingray Evaluation. Where to next? Try Getting Started - Load-balancing to a website using Stingray Traffic Manager to begin. Then you can check out the Stingray Splash Community in more depth: Learn about Stingray Traffic Manager (the Feature Brief: Introduction to the Stingray Architecture is a good place to begin) Browse through the tech tips and solutions Check out the product videos Ask a question or join a discussion Share suggestions and raise feature requests
View full article
This Document provides step by step instructions on how to set up Brocade Virtual Traffic Manager for Oracle WebLogic Applications. Sample applications that can be deployed using this document include Oracle's PeopleSoft and Blackboard's Academic Suite.   This document has been updated from the original deployment guides written for Riverbed Stingray and SteelApp software.
View full article
Following the recent security vulnerability in the OpenSSL TLS implementation (see CVE-2014-0160) server administrators have been scrambling to protect vulnerable services.   Fortunately any virtual server or pool using Stingray Traffic Manager's built-in support for TLS (the ssl_decrypt or ssl_encrypt settings) are not vulnerable, see this Knowledge Base article for the status of all Riverbed products.   One write-up of the vulnerability asks;   Can I detect if someone has exploited this against me?   and;   Can IDS/IPS detect or block this attack?   This article shows how STM's TrafficScript can operate on connections to log possible attempts at exploitation of this vulnerability, and drop only those connections that may be malicious.   A simple TrafficScript rule to drop TLS connections using heartbeat messages   To get started, the following simple TrafficScript rule can be used as a request rule drop to all incoming heartbeat records (make sure that the rule runs for every request made on the connection by checking "Every" and not "Once" in the administrative UI);   # Get the TLS record header $record_header = request.get( 5 ); # Check if this record is a heartbeat record. $content_type = lang.ord( string.left( $record_header, 1 ) ); if( $content_type == 24 ) { connection.discard(); # Terminate the connection } # Not a heartbeat record, so skip to the next record. $record_length = ( lang.ord( string.substring( $record_header, 3, 3 ) ) << 8 ) | lang.ord( string.substring( $record_header, 4, 4 ) ); request.endsAt( 5 + $length );   To test our homemade Intrusion Detection/Prevention System (IDS/IPS) we will first need to arrange for the traffic to pass through the traffic manager on its way to a TLS server.  For example purposes, I have setup a TLS server using the openssl command line utility:   openssl s_server -accept 34848 -cert file.cert -key file.key -www -msg   This instructs an openssl test server to reply to incoming TLS/HTTP requests on port 34848 with an HTML page.   Browsing to https://localhost:34848/ on same machine (and ignoring any warnings about the invalid certificates, depending on how you created file.cert) leads to the output like; read from 0x1ae8c50 [0x1aee340] (11 bytes => 11 (0xB)) 0000 - 16 03 01 02 00 01 00 01-fc 03 03                  ........... read from 0x1ae8c50 [0x1aee34e] (506 bytes => 506 (0x1FA)) : write to 0x1ae8c50 [0x1af7e30] (66 bytes => 66 (0x42)) 0000 - 16 03 03 00 3d 02 00 00-39 03 03 53 4e 60 26 00   ....=...9..SN`&. : :   I've specifically picked out the beginning of two TLS records, where each TLS record's bytes are formatted like so; struct {        ContentType type;        ProtocolVersion version;        uint16 length;        select (SecurityParameters.cipher_type) {            case stream: GenericStreamCipher;            case block:  GenericBlockCipher;            case aead:   GenericAEADCipher;        } fragment;    } TLSCiphertext;   Both the client's message and the server's response above have their first byte as 0x16 - ContentType "handshake", the fourth and fifth bytes give the length of the data following the record header: for the ClientHello handshake message the client sent this is 0x200 (512) bytes.  The TLS heartbeat records we are interested in have ContentType of 24 (or 0x18).   To pass the request and response through STM I configure;   a pool "my TLS service" in traffic manager, adding your test server as its node, and a virtual server "my IDS" that uses "my TLS service" as its default pool. The virtual server has its protocol set to "SSL (HTTPS)" so that it will pass-through the TLS traffic as it arrives. Make sure the TrafficScript above has been added to to the Rules Catalog, and that it has been configured as a request rule on this virtual server.   Directing your browser to the newly created virtual server should behave just as before, except any connection where TLS heartbeat messages are exchanged will be terminated.  You may want to verify your newly protected system by using one of the many tools available; here are two examples:   First, from Filippo Valsorda, a web based tool where you simply type in the URL for virtual server (if accessible from the internet): https://filippo.io/Heartbleed/ Second, from Steffen Ullrich (and others) , a perl script that may be more suitable for testing a test deployment: https://github.com/noxxi/p5-scripts/blob/master/check-ssl-heartbleed.pl You should take care to only perform vulnerability testing on systems where you have permission to do so.   A comprehensive TrafficScript rule with a customizable response to TLS heartbeat messages   The above TrafficScript rule is simple and effective at preventing both heartbleed attack requests to a server and compromising responses from a client; it is, however, quite a blunt instrument.  It doesn't consider the case where the applications legitimately use TLS heartbeat messages for regular operation, and it will result in the traffic manager buffering the whole record before forwarding it on to the server (which may or may not impact performance, depending on the traffic your deployment observes).   A more complex TrafficScript rule can avoid these particular pitfalls, in particular being able to operate where TLS heartbeat messages are required, providing detailed event reporting and enabling the data to be streamed by the traffic manager.  You can find such a rule below, it improves upon the simple rule above in the following ways: It can be used as both a request and response rule (providing protection both clients and servers from attacks requests and/or compromising responses). It has a configurable threshold level (in the case where your applications require the heartbeat messages to operate correctly). It has a customizable "what to do on detection" sub-routine (it currently records the detected attack in the error log and terminates the connection, but you have the full power of TrafficScript available to you to adopt a suitable strategy for your deployment).   # A TrafficScript rule for detecting suspicious TLS Heartbeat records, with # a view to providing protection against the Heartbleed vulnerability # (CVE-2014-0160). # # Copyright (c) 2014, Riverbed Technology # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # This rule can be used as either a request and/or response rule on a virtual # server operating at the TCP level (it is recommended for use only on # virtual servers configured explicitly for SSL passthrough). Ensure the # rule is configured to be executed "everytime" on the virtual server. # The $threshold variable provides the primary configurable for this rule. # It represents the threshold size for TLS Heartbeat records above # which an error is generated and the connection dropped. Use a value of 0 # if you know heartbeat messages are never legitimately used, otherwise pick a # suitable value above which no valid client/server would use in your # deployment. # # Note: Any value above 0 does not prevent a heartbleed attack, it will just # mean naive attacks are more likely to be detected and prevented. # $threshold = 0; # bytes above which we consider the heartbeat malicious. # The action_to_take_on_detection subroutine is called by the rule when a # heartbeat message exceeding the threshold is detected. This subroutine # is provided to make it easy to customize the action to take upon # identification. # # The parameter provides the length of the threshold exceeding record. # sub action_to_take_on_detection( $length ) { # Create a description of who is involved and how. $prefix = "request from "; $from = ip_and_port_to_string( request.getRemoteIP(), request.getRemotePort() ); $to = ""; if( rule.getstate() == "RESPONSE" ) { $prefix = "response from "; $to = " to " . $from; $from = ip_and_port_to_string( response.getRemoteIP(), response.getRemotePort() ); } $who = $prefix . $from . $to; log.error( "Oversized Heartbeat packet detected, possible Heartbleed attack " . "(CVE-2014-0160), " . $length - $threshold . " bytes beyond threshold in " . $who ); # Could also add a specific alert, event.emit(...), to trigger notification to # an administrator. connection.discard(); # Do not send anything more to the client } # --- Primary rule logic starts here --- # Get the current state of the TLS record reading. # # The state is used to maintain the state of TLS record reading across # multiple executions of the rule for a single connection. This is # effectively an ordered pair, stored as two separate variables. The # semantics are: # # "remaining" The remaining data to be read for the current TLS record. Used # to determine where the next header to be considered for # heartbleed detection can be found in the stream. # # "saved" Saved data from a previous execution, to be prepended to # whatever data has been read by this execution. Used to store # partially complete SSL/TLS records (for when a record straddles # TCP packet boundaries). This should be 4 bytes at most. # # Note the invariants below which follows from the semantics described. $remaining_state_name = "heartbleed-remaining-" . rule.getname() . "-" . rule.getstate(); $saved_state_name = "heartbleed-saved-" . rule.getname() . "-" . rule.getstate(); # The starting position of the next record (relative to this rule). $pos = lang.toInt( connection.data.get( $remaining_state_name ) ); # The buffer to work with is whatever we have now, plus any saved data # from a previous execution. $buffer = lang.toString( connection.data.get( $saved_state_name ) ); # Sanity checks - can be removed - codifies the invariant that if we have # some "saved data" from a previous execution, then the remaining data # for a previous record must be 0. This is because we only save data when # trying to retrieve the whole header (at the start of a new record). lang.assert( string.length( $buffer ) == 0 || $pos == 0, "Unexpected saved data in the middle of a record" ); lang.assert( string.length( $buffer ) < 5, "Too much data saved across requests" ); # Append the rest of the buffer for consideration. if( rule.getstate() == "RESPONSE" ) { $buffer .= response.get( response.getLength() ); } else { lang.assert( rule.getstate() == "REQUEST", "Invalid context to use this rule" ); $buffer .= request.get( request.getLength() ); } # Check if we have enough data yet to reach the start of a new record. if( string.length( $buffer ) < $pos ) { # not read enough yet, remember how far through we are and try again later. connection.data.set( $remaining_state_name, $pos - string.length( $buffer ) ); # if $pos is positive then saved data state must already be "" by assertion. break; # exit the rule } # We have a new record to process in this rule execution, isolate the new # data for inspection as the beginning of a new record. $unchecked = string.skip( $buffer, $pos ); # Start with fresh state for the parsing loop. $remaining = 0; $saved = ""; while( string.length( $unchecked ) > 0 ) { # Check we have enough data to extract the header details (5 bytes). if( string.length( $unchecked ) < 5 ) { # Not enough data to extract a header, save what data we have # for the next execution of the rule. $saved = $unchecked; break; } # We have a full header; extract the header details. $type = lang.ord( string.left( $unchecked, 1 ) ); $length = ( lang.ord( string.substring( $unchecked, 3, 3 ) ) << 8 ) | lang.ord( string.substring( $unchecked, 4, 4 ) ); # Check if the record is OK, and deal with if it isn't. if( $type == 24 && $length > $threshold ) { action_to_take_on_detection( $length ); } # Find the start point of the next record. $rec_len = 5 + $length; if( string.length( $unchecked ) > $rec_len ) { # Still have some data left to process in this rule, go around again. $unchecked = string.skip( $unchecked, $rec_len ); } else { # The current record fits neatly into or extends beyond this buffer. # Store how much data needs to be read (if any) beyond what we already # have. $remaining = $rec_len - string.length( $unchecked ); break; } } connection.data.set( $remaining_state_name, $remaining ); connection.data.set( $saved_state_name, $saved ); sub ip_and_port_to_string( $ip, $port ) { $ipversion = string.validIPAddress( $ip ); if( 6 == $ipversion ) { return "[" . $ip . "]:" . $port; } else { return $ip . ":" . $port; } }   Recommendations   The best use of this rule depends on a number of factors specific to your deployment.  Below we've included some high level guidance. Use this as a request rule with threshold of zero; if you are concerned about vulnerable servers behind your STM deployment and you know heartbeat messages are not used by valid users. Use this as a response rule with a threshold of zero; if you want to protect clients in front of your STM deployment. You can use as both a request and response rule, each with differing actions, for example: Detecting and logging all heartbeat messages from clients. Terminating the connection if a large heartbeat message is seen in a response from a server (as an attempt to only prevent invalid heartbeat. If you have a significant amount of RAM available in your STM machines you may find the simple rule presented at the beginning of the article provides improved performance under certain traffic loads.
View full article
This Document provides step by step instructions on how to set up Pulse Virtual Traffic Manager for Microsoft Exchange 2016   Note that this deployment guide is out of date, and expected to be updated soon.   
View full article
This Document provides step by step instructions on how to set up Brocade Virtual Traffic Manager for Microsoft Exchange 2010.
View full article
I have zipped up some icons and Visio stencils that our technical teams use when they are creating diagrams. I have included different formats, including solid and sketch styles:   Attached three files: brocade-vadc-product-icons.zip - PNG files brocade-vadc-visio-stencils-1.zip - Visio files brocade-vadc-visio-stencils-2.zip - Visio files        
View full article