Forum Discussion

ngaze_66812's avatar
ngaze_66812
Icon for Nimbostratus rankNimbostratus
Sep 25, 2012

URI load balancing, rewriting, and security oh my!

What I attempted to do with this first iRule was ensure that only server subnets could connect to a few URI's that would then load balance the traffic out. The second statement was intended to be a "if the criteria isn't matched in the first statement, check against this." That action would be to allow all subnets access to a URI that would have it's URI rewritten and then sent to a pool. Finally, if the incoming request is not matched, I send some HTML informing the user that they aren't permitted to access whatever site they are requesting.

 

 

when HTTP_REQUEST {

 

if {[matchclass [IP::client_addr] equals allowed_networks] }{

 

switch -glob [string tolower [HTTP::host][HTTP::uri]] {

 

"*/uri1" { pool uri1-1234_pool }

 

"*/uri2" { pool uri2-1234_pool }

 

}

 

}

 

elseif {[HTTP::uri] starts_with "/uri3"}{

 

HTTP::uri "/blah/uri3"

 

pool uri3-5678_pool

 

}

 

else {

 

log local0. "[IP::remote_addr] attempted to access [HTTP::uri]"

 

(etc, etc)

 

}

 

}

 

Getting to /uri3 worked all fine and dandy when I tested from my desktop, but if a server within the allowed_networks attempted to go to /uri3, it was receiving a TCP reset. It seems like the logic was matching the IP and then if the requested URI was outside of what is switched, it stops communication rather than continuing down the iRule to match the next item. Is it true that once one condition is met, that command set has to have an outcome otherwise the traffic will be dropped? When I went to a user meetup, I seem to recall the F5 rep talking about the differences between switch and if + elseif being switch sends traffic out once it has a match but an iRule written with if/elseif must parse the whole rule before sending the traffic off.

 

 

I ended up swapping the placement of the two statements and was able to get the expected outcome, it just seems confusing to me why it would stop after the first 'if' when the rest of the iRule had not yet been executed as was expected.

 

As a theoretical scenario, it seems ineffecient to me that you would have to write an iRule like this...

 

when HTTP_REQUEST {

 

if {[matchclass [IP::client_addr] equals network_A] }{

 

switch -glob [string tolower [HTTP::host][HTTP::uri]] {

 

"*/uri1" { pool uri1-1234_pool }

 

"*/uri2" { pool uri2-1234_pool }

 

"*/uri3" { pool uri3-3456_pool }

 

"*/uri4" { pool uri4-3456_pool }

 

}

 

}

 

elseif {[matchclass [IP::client_addr] equals network_B] }{

 

switch -glob [string tolower [HTTP::host][HTTP::uri]] {

 

"*/uri3" { pool uri3-3456_pool }

 

"*/uri4" { pool uri4-3456_pool }

 

}

 

}

 

else {

 

log local0. "[IP::remote_addr] attempted to access [HTTP::uri]"

 

(etc, etc)

 

}

 

}

 

...When you could write it with a few less lines like this:

 

 

when HTTP_REQUEST {

 

if {[matchclass [IP::client_addr] equals network_A_and_B] }{

 

switch -glob [string tolower [HTTP::host][HTTP::uri]] {

 

"*/uri3" { pool uri3-3456_pool }

 

"*/uri4" { pool uri4-3456_pool }

 

}

 

}

 

elseif {[matchclass [IP::client_addr] equals network_A] }{

 

switch -glob [string tolower [HTTP::host][HTTP::uri]] {

 

"*/uri1" { pool uri1-1234_pool }

 

"*/uri2" { pool uri2-1234_pool }

 

}

 

}

 

else {

 

log local0. "[IP::remote_addr] attempted to access [HTTP::uri]"

 

(etc, etc)

 

}

 

}

 

(Assuming what I found to be true, there is no possible way this final iRule would ever work as intended because in it's current form, you could never get to uri1 or 2 from network_A. If you swapped the placement of the statements, then uri3 and 4 would never work because of the same implicit "TCP reset")

 

Edit: Cleaned up iRules, missing a couple brackets.

 

 

4 Replies

  • No, because the first section is limiting access through a matchclass, which in turn is referencing a list of IP subnets.
  • That's doesn't stop you from adding /uri3 to the first section although you'll have to keep that second section for /uri3 also. As I think you have, you could switch the first and second sections around and that should do the trick. To make it slightly more efficient you could also end both sections with a 'return' command to stop further processing of the iRule (if you switch them around) once a match is found.

     

  • Is it true that once one condition is met, that command set has to have an outcome otherwise the traffic will be dropped?

     

    No. Where did you read that? in an iRule does not make any decision about traffic, the virtual server config will decide.

     

     

    I did not give your problem much thought... but why not use "if" instead of "elseif" ?