Forum Discussion

James_Wrubel_48's avatar
James_Wrubel_48
Icon for Nimbostratus rankNimbostratus
Jun 27, 2009

forware 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

6 Replies

  • Hi Jim,

     

     

    Disabling the HTTP filter will not modify the TCP payload in any way. It just stops LTM from parsing the TCP payload as HTTP and logically breaking out the HTTP into headers and a payload. I would guess it might be more efficient to strip the HTTP payload out of the TCP packet. You could look for a \r\n\r\n which should delineate the HTTP headers and payload.

     

     

    I'm not sure whether you could remove the HTTP headers if you've already parsed the request as HTTP.

     

     

    Anyone else have ideas on this?

     

     

    Aaron
  • 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.

     

     

    Jim
  • I haven't seen any smoke from the direction of Pittsburgh. Have you had any success with either approach?

     

     

    Aaron
  • 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" 
     

    There's probably a way to optimize these two queries to run this in one command - I figure I'll get to this later. Now that I have the QS I'm able to parse out on the "=" and use a switch statement to dig in to the individual parameters. Seems to be working so far but I need to put it all together.

    Jim
  • 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 { 
      
     } 
     } 
     } 
      
     

    The variables I'm assigning, $remote_host and $remote_port, are defined globally so I am sure it's not a scope issue. but when I try to do a:

    use node $remote_host $remote_port

    The server-side handshake never fires. I think what is happening is that the node command doesn't like the format of the remote_host variable - if I manually set it to the same exact address that's being parsed above it works fine. Does Tcl have the concept of casting to a strong type? I'm more of an OO programmer so I get tripped up by these kinds of things in other languages. I'm also testing now to see if I have a leading or training space issue.
  • Argh! That was it. For some reason the foreach loop added a space to the end of the host, so the node command barfed. using

    set remote_host [string trimright $decoded_host " "]

    Totally worked. Now for a little regex cleanup and additional error checking, then on to the HTTP response. It is such a good feeling to get an iRule working.