on
18-Aug-2011
16:43
- edited on
05-Jun-2023
23:07
by
JimmyPackets
With the release of BIG-IP version 11 there are many, many new features and capabilities to come up to sped on. Not the least of which are the additions and changes to the already powerful iRules infrastructure. iRules, as a whole, is an amazingly powerful, flexible technology. We've seen it used for thousands of things over the years, and it has solved problems that many people thought were beyond fixing. That being said, there are some new tricks being added that will, simply put, blow you away. One such feature is the concept of a sideband connection. This is one of the most exciting features in the entire v11 release for those of us that are true iRules zealots out there, as it's something that we've been asking to have for years now, and adds tremendous power to the already vast iRules toolbox. So what is a sideband connection you ask? Think of a sideband connection as a way to access the world outside of an iRule. With this functionality you can create a connection (TCP or UDP) to any outside resource you choose, send a custom formatted request, await a response if applicable, act on that response, etc. The sky is really the limit. If you've done any kind of socket programming this should start sounding pretty familiar. The concept is very similar, open, send, receive, process. By allowing you to reach out to surrounding applications, APIs, servers and even, if you're tricky enough, databases...the possibilities of what you can do within your iRule open up considerably. Curious what permissions someone is supposed to have but they're stored in your LDAP system? No problem. Want to query that custom HTTP based API with some information about the current connection before deciding where to load balance to? Sure, you can do that. So how does it work? What does it look like? Well, the commands are pretty simple, actually. In this article I'll briefly cover the four main commands that allow you to establish, communicate via, and manipulate sideband connections within iRules.
First is the connect command, which is the command used to initiate the connection for use. This is what reaches out, does whatever handshaking necessary and actually establishes the connection with whatever remote server you'll be interacting with. The connect command looks like this:
connect [-protocol TCP|UDP] [-myport <port>] [-myaddr <addr>] [-tos <tos>] [-status <varname>] [-idle <s>] [-timeout <ms>] <destination>
As you can see, there are a lot of options, but the structure itself is pretty logical. You're calling the connect command, obviously, and specifying how you want to connect (TCP vs UDP), where you're connecting to (IP & Port), and then giving some basic information about that connection, namely timeout, idle time, etc. Now that you have an established connection, you're probably going to want to send some data through it. When you're initiating the connection you'll normally also specify a variable that represents the resulting handle for later use. This looks like:
set conn [connect -timeout 3000 -idle 30 -status conn_status vs_test] log local0. "Connect returns: <$conn> and conn status: <$conn_status>"
The above will give you a variable named "$conn" that you can then pass traffic to, assuming the connection was initiated successfully. Once things are up and running and your variable is set you can make use of the send command to pass traffic to your new connection. Keep in mind that you're going to be sending raw data, which will require whatever protocol specific formatting may be necessary for whatever it is you're trying to send. Below you'll see the simple HTTP GET request we'll be sending, stored in the variable "$data" to keep things obvious, as well as the send command that is used to send that data through the connection we opened above. Note that the send command also allows you to specify a variable to contain the status of the send so that you can later verify that the send went through properly.
set data "GET /mypage/myindex2.html HTTP/1.0\r\n\r\n" set send_info [send -timeout 3000 -status send_status $conn $data]
Now that you have a functioning connection and are sending data through it to some remote host, you're likely curious what that host is saying in response, I would imagine. There is a command for that too, naturally. With the recv command you're able to consume the data that is being returned from your open connection. There are also sub-commands like -peek and -eol. I'll get into more detail about these later, but here's the short version: The -peek flag allows you to instantly return any received data without unbuffering, to allow you to inspect a portion of the data before the recv command has completed collecting the response. The -eol command looks for an end-of-line character before terminating the recv. A basic recv looks like this, storing the data in a new variable:
set recv_data [recv -timeout 3000 -status recv_status 393 $conn]
At this point you'll be able to inspect whatever data was returned by parsing the $recv_data variable (though this variable name is up to you). Now that you've initiated a connection, sent data to it, and collected the response, the only thing left to do, unless you want to repeat the send/recv of course, is to close the connection. That is done quite simply with close command. No arguments or tricks here, just a simple termination of the connection:
close $conn
If you put it all together, a simple example iRule would look something like this:
when HTTP_REQUEST { set conn [connect -timeout 3000 -idle 30 -status conn_status vs_test] log local0. "Connect returns: <$conn> and conn status: <$conn_status> " set conn_info [connect info -idle -status $conn] log local0. "Connect info: <$conn_info>" set data "GET /mypage/myindex2.html HTTP/1.0\r\n\r\n" set send_info [send -timeout 3000 -status send_status $conn $data] log local0. "Sent <$send_info> bytes and send status: <$send_status>" # This magically knows that we’re getting 393 bytes back set recv_data [recv -timeout 3000 -status recv_status 393 $conn] log local0. "Recv data: <$recv_data> and recv status: <$recv_status>" close $conn log local0. "Closed; conn info: <[connect info -status $conn]>" }
So there you have it, a simple intro to how you can manipulate sideband connections via iRules. Keep in mind that the devil is, of course, in the details and it will take some practice to harness the power of these new commands, but the power is most definitely there for the taking.
Feel free to ask any questions either here or in the iRules Q&A and also keep your eye on the wiki for the official command pages for the new v11 commands which will be coming soon.
Ideally, return value of connect should always be validated before used.
set conn [connect -timeout 3000 -idle 30 -status conn_status vs_test]
if { $conn == "" } {
log local0. "connect timed out; unable to continue"
return
}
I added a codeshare example which handles the response size for HTTP sideband responses more gracefully than hardcoding the value:
http://devcentral.f5.com/wiki/iRules.Sideband-connection-HTTP-example.ashx
It's a work in progress...
Aaron
Any time I try to use a virtual server (VS) I can't get things to work.
set conn [connect -timeout 2000 -idle 30 -status conn_status vs_main_icdb
But if I use a IP:port from one of the pool members in the 'connect' everything seems to work.
set conn [connect -timeout 2000 -idle 30 -status conn_status 192.168.3.100:1798 ]
any thought on what I might be doing wrong? I drives me crazy that I have to 'write' my
own load round-robin balancer looking a all members in a poop, testing the 'up' status and
then selecting one of them.
--
BTW there is a 275 byte leak on each sideband request case C1200124 any one else
seen this.
Jon
I noticed same think.
When I open connection with
set lookupcon [connect -timeout 1000 -status lookupcstatus fmi-apikey-lookup-sideband]
data sent with
set send_bytes [send -timeout 300 -status send_status $lookupcon "$apikey" ]
does not have received. When i open it with
set static::fmiapikeylookup "192.168.6.14:8006"
set lookupcon [connect -timeout 1000 -status lookupcstatus $static::fmiapikeylookup]
data is received. And $lookupcstatus claims "connected" on both cases. And $send_status is "sent" on both cases.
set lookupcon [connect -timeout 1000 -status lookupcstatus fmi-apikey-lookup-sideband]"
This was fixed with
modify fmi-apikey-lookup-sideband snat automap
/ Kari Hurtta
I would like to know if it possiable in the 'connect' command to write FQDN as the destination for example :
set conn [connect -timeout 3000 -idle 30 -status conn_statusa.b.c.com]
as long there is a resolving to the FQDN by dns or /etc/hosts.
There are sites that are configured to accept hostname rather then ip address.
Regards,
Yossi
set server_ip [RESOLV::lookup @8.8.8.8 -a "my.serverip.com"]
set conn [connect -timeout 3000 -idle 30 -status conn_status $server_ip]
I hit that same issue my first time. What I realized was happening was that if I made the request to a virtual server the side band connection would pass my browsers original request instead of the request I crafted.
It turns out that if the virtual server in question has snat automap enabled it will pass the request I formatted instead of the original request.