Forum Discussion

dan_19334's avatar
dan_19334
Icon for Nimbostratus rankNimbostratus
Dec 20, 2010
Solved

determine HTTP or HTTPS

What is the best way to determine if the connection came in HTTP or HTTPS? I want to have a common iRule applied to both port 80 & 443 that redirects the connection to a different location but keeps it HTTP or HTTPS depending on how it came in.

 

 

 

when HTTP_REQUEST {

 

if { "CAME IN WITH SSL?" } {

 

HTTP::redirect "https://abc123.com[HTTP::uri]"

 

} else {

 

HTTP::redirect "http://abc123.com[HTTP::uri]"

 

}

 

}

 

 

 

Is there an efficient way to do this?

 

 

Thanks,

 

-Dan

 

 

 

  • Patrik, good one. You have typo. It should be:

    if { [PROFILE::exists clientssl] == 1 } {
        set protocol "https"
    } else {
        set protocol "http"
    }
    

    I'm doing this on CLIENT_ACCEPTED. The method with CLIENTSSL_HANDSHAKE will not work because BIG-IP refuse to load it on VS without SSL profile.

11 Replies

  • Hi Dan,

    If you want to assume anything on 443 is SSL, you could use something like this:

    
    when CLIENT_ACCEPTED {
    
        Check the VS port to determine if connection is SSL or not
       switch [TCP::local_port] {
          "443" {
             set proto "https"
          }
          default {
             set proto "http"
          }
       }
    }
    when HTTP_REQUEST {
       if {$we_are_redirecting==1}{
          HTTP::redirect "${proto}://abc123.com[HTTP::uri]"
       }
    }
    

    Or you could look for a completed SSL handshake with this:

    
     From http://devcentral.f5.com/Community/GroupDetails/tabid/1082223/aff/5/afv/topic/aft/1176419/afc/1200188/Default.aspx
    when CLIENT_ACCEPTED { 
    
        Set a variable to track whether this is an HTTPS request 
       set proto "http"
    } 
    when CLIENTSSL_HANDSHAKE {
        There was a client side SSL handshake, so update the variable 
       set proto "https"
    } 
    when HTTP_REQUEST {
       if {$we_are_redirecting==1}{
          HTTP::redirect "${proto}://abc123.com[HTTP::uri]"
       }
    }
    

    Aaron
  • Thanks Aaron, I like the CLIENTSSL_HANDSHAKE method as it will be more adaptable to all situations.

     

     

    Would be nice though if there was an [HTTP::URL] command to return the entire URL that was called, then could just do something like:

     

    [URI::protocol [HTTP::URL]]

     

    Or, if [URI::protocol] with no argument would return the URI scheme of the current connection.

     

     

     

     

  • I'm not familiar enough with [URI::protocol] but why wouldn't that work here?

    
    
    when HTTP_REQUEST {
        if { [URI::protocol [HTTP::uri]] eq "https" } {
          HTTP::redirect "https://abc123.com[HTTP::uri]"
        } else {
          HTTP::redirect "http://abc123.com[HTTP::uri]"
        }
    }
    

    Examples for URI::protocol seem to be lacking but is there any reason this wouldn't work?
  • The protocol isn't included in an HTTP request, so I'm not sure HTTP::url would make sense. Maybe something like SSL::enabled returning 1 if a handshake with a non-null cipher would make sense. I'll open a request for enhancement case and reply here with the RFE ID.

     

     

    Aaron
  • Chris,

    I think URI::protocol will only parse the protocol from a full URL that already has the protocol listed. I could imagine it being useful for parsing fully qualified URLs in requests through a web proxy. However, if the client didn't include the protocol in the URI, I expect URI::protocol wouldn't return anything:

    
    when RULE_INIT {
    log local0. "\[URI::protocol /path/to/file.ext\]: [URI::protocol /path/to/file.ext]"
    log local0. "\[URI::protocol https://www.example.com/path/to/file.ext\]: [URI::protocol https://www.example.com/path/to/file.ext]"
    }
     : [URI::protocol /path/to/file.ext]:
     : [URI::protocol https://www.example.com/path/to/file.ext]: https
    

    Aaron
  • I did try the [SSL::enabled] but you can't have that in an iRule if there is no clientssl profile assigned, it would not allow it.

     

     

    Thanks for the RFE, think it does make sense here...

     

     

     

     

  • Another option is a small tcp collect in the CLIENT_ACCEPTED event to see if a method is present:

    class httpmethods {
       {
          "CONNECT"
          "DELETE"
          "GET"
          "HEAD"
          "OPTIONS"
          "POST"
          "PUT"
          "TRACE"
       }
    }
    
    
    when CLIENT_ACCEPTED {
    TCP::collect 5
    }
    when CLIENT_DATA {
    if { [class match [TCP::payload] equals httpmethods] } {
    set nonssl 1
    } else { set nonssl 0 }
    }
    when HTTP_REQUEST {
    if { $nonssl } {
    HTTP::redirect "http://abc123.com[HTTP::uri]"
    } else { HTTP::redirect "https://abc123.com[HTTP::uri]" }
    }
    
  • Hi!

    Old post, but in case someone else finds it here's how I solved it:

    if { [PROFILE::exists clientssl == 1] } {
        set protocol "https"
    } else {
        set protocol "http"
    }
    

    Might not be 100% reliable if you disable ssl profiles in your irules but otherwise it should work fine.

    /Patrik

  • Patrik, good one. You have typo. It should be:

    if { [PROFILE::exists clientssl] == 1 } {
        set protocol "https"
    } else {
        set protocol "http"
    }
    

    I'm doing this on CLIENT_ACCEPTED. The method with CLIENTSSL_HANDSHAKE will not work because BIG-IP refuse to load it on VS without SSL profile.

    • Kevin_Davies_40's avatar
      Kevin_Davies_40
      Icon for Nacreous rankNacreous

      Given the predilection for TCL that 0 is false and anything else is true you can shorten this to....

      if {[PROFILE::exists clientssl]} {
          set protocol https
      } else {
          set protocol http
      }
      

      But you can even get more funky with TCL ? conditions

      set protocol [[PROFILE::exists clientssl]?https:http]
      
  • Create two Virtuals. One for HTTP one for HTTPS. Now you know whether it's HTTP or HTTPS. Apply irule for each. Looking for client profile assumes you're doing SSL birding or termination. Some virtuals may not do this but still service HTTPS traffic.