Forum Discussion

Tony2020's avatar
Tony2020
Icon for Nimbostratus rankNimbostratus
Mar 22, 2017

XFF and efficiently group code/iRule

Hi iRule gurus -

 

Was wondering if anyone can help me take and consolidate/put together the three code section efficiently. It seems there are too many "if" section just to do the same function.

 

What is needed is broken down into 3 section. They are as follows.

 

section 1: Validate pool members, and if all are down, redirect to a maintenance page.

 

section 2: validate the IP address in XFF (there are two IP in an XFF, the first is the proxy IP, and the second is the real connecting client IP address. Based on the second IP (which is listed in a data group called "DG_RESTRICTED_URI"), allow access to the URI, also defined in another data group called "DG-XFF-ALLOWED-IP-LIST".

 

Section 3: Does the same as section 2, however this is a little different. Instead of matching the URI in a data group, i want to specify it in the code since there is only one, and based the IP also in an allowed IP data group, redirect/allow to another URI.

 

Here are the code. I have not tested this yet since before we do, we have to move it to an external service that provides proxy (similar to incapsula).

 

Note that the info in the data group was modify and IP 1.1.1.1 and 2.2.2.2 were used to represent the real IP of the outside of the FW. The reason for this is outbound request from inside needs to go out and to an external provider hence the need for XFF to distinguish who the internal users vs external users are, and if they match the DG, they get access to the URI in the other data group.

 

Thanks all! Tony

 

ltm data-group internal DG-XFF-ALLOWED-IP-LIST {

    records {

        1.1.1.1/32 { }

        2.2.2.2/32 { }

    }

    type ip

}

ltm data-group internal DG_RESTRICTED_URI {

    records {

        /URI1 { }

        /URI2 { }

        /URI3 { }

        /URI4 { }

        /URI5 { }

        /URI6 { }

    }

    type string

}
Section 1
when HTTP_REQUEST {
if { [active_members MYPOOL-PORT-443] < 1 } {
         HTTP::redirect "http://maintenance-page.company.com" }
         log local0. "Redirect to maintenance page when all pool members is down: [HTTP::host]"
Section 2
  if { [class match [HTTP::uri] eq "DG_RESTRICTED_URI"] } {
    if { ([HTTP::header exists "X-Forwarded-For"]) and ([HTTP::header values X-Forwarded-For] ne " ") and ([class match [getfield [HTTP::header values X-Forwarded-For] " " 1] eq "DG-XFF-ALLOWED-IP-LIST"]) } {
     log local0."[HTTP::header values X-Forwarded-For]"
     pool MYPOOL-PORT-443
Section 3 -- This section does not use a data group for a URI list, there is a specific match listed below as "/URI1/URL2/PORTAL/ADMIN" that needs to match exactly
   if { [class match [HTTP::uri] eq "*/URI1/URI2/PORTAL/ADMIN*"] } {
     if { ([HTTP::header exists "X-Forwarded-For"]) and ([HTTP::header values X-Forwarded-For] ne " ") and ([class match [getfield [HTTP::header values X-Forwarded-For] " " 1] eq "DG-XFF-ALLOWED-IP-LIST"]) } {
     HTTP::redirect "https://[HTTP::host]/SECRET/URI1/URI2/ADMIN/"

  } else {
    reject
    log local0. "Client IP Discard: \ [HTTP::uri]  [HTTP::header values X-Forwarded-For] ->   [IP::local_addr]:[TCP::local_port]"

    }

   }

  }

 }

}

6 Replies

  • I am not sure about the efficiency level you can achieve but I would recommend considering this untested version:

    when HTTP_REQUEST {
        if { [active_members MYPOOL-PORT-443] < 1 } {
            HTTP::redirect "http://maintenance-page.company.com" 
        } else {
        set CHECK_IP [getfield [HTTP::header values X-Forwarded-For] " " 1]
    
        if { ([class match $CHECK_IP eq "DG-XFF-ALLOWED-IP-LIST"]) } {
            if { [class match [HTTP::uri] eq "DG_RESTRICTED_URI"] } {
                    pool MYPOOL-PORT-443
                elseif { [class match [HTTP::uri] eq "/URI1/URI2/PORTAL/ADMIN"] } {
                    HTTP::redirect "https://[HTTP::host]/SECRET/URI1/URI2/ADMIN/"
                 }
             }
         }
       }
    }
    
  • Hi Guys,

    The "elseif" was missing a bracket. I also added the "reject" statement where if you are trying to go to the URI in the data group or URI "*/URI1/URI2/PORTAL/ADMIN" on this site, your IP must match the ones from the XFF defined in the data group. If not, it should reject. Is this correct to use the "reject" or will this deny all traffic to the site? Which is what we do not want to do. Only deny if your XFF IP does match the ones in the data group when you go the URIs on this site.

    Thank you.

    when HTTP_REQUEST {
    if { [active_members MYPOOL-PORT-443] > 1 } {
    HTTP::redirect "http://maintenance-page.company.com" 
    
    } else { 
    
    set CHECK_IP [getfield [HTTP::header values X-Forwarded-For] " " 1]
    
      if { ([class match $CHECK_IP eq "DG-XFF-ALLOWED-IP-LIST"]) } {
          if { [class match [HTTP::uri] eq "DG_RESTRICTED_URI"] } {
                 pool MYPOOL-PORT-443
            } elseif { [class match [HTTP::uri] eq "*/URI1/URI2/PORTAL/ADMIN"] } {
                 HTTP::redirect "https://[HTTP::host]/SECRET/URI1/URI2/ADMIN/"
                 reject
             }
         }
       }
    }
    
    • Vijay_E's avatar
      Vijay_E
      Icon for Cirrus rankCirrus
      `if { [active_members MYPOOL-PORT-443] < 1 } {`
      

      Should be less than 1 and not greater than 1

    • Tony2020's avatar
      Tony2020
      Icon for Nimbostratus rankNimbostratus

      hi vijay,

       

      will the "reject" work in the code where the irule looks at the data group to match the ip obtained from the XFF header and if you go to the URI in the other data group or in the code, allow, and if your not part of the IP list, deny? otherwise allow access to the full site without restrictions? we do not want the "reject" to prevent access to the site under normal conditions if not accessing the protected URI....

       

      thank you, tony

       

    • Vijay_E's avatar
      Vijay_E
      Icon for Cirrus rankCirrus

      Why do you need a reject after redirecting ?

       

      Also, the idea of coming up with an iRule and running it directly on production VS is a bit disconcerting. I would recommend creating a test VS to test out the iRule before deploying it in production environment.