Forum Discussion

John_Nootens_45's avatar
John_Nootens_45
Icon for Nimbostratus rankNimbostratus
Jun 14, 2005

How do I redirect client dest port

1) Here is the rule I am trying. Does this look correct. I want to re-direct the client to talk on a unique port.

 

 

when HTTP_REQUEST {

 

if { [HTTP::host] contains "marstest."} {

 

HTTP::redirect HTTP://[HTTP::host][HTTP::uri]:5878

 

}

 

}

 

 

Here is what I want to do:

 

If the URL (ie: "marstest.xxx.com") contains "marstest."

 

then HTTP redirect to http://marstest.xxx.com:5878

 

 

2) Then I will probably need to do this for 10-20 URLs. Does this syntax look correct?

 

 

when HTTP_REQUEST {

 

if { [HTTP::host] contains "marstest."} {

 

HTTP::redirect HTTP://[HTTP::host][HTTP::uri]:5878

 

}

 

if { [HTTP::host] contains "other."} {

 

HTTP::redirect HTTP://[HTTP::host][HTTP::uri]:5902

 

}

 

}

 

 

Or will I need to nest if/else's 10-20 times, like this? And if this is the right way, how far can I nest the if/else's?

 

 

when HTTP_REQUEST {

 

if { [HTTP::host] contains "marstest."} {

 

HTTP::redirect HTTP://[HTTP::host][HTTP::uri]:5878

 

}

 

else if { [HTTP::host] contains "other."} {

 

HTTP::redirect HTTP://[HTTP::host][HTTP::uri]:5902

 

}

 

else if { [HTTP::host] contains "otherxxx."} {

 

HTTP::redirect HTTP://[HTTP::host][HTTP::uri]:5977

 

}

 

}

 

  • This looks good with one issue: The format for a url is the following

     

     

    protocol://host[:port]uri

     

     

    So, you'll have to change your redirects to the following:

     

     

     when HTTP_REQUEST {  
       if { [HTTP::host] contains "marstest."} {  
         HTTP::redirect HTTP://[HTTP::host]:5878[HTTP::uri]  
       } elseif { [HTTP::host] contains "other."} {  
         HTTP::redirect HTTP://[HTTP::host]:5902[HTTP::uri]  
       } elseif { [HTTP::host] contains "otherxxx."} {  
         HTTP::redirect HTTP://[HTTP::host]:5977[HTTP::uri] 
       }   
     }

     

     

    You can nest 20 or so values without any performance issues. The only downside is that it will make your iRule very cluttered. You'll also notice that I used a bunch of elseif's. If you use all "ifs" then each comparison will be run regardless of whether you matched one already and you might have an overlap that not what you intended. I'd use elseif's so that when a match is found, none of the other cases will be executed.

     

     

    Looking at this from another approach, a more optimal way to do this would be to use data groups, the findclass command, and some string extraction to make a fixed size iRule and only require to you modify the class list when you need to update the redirects.

     

     

    Off the top of my head, I'd look at doing something like the following:

     

     

    Create the string data group via the Data Groups tab under the iRules section of the GUI (or directly in the config file as shown below).

     

     class domain_redirects { 
       "www.marstest.com :5878" 
       "www.other.com :5902" 
       "www.otherxxx.com :5977" 
     }

     

     

    This contains the host value along with the port separated by a space.

     

     

    Then create the following iRule (I've included a bunch of debugging log commands that you can uncomment during your testing cycle).

     

     

     
     when HTTP_REQUEST { 
       log local0. "domain_redirect iRule" 
      
        Look for an entry in the domain_redirects data group 
        that starts with the value of the HTTP::host value 
       set match [findclass [HTTP::host] $::domain_redirects] 
       log local0. "Match: $match" 
      
       if { "" ne $match } { 
         log local0. "Found Match! 
      
          Extract the port portion of the data group item 
          Check out http://tmml.sourceforge.net/doc/tcl/string.html 
          for documentation on the TCL string command. 
         set thePort [string range $match [string last ":" $match] 999] 
         log local0. "thePort: $thePort" 
      
         set theRedirect http://[HTTP::host]$thePort[HTTP::uri] 
         log local0. "theRedirect: $theRedirect" 
      
          Redirect to the specified port on the given server 
         HTTP::redirect $theRedirect 
      
       } else { 
         log local0. "Host [HTTP::host] not in domain_redirects data group" 
       } 
     }

     

     

    The only downside with this approach is that you'll have to have separate entries for all unique domain names that your virtual server is running.

     

     

    **Update - Now that I think about it, you don't need to do the string extraction at all. I'm not going to erase the above code as it may help someone elsewhere at a later date.

     

     

    If you make the data group like this:

     

     

     class domain_redirects { 
       "www.marstest.com:5878" 
       "www.other.com:5902" 
       "www.otherxxx.com:5977" 
     }

     

     

    You can get rid of all the string searching and just use the value to replace the current HTTP::host

     

     

    when HTTP_REQUEST { 
       log local0. "domain_redirect iRule" 
      
        Look for an entry in the domain_redirects data group 
        that starts with the value of the HTTP::host value 
       set newHost [findclass [HTTP::host] $::domain_redirects] 
       log local0. "newHost: $newHost" 
      
       if { "" ne $newHost } { 
         log local0. "Found Host! 
      
          Redirect to the updated host with a new port 
         HTTP::redirect http://$newHost[HTTP::uri] 
       } else { 
         log local0. "Host [HTTP::host] not in domain_redirects data group" 
       } 
     }

     

     

    or without comments, you get the nice and tidy 4-line iRule.

     

     

     when HTTP_REQUEST { 
       set newHost [findclass [HTTP::host] $::domain_redirects] 
       if { "" ne $newHost } { 
         HTTP::redirect http://$newHost[HTTP::uri] 
       } 
     }

     

     

    -Joe
  • Hi how do I elemented the port, basically I don't to see the port that gets reditect in my browser.

     

     

    thx