Forum Discussion

Ethan_Erchinger's avatar
Ethan_Erchinger
Icon for Nimbostratus rankNimbostratus
Mar 09, 2006

Snat pool choice based on destination URL

Hi,

 

 

We have a group of servers that make outbound HTTP requests to a partner. We'd like requests going to a specific uri, call it partner.com/a to come from a specific pool of addresses. Requests destined to partner.com/b should come from a different pool of addresses. We'd like to know of that's possible?

 

 

To ensure I'm understood I would like something like:

 

 

Source hosts on our internal vlan: 10.1.0.x

 

 

Destination URL: http://partner.com/a

 

Source NATd IPs: x.1.1.1-16

 

Destination URL: http://partner.com/b

 

Source NATd IPs: x.1.1.17-32

 

 

All the outbound requests are HTTP, no-ssl on the outbound request.

 

 

The only solution I've found would be to specify a wildcard virtual of 0.0.0.0 and then assign a rule that does all nat translation, based on various source addresses and other measures. But, wouldn't I generate quite a bit more load on the system if I need to run through an iRule on every outbound request, over using standard snat entries?

 

 

Thanks for your time.

 

Ethan

9 Replies

  • I would make a specific vip for your partner site, even if it is only one server. You could try something like this:

    
    rule snat_selection {
      when HTTP_REQUEST {
        if { [HTTP::uri] starts_with "/a" } {
          use snatpool snat_a
          use pool partner_pool
        } elseif { [HTTP::uri] starts_with "/b" } {
            use snatpool snat_b
            use pool partner_pool
        } else {  }
      }
    }
    snatpool snat_a {
      member x.1.1.1
      
      member x.1.1.16
    }
    snatpool snat_b {
      member x.1.1.17
      
      member x.1.1.32
    }
    snatpool snat_default {
      member x.1.1.33
      
      member x.1.1.254
    }
    pool partner_pool {
      member :80
      monitor all tcp  or whatever is appropriate
    }
    virtual partner_virtual {
      destination 10.1.0.100  assuming this is defined on your ltm
      snatpool default_snatpool  if necessary
      ip protocol tcp
      profile http
      rule snat_selection
    }

    Note that this is not tested. HTH
  • I'd probably like a wildcard vip, like you mentioned, then have basically the same rule, minus the definitions having to do with defining a pool directly.

    
    rule snat_selection {
      when HTTP_REQUEST {
        if { [HTTP::uri] starts_with "/a" } {
          use snatpool snat_a
         } elseif { [HTTP::uri] starts_with "/b" } {
            use snatpool snat_b
        } else {  }
      }
    }
    snatpool snat_a {
      member x.1.1.1
      
      member x.1.1.16
    }
    snatpool snat_b {
      member x.1.1.17
      
      member x.1.1.32
    }
    snatpool snat_default {
      member x.1.1.33
      
      member x.1.1.254
    }
    pool partner_pool {
      member :80
      monitor all tcp  or whatever is appropriate
    }
    virtual partner_virtual {
      destination 0.0.0.0  assuming this is defined on your ltm
      snatpool default_snatpool  if necessary
      ip protocol tcp
      profile http
      rule snat_selection
    }

    You might be able to make it more efficient by using classes and the switch command. Kind of like in this post:

    http://devcentral.f5.com/Default.aspx?tabid=28&view=topic&forumid=5&postid=5970

    Except, in your class, you'd have

    class domain_mappings {

    "domain.ca snat_a"

    "domain.com snat_b"

    "domain.biz snat_c"

    "joe.com snat_d"

    "fred.us snat_e"

    }

    Then, your rule would use switch to match the uri to a snatpool. I'm not exactly sure what the rule would look like, but its an idea.
  • Thanks to everyone for their help. It turns out that some of the outbound requests are using SSL, so inspection of the URI has become difficult at best, we aren't using SSL encrypt/decrypt on the BigIPs. So at this point we have multiple virtuals using our private IP space as the destination, and using the partners IPs as the members of a pool for that virtual.

    I believe though, that I should be able to modify your above example a bit and get some more flexibility, not having to manually insert the member IPs into the pool, which is effectively bypassing our partners DNS magic.

    I was thinking of something like this.

    
    rule partner_snat_rule {
      when CLIENT_CONNECTED {
          use snatpool snat_a
          use node a.partner.com 443
      }
    }

    Though when I try it, it says that "use node" requires an IP. I thought that HTTP::host was a hostname, not an IP, so the above example wouldn't work?

    Thanks,

    Ethan
  • It looks like you need to combine what you have so far with logic from this thread to resolve the name:

     

     

    http://devcentral.f5.com/default.aspx?tabid=28&view=topic&forumid=5&postid=6546
  • Yeah funny, I was just experimenting with that, but I can't seem to get it to resolve. Anyone know if I need to restart something after modifying tmm_base.tcl? I'll post this same question on 6456 and post the answer here if answered there. :-)

     

     

    Thanks,

     

    Ethan
  • Done. If it doesn't match typical CodeShare standards, please feel free to edit.

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/DestinationSnatUsingDNS.html

     

     

  • I modified the format a bit. In the future, you can use the CodeShare template as described in the overview on the top of the CodeShare topic. This way your sample will get incorporated into the sample code listing as well as links added to the relevant commands.

     

     

    Thanks for the contribution!

     

     

    -Joe
  • Sorry, I thought I had used the proper formatting. Honestly the "template" is a little skimpy on details..but whatever.

    I have a little update on a problem we ran into with DNS lookup, I'll update the codeshare as well, but thought I'd complete the thread for completeness.

    While DNS lookup does work as described in the below article, it only works correctly when the DNS lookup returns 1 IP.

    http://devcentral.f5.com/Default.aspx?tabid=28&forumid=5&postid=6546&view=topic

    To get around this limitation we found this to work nicely.

    
     when NAME_RESOLVED {
       set ::node [lindex [split [NAME::response] " "] 0]
       node $::node 80
     }

    This will take the first response from the DNS server and set the "node" variable to that IP. Otherwise $::node will be set to multiple IPs, and subsequent requests to that node will fail.