Technical Forum
Ask questions. Discover Answers.
cancel
Showing results for 
Search instead for 
Did you mean: 
Custom Alert Banner

iRule operator evaluation order OR/AND

alex100
Cirrostratus
Cirrostratus

Hi all, 

This must be some simple syntax problem but I have been bashing my head for a while. Here is the irule:

 

 

when HTTP_REQUEST {
    if {(![class match [getfield [IP::client_addr] "%" 1] eq tcp_whitelist]) or (![class match [getfield [HTTP::header X-Forwarded-For] "%" 1] equals xff_whitelist]) and ([class match [string tolower [HTTP::uri]] contains uripath_a])}
        {
            
            log local0. "## Batman Client IP [IP::client_addr], Client XXF IP [HTTP::header X-Forwarded-For],  [HTTP::method], URL: [HTTP::host][HTTP::uri]"
        } else {
          
         pool pl-something-WEB-443
        #log local0. "## Robin Client IP [IP::client_addr], Client XXF IP [HTTP::header X-Forwarded-For],  [HTTP::method], URL: [HTTP::host][HTTP::uri]"
        }
        
    }

 

 

Here is some additional info. I have two data groups containing XFF src IPs and another group with TCP IP  as well as a datagroup with list of URI paths. So the idea is that we evaluated where http request is NOT comming from the IP address neither on xff_whitelist nor tcp_whitelist dg and also that URI path is matching one in uripath_a dg. I am having problems figuring out proper syntax to evaluate or operator before evaluating and operator. 

I have tried wrapping or statemnts in additional clause but that does not seem to work. I think I am doing it wrong. 

 

 

{((![class match [getfield [IP::client_addr] "%" 1] eq tcp_whitelist]) or (![class match [getfield [HTTP::header X-Forwarded-For] "%" 1] equals xff_whitelist])) and ([class match [string tolower [HTTP::uri]] contains uripath_a])}

 

 

Any help and advice is greatly appreceated. 

1 ACCEPTED SOLUTION

Hi alex100,

It might be better to think in parts.

when HTTP_REQUEST {
    #if uri matches with uripath_a:
    if { [class match [string tolower [HTTP::uri]] contains /Common/uripath_a] } {
        #log local0. "Log1 - Uri matched [HTTP::host][HTTP::uri]"
        
        #if Client IP doesn't match with tcp_whitelist
        if { !([class match [getfield [IP::client_addr] "%" 1] eq /Common/tcp_whitelist]) }
            #log local0. "Log2 - Uri matched [HTTP::host][HTTP::uri] | Client IP did not match [IP::client_addr]"
            
            #if XFF doesn't match with xff_whitelist
            if { !([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist]) }
                #log local0. "Log3 - Uri matched [HTTP::host][HTTP::uri] | Client IP did not match [IP::client_addr] | XFF did not match [HTTP::header X-Forwarded-For]"
            }
            #if Client IP doesn't match with tcp_whitelist and XFF matches with xff_whitelist
            else {
                #log local0. "Log4 - Uri matched [HTTP::host][HTTP::uri] | Client IP did not match [IP::client_addr] | XFF matched [HTTP::header X-Forwarded-For]"
            }
        #if Client IP matches with tcp_whitelist
        else {
            #log local0. "Log5 - Uri matched [HTTP::host][HTTP::uri] | Client IP matched [IP::client_addr]"
            
            #if XFF doesn't match with xff_whitelist
            if { !([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist]) }
                #log local0. "Log6 - Uri matched [HTTP::host][HTTP::uri] | Client IP matched [IP::client_addr] | XFF did not match [HTTP::header X-Forwarded-For]"
            }
            #if Client IP matches with tcp_whitelist and XFF matches with xff_whitelist
            else {
                #log local0. "Log7 - Uri matched [HTTP::host][HTTP::uri] | Client IP matched [IP::client_addr] | XFF matched [HTTP::header X-Forwarded-For]"
            }
        }
    }
    #if uri doesn't match with uripath_a
    else {
        #log local0. "Log8 - Uri did not match [HTTP::host][HTTP::uri]"
    }
}

I think you want this condition:

when HTTP_REQUEST {
    if { !([class match [getfield [IP::client_addr] "%" 1] eq /Common/tcp_whitelist]) and !([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist]) and ([class match [string tolower [HTTP::uri]] contains /Common/uripath_a]) }
        # log local0. "Batman Client IP [IP::client_addr], Client XXF IP [HTTP::header X-Forwarded-For], [HTTP::method], URL: [HTTP::host][HTTP::uri]"
    }
    else {
        pool pl-something-WEB-443
    }
}

some function with different operators:

when HTTP_REQUEST {
    if { !(([class match [getfield [IP::client_addr] "%" 1] eq /Common/tcp_whitelist]) or ([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist])) and ([class match [string tolower [HTTP::uri]] contains /Common/uripath_a]) }
        # log local0. "Batman Client IP [IP::client_addr], Client XXF IP [HTTP::header X-Forwarded-For], [HTTP::method], URL: [HTTP::host][HTTP::uri]"
    }
    else {
        pool pl-something-WEB-443
    }
}

View solution in original post

2 REPLIES 2

Hi alex100,

It might be better to think in parts.

when HTTP_REQUEST {
    #if uri matches with uripath_a:
    if { [class match [string tolower [HTTP::uri]] contains /Common/uripath_a] } {
        #log local0. "Log1 - Uri matched [HTTP::host][HTTP::uri]"
        
        #if Client IP doesn't match with tcp_whitelist
        if { !([class match [getfield [IP::client_addr] "%" 1] eq /Common/tcp_whitelist]) }
            #log local0. "Log2 - Uri matched [HTTP::host][HTTP::uri] | Client IP did not match [IP::client_addr]"
            
            #if XFF doesn't match with xff_whitelist
            if { !([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist]) }
                #log local0. "Log3 - Uri matched [HTTP::host][HTTP::uri] | Client IP did not match [IP::client_addr] | XFF did not match [HTTP::header X-Forwarded-For]"
            }
            #if Client IP doesn't match with tcp_whitelist and XFF matches with xff_whitelist
            else {
                #log local0. "Log4 - Uri matched [HTTP::host][HTTP::uri] | Client IP did not match [IP::client_addr] | XFF matched [HTTP::header X-Forwarded-For]"
            }
        #if Client IP matches with tcp_whitelist
        else {
            #log local0. "Log5 - Uri matched [HTTP::host][HTTP::uri] | Client IP matched [IP::client_addr]"
            
            #if XFF doesn't match with xff_whitelist
            if { !([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist]) }
                #log local0. "Log6 - Uri matched [HTTP::host][HTTP::uri] | Client IP matched [IP::client_addr] | XFF did not match [HTTP::header X-Forwarded-For]"
            }
            #if Client IP matches with tcp_whitelist and XFF matches with xff_whitelist
            else {
                #log local0. "Log7 - Uri matched [HTTP::host][HTTP::uri] | Client IP matched [IP::client_addr] | XFF matched [HTTP::header X-Forwarded-For]"
            }
        }
    }
    #if uri doesn't match with uripath_a
    else {
        #log local0. "Log8 - Uri did not match [HTTP::host][HTTP::uri]"
    }
}

I think you want this condition:

when HTTP_REQUEST {
    if { !([class match [getfield [IP::client_addr] "%" 1] eq /Common/tcp_whitelist]) and !([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist]) and ([class match [string tolower [HTTP::uri]] contains /Common/uripath_a]) }
        # log local0. "Batman Client IP [IP::client_addr], Client XXF IP [HTTP::header X-Forwarded-For], [HTTP::method], URL: [HTTP::host][HTTP::uri]"
    }
    else {
        pool pl-something-WEB-443
    }
}

some function with different operators:

when HTTP_REQUEST {
    if { !(([class match [getfield [IP::client_addr] "%" 1] eq /Common/tcp_whitelist]) or ([class match [getfield [HTTP::header X-Forwarded-For] "%" 1] eq /Common/xff_whitelist])) and ([class match [string tolower [HTTP::uri]] contains /Common/uripath_a]) }
        # log local0. "Batman Client IP [IP::client_addr], Client XXF IP [HTTP::header X-Forwarded-For], [HTTP::method], URL: [HTTP::host][HTTP::uri]"
    }
    else {
        pool pl-something-WEB-443
    }
}

Thank you for your feedback, time and refactored rule. Looks like I was on the right path but the culprit turned out to be about negation sign ["!"] placement. 

Original if statement 

{((![class match [getfield [IP::client_addr] "%" 1] eq tcp_whitelist]) or (![class match [getfield [HTTP::header X-Forwarded-For] "%" 1] equals xff_whitelist])) and ([class match [string tolower [HTTP::uri]] contains uripath_a])}

Re-factored if statement

{ ([class match [string tolower [HTTP::uri]] starts_with uripath_a]) and !(([class match [getfield [IP::client_addr] "%" 1] eq /Common/tcp_whitelist]) or ([class match [HTTP::header X-Forwarded-For] contains /Common/xff_whitelist])) }

Looks like with multiple class mach commands , "!" has to be moved outside of ().