Forum Discussion
James_Wrubel_48
Nimbostratus
Jun 27, 2009forware only http payload to pool
Hi all,
I've got a requirement to tunnel a TCP-based application over HTTP. We control the data the client sends, so I had intended to put the node and port in custom http headers and the data that the application should process in the HTTP payload. From what I can tell, if I do the redirection in an HTTP profile the data passed to the remote application will still be wrapped as HTTP; I can remove the headers but that's about it. What I would like to do is forward the HTTP payload as TCP payload. From a strategy perspective I'm evaluating the following options:
1) Use only a TCP profile and set up my own iRule string processing on the TCP payload to replicate the HTTP profile commands. Years of programming have taught me that if you are writing code someone else has already built, you're wasting your time, so I'd prefer to avoid this though I figure I could get it to work.
2) Use the HTTP::disable command in some way to disable HTTP processing. From testing it appears that forwarding even after the HTTP::disable command still sends the full HTTP data, and HTTP::disable discard sets up the handshake but sends no data to the server. Could I use a split command on the full payload including HTTP headers after the HTTP profile is disabled and send the data that way? I'm having trouble getting that syntax correct if it's even possible.
3) Use the virtual command to forward the traffic to a VIP without an HTTP profile after I've done some basic processing. This might work in conjunction with the above two and make it easier to find the split points I'd need.
Any thoughts on the above? Has anyone ever implemented variants on these, and are any of the options clearly better or worse than others?
Jim
- hoolio
Cirrostratus
Hi Jim, - James_Wrubel_48
Nimbostratus
Aaron - Thanks for the pointer. I am now working on a conceptual model that sets up some global variables in RULE_INIT, uses HTTP_REQUEST to parse the HTTP headers, and CLIENT_DATA to actually manipulate the stream and execute routing. So the general plan is to have a global variable to hold the HTTP payload, one to hold the remote host and one for the remote port. Lastly one global binary variable to set when the entire HTTP payload is read in. So the HTTP_REQUEST reads the content-length header to and sets the _collected flag when the entire HTTP payload is collected. At that point we stuff the HTTP payload and parsed in a global variable. The CLIENT_DATA rule calls TCP::Collect until the _collected flag is true, replaced the TCP Payload with the collected HTTP payload, calls use node with the host and port, and releases the TCP stream. It works on the whiteboard at least. If you see a small mushroom cloud near Pittsburgh you'll know it didn't work. If so, we'll fall back to your suggestion of sticking with the TCP commands and parsing on \r\n\r\n. - hoolio
Cirrostratus
I haven't seen any smoke from the direction of Pittsburgh. Have you had any success with either approach? - James_Wrubel_48
Nimbostratus
I got stuck along the way - I couldn't get variables set in HTTP_REQUEST to show up in CLIENT_DATA. I assume that's either because doing the equivalent of a 'wait' statement is not possible or a bad idea, or because the F5 processes the TCP stream before the higher order HTTP. I have put that on the shelf for a while and am doing my own HTTP parsing (sigh) in CLIENT_DATA:Only get the info before the HTTP headers set myURI [getfield $cdata "HTTP" 1] now trim off everything before the ? so we just have the querystring parameters set myQS [getfield $myURI "?" 2] log local0.info "uri = $myURI" log local0.info "qs = $myQS"
- James_Wrubel_48
Nimbostratus
Okay this is mostly working - the thing that is tripping me up I think is just Tcl syntax. I'm parsing the IP address in dotted decimal format (along with the port) and assigning them to variables:foreach val [split $qsVars] { set qsName [getfield $val "=" 1] set qsValue [decode_uri [getfield $val "=" 2]] log local0. "\$val = $qsName, value = $qsValue" switch -glob $qsName { "data" { set decoded_data [decode_uri $qsValue] log local0.info "data = $decoded_data" set vnc_payload $decoded_data } "host" { set decoded_host [decode_uri $qsValue] log local0.info "host = $decoded_host" set remote_host $decoded_host } "\{port" { set decoded_port [decode_uri $qsValue] log local0.info "port = $decoded_port" set remote_port $decoded_port } default { } } }
use node $remote_host $remote_port
- James_Wrubel_48
Nimbostratus
Argh! That was it. For some reason the foreach loop added a space to the end of the host, so the node command barfed. usingset remote_host [string trimright $decoded_host " "]
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects