Forum Discussion

gGnome_32510's avatar
gGnome_32510
Icon for Nimbostratus rankNimbostratus
Jan 13, 2010

Redirection

We are new to F5, tcl, iRules... the works, so I apologize if this is an easy one. I have several SSL sites (F5 is the endpoint) that are secured with *.domain.com cerfificates, and an iRule that redirects http requests to https. I now have marketing complaining because a cerficate error is generated whenever someone leaves out the hostname (as in http://domain.com). I need to create an iRule that will catch this scenario and cause the browser to reissue the request as http://site.domain.com. I would appreciate any help.

 

 

28 Replies

  • Here's a version with logging. Can you reproduce the issue and post anonymized logs from /var/log/ltm for a failure?

     

     

       
      when HTTP_REQUEST {   
         
         log local0. "[IP::client_addr]:[TCP::client_port]: [HTTP::method] request\   
            to [IP::local_addr] [HTTP::host][HTTP::uri]"   
         
          Check if the host header has at least three fields (anything.example.com)   
          This would also match an IP address, but that seems like a use case   
          where the client would expect a cert mismatch error when requested via HTTPS   
         if {[string match "*.*.*" [HTTP::host]]}{   
         
            log local0. "[IP::client_addr]:[TCP::client_port]: Passed domain check."   
         
             Assume the client has requested a valid domain (*.example.com)   
             where the domain of the host header is what the SSL cert on the HTTPS VIP is issued for   
            HTTP::redirect "https://[HTTP::host][HTTP::uri]"   
         
         } else {   
         
            log local0. "[IP::client_addr]:[TCP::client_port]: Two domain fields or less"   
         
             Look up the correct domain for this request   
             using the VIP address in the ip_to_hostname_class datagroup   
            set hostname [findclass [IP::local_addr] $::ip_to_hostname_class]   
         
            log local0. "[IP::client_addr]:[TCP::client_port]: Parsed $hostname from class $::ip_to_hostname_class"   
         
            if {$hostname eq ""}{   
                Should there ever be a VIP IP which doesn't have a corresponding class entry??   
        You could hard code a default redirect here if you want   
               HTTP::redirect "https://www.example.com[HTTP::uri]"   
               log local0. "[IP::client_addr]:[TCP::client_port]: No hostname parsed. Using default hostname"   
            } else {   
                Parse the last two parts of the hostname (returns example.com from www.example.com   
               log local0. "[IP::client_addr]:[TCP::client_port]: Redirectting to https://www.[domain $hostname 2][HTTP::uri]"   
               HTTP::redirect "https://www.[domain $hostname 2][HTTP::uri]"   
            }   
         }   
      }  
       

     

     

     

    If the user types https://example.com, that VS never runs so the redirect never occurs. I tried adding the same iRule to the https VS for the same site, and it doesn't work there. Can you tell me why?

     

     

     

     

    A request directly to https://example.com cannot work without a cert mismatch error using the existing *.example.com cert. Trying to redirect the HTTPS request won't help, as the cert warning occurs during the SSL handshake before any HTTP headers are sent or received. If this is really a problem, you could add a new DNS A record to point example.com to a different IP than www.example.com, or get a new cert which is valid for *.example.com and example.com.

     

     

    Aaron
  • I think it would be easier to add a unique string to the log lines for this rule compared with modifying the syslog-ng configuration to log to a separate file or trying to find a syslog facility which isn't used much. You could add [virtual name] to the log line and then tail the ltm log file and grep for only the lines which contain VIP_NAME:

     

     

    tail -f /var/log/ltm | grep -i VIP_NAME

     

     

    This will output new lines from the ltm log file which match the string VIP_NAME. Type Ctrl+c to stop the tail.

     

     

    As for the cert, I think some CA's do offer a wildcard cert which supports *.example.com and example.com (Redirect abc.com to www.abc.com - Click here). Whether it's worth it for your scenario or not is another question...

     

     

    Aaron
  • Right now I don't have a good way to test the "Using default hostname" case, so I'm concentrating on the other two. I ran the request once with www.example.com and once with http://example.com, and both passed the if {[domain [HTTP::host] 3] ne ""} check though the second should have failed. Here are the log entries:

     

     

    Jan 15 08:17:01 tmm tmm[929]: Rule http_to_https_v3 : 1.1.1.7:1053: GET request to 192.168.18.34 www.example.com/

     

    Jan 15 08:17:01 tmm tmm[929]: Rule http_to_https_v3 : 1.1.1.7:1053: Passed domain check.

     

    Jan 15 08:17:38 tmm tmm[929]: Rule http_to_https_v3 : 1.1.1.7:1060: GET request to 192.168.18.34 example.com/

     

    Jan 15 08:17:38 tmm tmm[929]: Rule http_to_https_v3 : 1.1.1.7:1060: Passed domain check.

     

     

    Thanks for the info on Pair. Thawte told me I would have to use two certificates to accomplish the same end result (and Thawte is even more expensive). It won't help me in the short term, but I may well change CA's as my wildcards come up for renewal.

     

     

    Gregg
  • Hi Gregg,

    Sorry, I was misinterpreting what the domain command would return if the number of fields specified was greater than the number of fields in the input string. string match should work though. I edited the examples above to use string match. Can you try that?

    Here is an example of how to test for at least three fields in the host header:

     
     when RULE_INIT { 
      
         domain returns up to the number of fields specified in the count parameter 
        log local0. "\[domain 10.11.12.13 3\]: [domain 10.11.12.13 3]" 
        log local0. "\[domain test.sub.example.com 3\]: [domain test.sub.example.com 3]" 
        log local0. "\[domain sub.example.com 3\]: [domain sub.example.com 3]" 
        log local0. "\[domain example.com 3\]: [domain example.com 3]" 
      
         string match matches three or more fields with a pattern of *.*.* 
        log local0. "\[string match *.*.* 10.11.12.13\]: [string match *.*.* 10.11.12.13]" 
        log local0. "\[string match *.*.* test.sub.example.com\]: [string match *.*.* test.sub.example.com]" 
        log local0. "\[string match *.*.* sub.example.com\]: [string match *.*.* sub.example.com]" 
        log local0. "\[string match *.*.* example.com\]: [string match *.*.* example.com]" 
        log local0. "\[string match *.*.* com\]: [string match *.*.* com]" 
     } 
     

    Log output:

    : [domain 10.11.12.13 3]: 11.12.13

    : [domain test.sub.example.com 3]: sub.example.com

    : [domain sub.example.com 3]: sub.example.com

    : [domain example.com 3]: example.com

    : [string match *.*.* 10.11.12.13]: 1

    : [string match *.*.* test.sub.example.com]: 1

    : [string match *.*.* sub.example.com]: 1

    : [string match *.*.* example.com]: 0

    : [string match *.*.* com]: 0

    Aaron
  • Jan 19 05:10:15 tmm tmm[929]: Rule http_to_https_v3 : 10.11.12.13:1118: GET request to 192.168.18.34 hostname.example.com/

     

    Jan 19 05:10:15 tmm tmm[929]: Rule http_to_https_v3 : 10.11.12.13:1118: Passed domain check.

     

    Jan 19 05:10:45 tmm tmm[929]: Rule http_to_https_v3 : 10.11.12.13:1126: GET request to 192.168.18.34 example.com/

     

    Jan 19 05:10:45 tmm tmm[929]: Rule http_to_https_v3 : 10.11.12.13:1126: Two domain fields or less

     

    Jan 19 05:10:45 tmm tmm[929]: 01220001:3: TCL error: Rule http_to_https_v3 - can't read "::ip_to_hostname_class": no such variable while executing "findclass [IP::local_addr] $::ip_to_hostname_class"

     

     

    It appears to have some problem with my data group. I created it in the GUI as type string; currently it has one record: 192.168.18.34 hostname.example.com. Should I have done something differently?
  • That's a step forward as far as the hostname parsing.

     

     

    The iRule references a datagroup named ip_to_hostname_class. If yours is named differently (which the error log indicates), you can change the reference in the iRule from ip_to_hostname_class to the actual datagroup name you've created. As you're running a version before 9.4.4, make sure to prefix the datagroup name with $::.

     

     

    Aaron
  • Sorry... freakin' typo. It appears to be working properly now. You're a rock star. Thank you. Thank you. Thank you. I will start building up the data group and migrating my sites shortly.

     

     

    FYI: when I tried to recreate the Data Group with the "$::" prepended to the name, the GUI returns an illegal character error regarding the dollar sign. When I removed the dollar sign(ie: "::ip_to_hostname_class"), it simply told me the name is invalid.

     

     

    Other than the info on the Dev Central site, do you have a favorite reference for learning the language?
  • Looks like I have some homework to do. Thank you again for your patience and all your help, Aaron.

     

     

    Gregg