Forum Discussion

MW1's avatar
MW1
Icon for Cirrus rankCirrus
Jan 23, 2020

Class match does not appear to work how I expected with contains

All,

I am trying to write an irule that essentially matches a http header value and checks the allowed IPs which can send it. I have created a datagroup called headers (string type as address type does not allow multiple rows with the same IP address), where I hoped to be able to put mutliple header values with a separator as the string and the ip address/range as the value (e.g. header values are dave and matt) - below is an example record in the headers datagroup:

 

SSSdaveSSSmattSSS:= 10.10.10.5

 

I was expecting I could do a " class match -value SSSdaveSSS contains headers" however this fails to find a match, however if I change the string in the datagroup to be just "SSSdaveSSS" it matches, and appears to act the same as equals.

 

Can anyone advise how "contains" works when checking a string in datagroup and/or if there is a way to do a partial match on the string value in the datagroup?

  • Hi

    Then you can :

    - Create a data group "string" with header name as key, and IP / IP RANGE as values

    header1 := 10.10.10.0/24|10.10.20.0/24|10.50.1.1

    Get the header

    Check if header in datagroup, and if not, allow (header not filtered)

    If header in datagroup, get allowed IPs and range in list

    Loop through each IP /range and check if source is included there.

    And make a decision.

     
    set allowedips [split [class match -value $hdrtocheck equals ttt] "|"]
    log local0. "$allowedips"
    set allowed 0
     
    if { ! ($allowedips equals "") } {  
        foreach ip $allowedips {
            if {[IP::addr $srcip equals $ip ]}{
                incr allowed
            }
        }
     
        if { $allowed > 0 } {
                log local0. "$srcip allowed"
        } else {
        
                log local0. "$srcip denied"   
            }
            
    } else {
        log local0. "not checked"
     
    }
     
  • Hi

    Then you can :

    - Create a data group "string" with header name as key, and IP / IP RANGE as values

    header1 := 10.10.10.0/24|10.10.20.0/24|10.50.1.1

    Get the header

    Check if header in datagroup, and if not, allow (header not filtered)

    If header in datagroup, get allowed IPs and range in list

    Loop through each IP /range and check if source is included there.

    And make a decision.

     
    set allowedips [split [class match -value $hdrtocheck equals ttt] "|"]
    log local0. "$allowedips"
    set allowed 0
     
    if { ! ($allowedips equals "") } {  
        foreach ip $allowedips {
            if {[IP::addr $srcip equals $ip ]}{
                incr allowed
            }
        }
     
        if { $allowed > 0 } {
                log local0. "$srcip allowed"
        } else {
        
                log local0. "$srcip denied"   
            }
            
    } else {
        log local0. "not checked"
     
    }
     
  • Hi

    class match -value SSSdaveSSS will return "10.10.10.5" that is, the value of the name/value pair.

    Depending on what you are trying to create a datagroug of type address, then insert name value pair, like this :

    10.10.10.0/24 := header1|header2|header3|header4

    then use

    if { [class match -value $srcIP equals DGallowedheader] contains $headertocheck } {
     
    log local0. "allowed"
     
    } else {
     
    log local0. "denied
     
    }

    This approach also allows you to use netork range in your datagroup.

    Yoann

    • MW1's avatar
      MW1
      Icon for Cirrus rankCirrus

      apologies meant to hit reply rather than submit as a different answer

  • Thanks for the above. I have to admit I hadnt thought of nesting the class match and then contains in one.

     

    On my original code with the string type it doesnt return a match on the contains SSSdaveSSS (running 12.1.3 I had logging in the irule and verified it did not match but if I put a record with a plain SSSdaveSSS underneath a record for SSSdaveSSSmattSSS, or removed the original record it did match ). I'll look to see if I can use the address type.

     

    Unfortunately though I need to check the header value first as this is the element that decides if it should be restricted. I can create a 2nd datagroup with just the list of header values to check first (so it knows it should existing the other datagroup as a value), but was trying to reduce any duplication.

     

    Logic trying to implement

    1) request comes in check header value to see if it is a restricted header that can only be sent from specified IPs -- otherwise let request route on.

    2) If header matches check if client IP is on the "allowed list", if not return block msg, if matches lsit let request route on.

     

    The issue is there could be multiple IP addresses allowed to send multiple headers.

    thanks