Forum Discussion

brettbeggs_1177's avatar
brettbeggs_1177
Icon for Nimbostratus rankNimbostratus
Apr 07, 2010

iRule Request - strip sub domains

I'm trying to create an iRule that can be used similar to the following mod rewrite command:

 

 

RewriteCond %{HTTP_HOST} ^.+\.(.+)\.mydomain\.com$ [NC]

 

RewriteRule ^(.*)$ https://%1.mydomain.com$1 [R=301,L]

 

 

What we're wanting is anything that hits https://*.sub.mydomain.com to be redirected to https://sub.mydomain.com. I guess i'm just not sure how to strip everything before sub.mydomain.com from the URL while maintaining whatever is in that first sub domain spot.

 

 

Ideally this single rule would work for any of these variants:

 

https://*.sub1.mydomain.com > https://sub1.mydomain.com

 

https://*.sub2.mydomain.com > https://sub2.mydomain.com

 

https://*.whatever.mydomain.com > https://whatever.mydomain.com

 

 

If it matters, the virtual server is configured with a wildcard ssl certificate *.mydomain.com so we're trying to avoid customers instinctively adding www. to the beginning of the url and getting a certificate error.

 

 

Thanks for helping!

 

 

 

 

 

6 Replies

  • Hi Brett,

    I tried a regex, but it was about 10x less efficient than a couple of string and list operations:

    Simple perf test:

    % time {set host_list [split $host "."]; lindex $host_list [expr {[llength $host_list] -3}]} 1000

    13 microseconds per iteration

    % time {regexp -inline -nocase {(?:[^.]+\.){0,}([^.]+)\.mydomain\.com} test.mydomain.com} 1000

    133 microseconds per iteration

    when HTTP_REQUEST {
       log local0. "[IP::client_addr]:[TCP::client_port]: [HTTP::method] request to [HTTP::host][HTTP::uri]"
        Split the host header value on periods into a list
       set host_list [split [HTTP::host] "."]
       log local0. "[IP::client_addr]:[TCP::client_port]: Parsed host list $host_list"
        Check if there were more than three fields
       if {[llength $host_list] > 3}{
           Send a redirect with the third to last field from the requested host prepended to .mydomain.com
          HTTP::respond 301 Location "https://[lindex $host_list [expr {[llength $host_list] -3}]].mydomain.com"
          log local0. "[IP::client_addr]:[TCP::client_port]: Redirecting to\
             https://[lindex $host_list [expr {[llength $host_list] -3}]].mydomain.com"
       }
    }

    Aaron
  • Thanks Aaron.

     

    I ended up having to make one little tweak, adding "https://" to the response code to get it sent over to the correct place.

     

     

    
           Send a redirect with the third to last field from the requested host prepended to .mydomain.com
          HTTP::respond 301 Location "https://[lindex $host_list [expr {[llength $host_list] -3}]].mydomain.com"
     

     

     

    The problem now seems to be that the redirect isnt taking place before the request hits the virtual server. This is causing a certificate error to pop up. Once you add the exception and advance past it, the redirect works like a champ. I guess on some level that makes sense. The request has to hit the virtual server before it processes the iRule, but in doing so, causes the certificate exception.

     

     

    When monitoring the logs, nothing gets logged until after you accept the certificate warning.
  • Thanks for the correction on the redirect location protocol. I assumed you were using this rule on an HTTP VIP. As you found it's too late to fix this when the client is making an HTTPS request with a hostname that doesn't match the SSL cert. For HTTPS, LTM needs to decrypt the SSL before viewing the HTTP or sending an HTTP response. In order to decrypt the SSL, LTM needs to send its cert and complete an SSL handshake.

     

     

    To fix this, you'd need to correct the client's request before it's made via HTTPS. So if you can add this iRule to an HTTP VIP you could prevent the insecure cert warning for the HTTPS requests. Or if clients are expected to make requests directly via HTTPS to the various hostnames, you could create separate A records to resolve the hostnames to different IP addresses.

     

     

    Aaron
  • This is so frustrating...

     

     

    I've decided to apply this iRule to the HTTP virtual server and wanted to add an else statement. Basically, the first part of the script should run and fix anything with more than 3 levels to the domain name. I want the else statement to kick in for everything else and simply redirect to https. Using the code below, i see the stuff show up in the log, but for the life of me, i can't get it to work. The browser just keeps saying that "The page isn't redirecting properly...Firefox has detected that the server is redirecting the request for this address in a way that will never complete".

     

     

    Here's the code added...

     

     

    else {

     

    HTTP::respond 301 Location "https://[HTTP::host][HTTP::uri]"

     

    log local0. "[IP::client_addr]:[TCP::client_port]: Redirecting to https://[HTTP::host][HTTP::uri] without parsing"

     

    }

     

     

    Any thoughts on why that keeps failing?
  • What do the logs show (/var/log/ltm)? Is the HTTPS VIP redirecting some or all requests to HTTP?

     

     

    Aaron
  • Ahh, yes...i was stupid and had the same irule on the http and https virtual server. I tweaked the version running on the https VS and now all is well. Thanks for all your help.