Forum Discussion

FraserK_151071's avatar
FraserK_151071
Icon for Nimbostratus rankNimbostratus
Jun 02, 2015

iRule catching HTTP_REQUEST made to other Virtual Server

I'm experiencing a problem with apparently conflicting LTM iRules.

I have two Virtual Servers set up (let's name one

VS_TEST
and the other
VS_PREP
). Each has a different iRule applied to it (
iRule_TEST
and
iRule_PREP
). These iRules perform the same function - they intercept incoming HTTP requests, extract some data, and then forward the data to an application running on the corresponding Pool (
POOL_TEST
,
POOL_PREP
) in the form of a
HTTP GET
. The application returns either
Allow
or
Deny
, informing the iRule whether to allow the request to pass through, or to reject it. Each Pool has only one node.

Normally these iRules behave correctly. A request made to

VS_TEST
will be handled by
iRule_TEST
and send information to the application running on the single node in
POOL_TEST
.

There is a second type of request made to the Virtual Servers, let's call these password requests as they retrieve a password that is randomly generated by the server. I need to intercept the response by the sever and extract the password, and then send it to the same application as before. I add

HTTP_RESPONSE
and
HTTP_RESPONSE_DATA
events to the iRules.

However, when I add

HTTP_RESPONSE
and
HTTP_RESPONSE_DATA
events to both iRules, there is a conflict which depends on the order the iRules are updated.

For example, if I update

iRule_TEST
first, followed by
iRule_PREP
:

  1. Requests made to
    VS_TEST
    are handled by
    iRule_TEST
  2. iRule_TEST
    sends the data of the request to the single node in
    POOL_PREP
    !
  3. Requests made to
    VS_PREP
    are handled by
    iRule_PREP
    and the data of the request is sent to the single node in
    POOL_PREP
    , as expected.

How is this possible when both

POOL_TEST
and the IP:port of its corresponding node are explicitly mentioned in
iRule_TEST
? The exact opposite happens if I update
iRule_TEST
first.

iRule_TEST
when RULE_INIT {
     set ip:port of destination node (specific to TEST)
    set static::serveripport "192.168.10.80:80"
}

when HTTP_REQUEST {
    if {([HTTP::query] starts_with "message=")} {
         This is a request we want to intercept
        log local0. "Raw request: [HTTP::query]"

         Extract the actual message
        regexp {(message\=)(.*)} [HTTP::query] -> garbage query

         Connect to node. Use catch to handle errors. Check if return value is not null.
        if {[catch {connect -timeout 1000 -idle 30 -status conn_status $static::serveripport} conn_id] == 0 && $conn_id ne ""} {
             Send TCP payload to application
            set data "GET /Service.svc/checkmessage?message=$query"
            set send_info [send -timeout 1000 -status send_status $conn_id $data]

             Receive reply from application
            set recv_info [recv -timeout 1000 -status recv_status $conn_id]

             Allow or deny request based on application response
            if {$recv_info contains "Allow"} {
                pool POOL_TEST
            } elseif {$recv_info contains "Deny"} {
                reject
            }             
             Tidy up
            close $conn_id
        } else {
            reject
        }
    }
}

 Update below 

when HTTP_RESPONSE {
     Collect all 200 responses
    if {[HTTP::status == 200} {
        set content_length [HTTP::header "Content-Length"]
        HTTP::collect $content_length
    }
}

when HTTP_RESPONSE_DATA {
    if {[catch {binary scan [HTTP::payload] H* payload_hex} error] ne 0} {
        log local0. "Error whilst binary scanning response: $error"
    } else {
        if {some hex string matches} {
             collect password from response and set to $password
             Connect to node. Use catch to handle errors. Check if return value is not null.
        if {[catch {connect -timeout 1000 -idle 30 -status conn_status $static::serveripport} conn_id] == 0 && $conn_id ne ""} {
             Send TCP payload to application
            set data "GET /Service.svc/submitresponse?password=$password"
            set send_info [send -timeout 1000 -status send_status $conn_id $data]

             Tidy up
            close $conn_id
        }
    }
    HTTP::release
}

iRule_PREP
is identical, save for references to
POOL_TEST
and the
static::serveripport
address.

  • set static::serveripport "192.168.10.80:80"

    The above variable is global, static, and is evaluated each time the irule is updated, or whenever tmm starts (See Rule_Init ).

    I hope that you haven't used the same name in both of your irules?

  • BinaryCanary_19's avatar
    BinaryCanary_19
    Historic F5 Account

    set static::serveripport "192.168.10.80:80"

    The above variable is global, static, and is evaluated each time the irule is updated, or whenever tmm starts (See Rule_Init ).

    I hope that you haven't used the same name in both of your irules?

  • BinaryCanary_19's avatar
    BinaryCanary_19
    Historic F5 Account

    set static::serveripport "192.168.10.80:80"

    The above variable is global, static, and is evaluated each time the irule is updated, or whenever tmm starts (See Rule_Init ).

    I hope that you haven't used the same name in both of your irules?