For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

Russell_E_Glaue's avatar
Russell_E_Glaue
Icon for Nimbostratus rankNimbostratus
Feb 18, 2009

How to disable iRule processing on keep-alive per request when using HTTP::respond

How to disable iRule processing on keep-alive per request when using HTTP::respond

 

 

 

Okay, I have encountered a problem I cannot figure out how to get around.

 

 

Here is what I want to do:

 

1) First of all I want to keep the keep-alive connection open - I do not want to close it.

 

2) The web user connects to the IP for a web site and sends a request

 

3) the iRule catches something in the request, and send back a response via "HTTP::respond"

 

4) the iRule execute "event HTTP_REQUEST disable" to stop further iRule processing (important) of HTTP_REQUEST.

 

5) the keep-alive connection remains open

 

6) some how the iRule processing is enabled again for the HTTP_REQUEST event.

 

7) on the next web user's http request, the same iRule(s) is processed.

 

 

How do I do this?

 

 

*) I do not see how 6 can be possible, while keeping the keep-alive connection open, from everything I have read about how iRules work.

 

When we use HTTP::respond, the HTTP_RESPONSE event is never processed in the iRules (which is where it has been recommended to execute the "event enable" command), plus I do not see any other events being processed.

 

 

My question may be, how can I reenable the HTTP_REQUEST event for the next request on the same keep-alive connection?

 

But perhaps it should be, how do I turn off iRule processing on a per-request basis when using HTTP::respond?

 

 

My goal is to:

 

1) use the HTTP::respond - immediately returning the response to the web user

 

2) keep the keep-alive connection open

 

3) do not process any further iRules

 

4) allow the web user to send another request on the same keep-alive connection.

 

5) have the iRules process the new request coming across the same keep-alive connection from the web user.

 

6) be able to go back to 1 and continue this loop indefinitely.

 

 

What does NOT work:

 

1) the "return" command - it returns, but further iRules are still processed.

 

2) the "event disable" command - it disables iRules for any future events on the same keep-alive connection, and if you use HTTP::respond, then you have no opportunity to execute "event enable" at the end of the request so iRules will process the next request.

 

3) the "reject", "TCP::close", or other commands that close the keep-alive connection - I do not want to close the connection.

 

4) using global variables as flags for determining it further iRules should be processed - according to this article ( http://devcentral.f5.com/Default.aspx?tabid=63&articleType=ArticleView&articleId=236 ) "a global variable ... [is] shared by all connections"

 

 

Would anyone know what I can do to resolve this?

 

 

-RG

18 Replies

  • spark_86682's avatar
    spark_86682
    Historic F5 Account
    The only other thing I can think of that even remotely has a chance of working is to add an HTTP class that matches every request, run "event disable" in HTTP_REQUEST like you were doing before, and then re-enable HTTP_REQUEST (via "event enable") in the

     

    HTTP_CLASS_SELECTED event. I can't test this right now, but it just might work.
  • I have an open case already.

     

    C498394

     

    The support guy is fantastic!

     

    He hinted I try over here for a possible solution first.

     

    Now I am back at the case trying to write out a feature request.

     

     

     

    Can someone tell me how the iRule events are execute during a connection? Yes, I thought about what spark is suggesting, but I did not know if there was an event fired in between each HTTP_REQUEST event on the same connection.

     

     

    So what is the firing order of events?

     

     

    CLIENT_CONNECT

     

    HTTP_REQUEST

     

    HTTP_RESPONSE (ONLY if the response comes from a node)

     

    HTTP_REQUEST

     

    HTTP_REQUEST

     

    ... etc..

     

     

    Is there an event in between successive HTTP_REQUEST events?

     

     

    If there is, then my problem is easily solvable by disabling the event in HTTP_REQUEST, and reenabling the HTTP_REQUEST event inside the execution of another in between event.

     

     

    I would not have a problem right now if using HTTP::respond also caused the execution of HTTP_RESPONSE event - because I could then just reenable the HTTP_REQUEST event inside the HTTP_RESPONSE event when sending the response back to the client.

     

     

    -RG

     

  • Okay, I submitted my feature request.

     

     

    Here is my proposed changes:

     

     

    I want to change the syntax for the "event" command.

     

     

    Currently syntax is:

     

     
     event [] [enable|disable] | [enable all|disable all] 
     

     

     

    I propose that the new syntax would be:

     

     
     event [] [enable|disable|end] | [enable all|disable all|end all] 
     

     

     

    And basically, this will change the following scenario:

     

     

    Current procedure for disabling an event for a single request:

     

    1) CLIENT_CONNECT

     

    2) HTTP_REQUEST event HTTP_REQUEST disable

     

    3) HTTP_RESPONSE event HTTP_REQUEST enable

     

    4) HTTP_REQUEST

     

    5) HTTP_RESPONSE

     

    6)

     

     

    New procedure to get the same exact results:

     

    1) CLIENT_CONNECT

     

    2) HTTP_REQUEST event HTTP_REQUEST end

     

    3) HTTP_RESPONSE

     

    4) HTTP_REQUEST

     

    5) HTTP_RESPONSE

     

    6)

     

     

    This is useful for functions like HTTP::respond which causes the BigIP to send a response back to the web client, but the HTTP_RESPOSE event is not being executed.

     

     

    Also useful for HTTP::redirect

     

     

     
     rule redirect { 
         when HTTP_REQUEST { 
             if { [HTTP::host] equals "yoursite.com" } { 
                 HTTP::redirect http://mysite.com/ 
                 event end 
                 return 
             } 
             elseif { HTTP::host equals "thatsite.com" } { 
                 HTTP::response 200 content { 
                      
                      
                     We have moved to a new domain. 
                      
                 } noserver 
                 event end 
                 return 
             } 
      
             pool mysite.com_pool 
         } 
     } 
     

     

     

    In the above code (assuming yoursite.com, thissite.com and mysite.com all resolve to the same IP number for the web browser) the keep-alive connection does not have to end in order to get sent to the mysite.com web site from one of the other URLs.

     

     

    Of course this is a primitive example, this is best used in cases that have more advanced and complex uses that require the keep-alive connection to remain open.

     

     

    -RG

     

  • spark_86682's avatar
    spark_86682
    Historic F5 Account
    Two things. First, I got this working using HTTP classes, but it was slightly different than I thought. My idea was also to get another event firing between two HTTP_REQUEST events, but there aren't any that occur naturally, so you have to induce one. There are a couple choices, like the NAME or AUTH stuff, but HTTP_CLASS_SELECTED sounded easiest. The problem is that if you do an HTTP::respond in HTTP_REQUEST, then HTTP_CLASS_SELECTED never fires. But you can do:

      
     rule rule_one {  
       when HTTP_REQUEST {  
         set do_response 0  
         set condition 1   
      
         if { $condition } {  
           log local0. "Rule one, enabling response"  
           set do_response 1  
           event HTTP_REQUEST disable  
         }  
       }  
     }  
     rule rule_two {  
       when HTTP_REQUEST {  
         log local0. "Rule two, firing HTTP_REQUEST"  
       }  
     }  
     rule rule_respond {  
       when HTTP_CLASS_SELECTED {  
         log local0. "Got class match!"  
         if { $do_response } {  
           HTTP::respond 200 content { xyzabc123 }  
           event HTTP_REQUEST enable  
         }  
       }  
     } 
     virtual http_vip { 
        pool http_pool 
        destination 10.1.1.1:http 
        ip protocol tcp 
        rules { 
           rule_one 
           rule_two 
           rule_respond 
        } 
        httpclass httpclass 
        profiles { 
           http {} 
           tcp {} 
        } 
     } 
      
     

    In my tests, this will do the HTTP::respond and keep the connection open and the HTTP_REQUEST in rule_two will never fire. Obviously, you'll want something more complicated than "set condition 1" ;-).

    On another note, while I understand "event [foo] end", and quite like the idea, what are you suggesting "event [foo] end all" to do? Skip all events for the remainder of the connection? Please keep in mind that "event" is a very general command that needs to apply to all the protocols that BIG-IP does or will handle, and is not limited to request/response protocols like HTTP, so "skip all events for the remainder of this request" is probably an unuseful concept.
  • On another note, while I understand "event [foo] end", and quite like the idea, what are you suggesting "event [foo] end all" to do? Skip all events for the remainder of the connection? Please keep in mind that "event" is a very general command that needs to apply to all the protocols that BIG-IP does or will handle, and is not limited to request/response protocols like HTTP, so "skip all events for the remainder of this request" is probably an unuseful concept.

    I do not know the order of events for a request/connection, or what they are named, but bear with me while I give this example:

    Say the events are this for the life of a connection and all requests on that connection:

    01) CLIENT_CONNECT

    02) CONNECTION_HANDSHAKE

    03) EVENT_SOMETHING

    04) HTTP_REQUEST

    05) HTTP_RESPONSE

    06) EVENT_BACKGROUND

    07) EVENT_SOMETHING

    08) HTTP_REQUEST

    09) HTTP_RESPONSE

    10) EVENT_BACKGROUND

    11) CLIENT_DISCONNECT

    If this would be the EXACT sequence of events, then issuing "event end all" would cause all events to end for one round of firing.

    So if you issued "event end all" at event number 4 (HTTP_REQUEST), then event number 4,5,6,7 would all end immediately, and the cycle would continue at event number 8.

    So in effect, you might do:

     
       HTTP::redirect http://www.mysite.com/ 
       event end all 
       return 
     

    Which keeps the keep-alive connection, and sets the next event to be HTTP_REQUEST again - or in other words jumps over the other events back to waiting for the client to provide an HTTP_REQUEST event.

    Take for example the same events, but the client aborts the connection after getting a HTTP::redirect :

    01) CLIENT_CONNECT

    02) CONNECTION_HANDSHAKE

    03) EVENT_SOMETHING

    04) HTTP_REQUEST

    05) HTTP_RESPONSE

    06) EVENT_BACKGROUND

    07) EVENT_SOMETHING

    08) HTTP_REQUEST

    ... client aborts connection ...

    11) CLIENT_DISCONNECT

    This is how it might normally progress.

    But if you know that the events EVENT_BACKGROUND and EVENT_SOMETHING are going to be executed and you don't want those events to be executed, you would need to tell the BigIP to complete this request cycle and begin at the next request cycle.

    Perhaps this is not desired, or something.

    Like I said, I do not know the events in between successive HTTP_REQUEST events.

    But if there ARE in between events, and you want to skip through these cycle of other events that might otherwise get fired before the next HTTP_REQUEST event, then you essentially want to "even end all".

    Or in other words, if I issue "event end all" in the HTTP_REQUEST event, then end every successive event until I get back to this same HTTP_REQUEST event again.

    Probably "event end all" would be reserved to experts who know what they are doing.

    -RG

  • The ability to perform "event end" is all I need.

     

    I do not need "event end all".

     

     

    -RG

     

  • Has this change request been created for Big IP version 9.x? If so, please let us know how the specific event can be disabled.

     

  • What would happen if we perform a drop command on the irule that is performing the HTTP::respond? Basically we have a way of filtering out a set of IPs and want to prevent further execution of irules in the stack if the ips matches any one of them in the blacklisted ones mentioned in a data group.