Forum Discussion

Thiyagu's avatar
Thiyagu
Icon for Cirrus rankCirrus
May 10, 2021

Need help to merge the flow of two iRules

Hello All,

We have two iRules for different task and I'm getting LTM operation error when these two irules are associated to the VIP. As a possible solution to fix the issue I'm working to merge the two irules work flow:

 

Irule1: iRule to insert the validate the host header referer value:

IRULE_HTTP_REFERER

   when HTTP_REQUEST {

   set referer_host [string tolower [URI::host [HTTP::header value Referer]]]

   if { [HTTP::header exists "Referer"] } {

       if { [class match $referer_host contains HTTP_REFERER_LIST] }{

       } else {

           HTTP::respond 400 content "Bad Request" Content-Type "text/html"

       }

   }

}

 

iRule2: iRule to insert the source IP address

 

ltm rule IRULE_SOURCEADDR {

when HTTP_REQUEST {

set rd "%[ROUTE::domain]"

set client_ip [string map "$rd \"\"" [IP::client_addr]]

HTTP::header insert srcaddr $client_ip

}

}

 

Could you please suggest some ideas to fix the issue?

 

Regards,

Thiyagu

2 Replies

  • Hi Thiyagu,

     

    From my limited knowledge, I can't find anything clearly wrong with the iRules. Could you post the error message you are getting when you try to attach the iRules to the VS? I've quickly copied them into a test system but don't get any errors.

    Also, if the two iRules don't like being attached to the same virtual server at the same time, it is likely to give the same problem if you merge both rules into one.

  • I ran a test with your two iRules and ran into a situation where a Tcl error occurs during traffic processing if the iRules are both assigned and the invalid referer condition is triggered first. In other words, the iRules are ordered on the virtual server such that IRULE_HTTP_REFERER is first and IRULE_SOURCEADDR is second. If the else condition is triggered in IRULE_HTTP_REFERER (indicating an invalid referer), the system responds, as instructed, with a 400 Bad Request. However, the second iRule is triggered afterwards for the same HTTP_REQUEST event, and it tries to insert an HTTP header into the server-side request. Unfortunately, the system has already responded to client so such a request is invalid in that context. I get the following log message:

    May 11 13:26:07 bigip4 err tmm1[9908]: 01220001:3: TCL error: /Common/test_devcentral_irule2 <HTTP_REQUEST> - ERR_NOT_SUPPORTED (line 1)     invoked from within "HTTP::header insert srcaddr $client_ip"

    If you need to keep both iRules separate, one solution is to include an event disable instruction after the HTTP::respond command in IRULE_HTTP_REFERER so that the HTTP_REQUEST event in the second iRule, IRULE_SRCADDR, is not triggered. For example:

    when HTTP_REQUEST {
       set referer_host [string tolower [URI::host [HTTP::header value Referer]]]
       if { [HTTP::header exists "Referer"] } {
           if { [class match $referer_host contains valid_referer_datagroup] }{
           } else {
               HTTP::respond 400 content "Bad Request" Content-Type "text/html"
               event disable
           }
       }
    }

    As an alternative, you can reorder the iRules on your virtual server such that IRULE_SRCADDR is first and IRULE_HTTP_REFERER is second. However, that results in unnecessary overhead for invalid referers as the header insert will occur before the check for a valid referer. (Nothing will be sent to the server, but the command will execute unnecessarily.)

    The ideal solution is to combine both iRules into one and simplify your logic, if you can. Perhaps something like this. (I eliminated the variables which are not necessary.):

    when HTTP_REQUEST {
        set referer_host [string tolower [URI::host [HTTP::header value Referer]]]
        if { [HTTP::header exists "Referer"] } {
            if { [class match [string tolower [URI::host [HTTP::header value Referer]]] contains valid_referer_datagroup] } {
               HTTP::header insert srcaddr "%[ROUTE::domain]/[IP::client_addr]"
           } else {
               HTTP::respond 400 content "Bad Request" Content-Type "text/html"
           }
       }
    }