Forum Discussion

Rob_78590's avatar
Rob_78590
Icon for Nimbostratus rankNimbostratus
Aug 25, 2009

iRule for SNAT for Host IPs & Supernets based on specific customer

Hi everyone! We currently have an iRule setup to SNAT to a particular IP depending on which customer it is. We specify the customer's host address in the Data Group List and associate it to our IP that we would like to SNAT to. The iRule listed below currently works for host IPs, however, it does not support Supernets. Does anyone know how to modify the below iRule to also include Supernets for customers who may have a large block of addresses?

 

 

 

when CLIENT_ACCEPTED {

 

 

set syn_snat [findclass [IP::local_addr] $::syniverse_snat " "]

 

 

if { $syn_snat ne ""} {

 

 

snat $syn_snat

 

 

}

 

 

}

 

 

  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    I'd guess the current format is just a host and the corresponding SNAT IP:

    client IP | SNAT IP

    1.1.1.1 2.2.2.2

    Unfortunately, there isn't a simple way to do subnet evaluations against a two-field datagroup. Normally you could use matchclass to evaluate a client IP or subnet against a datagroup of a type "address". But that doesn't allow you to easily configure a corresponding SNAT address. You could loop through the datagroup as a TCL list, use IP::addr (Click here) to evaluate the client IP against the subnet (in CIDR format) and then get the corresponding SNAT IP. It wouldn't be as efficient as using a native class querying command line matchclass, but it should provide the functionality.

    So the class would be a string class with this format:

    1.1.1.0/24 2.2.2.2

    3.1.1.0/20 3.3.3.3

    And you could use a rule like this:

      
      when CLIENT_ACCEPTED {  
      
         log local0. "[IP::client_addr]:[TCP::client_port]: New connection. Using class: $::ip_snat_class"  
      
          Loop through each line in the datagroup  
         foreach line $::ip_snat_class {  
      
             Log the current line by field  
            log local0. "\$line: $line, IP: [lindex $line 0], SNAT: [lindex $line 1]"  
      
             Check if the client IP equals the current line's subnet  
            if {[IP::addr [client_addr] equals [lindex $line 0]]}{  
      
               log local0. "[IP::client_addr]:[TCP::client_port]: Matched [lindex $line 0], using SNAT [lindex $line 1]"  
      
        Use the SNAT IP 
               snat [lindex $line 1] 
      
                Exit the loop as we've found a match  
               break  
            }  
         }  
      } 
     

    Which logs this:

    : 1.2.2.3:37646: New connection. Using class: {1.2.0.0/16 4.4.4.4} {1.1.1.0/24 2.2.2.2} {3.4.5.0/24 3.3.3.3}

    : $line: 1.2.0.0/16 4.4.4.4, IP: 1.2.0.0/16, SNAT: 4.4.4.4

    : 1.2.2.3:37646: Matched 1.2.0.0/16, using SNAT 4.4.4.4

    Aaron
  • Hi Aaron (Hoolio),

     

     

    Thanks for the reply. Yes, the current format is as follows:

     

     

    client IP | SNAT IP

     

    1.1.1.1 2.2.2.2

     

     

    So, if I understand correctly, we can use the rule you recommended to specify the network & mask in the Data Group List and then specify the SNAT IP, right? If yes, then by using your iRule, I assume this would support host routes, by adding a /32, in addition to a range of addresses depending on the mask. Am I thinking correctly?

     

     

    Thanks,

     

     

    Rob
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    Hi Rob,

     

     

    Yep, I expect host entries specified with a /32 mask would work fine. Though just specifying the IP address should work too with IP::addr. The class could use either the first or second line's format:

     

     

    Subnet | SNAT IP

     

    1.1.1.1/32 2.2.2.2

     

    1.1.1.1 2.2.2.2

     

    3.3.3.0/24 4.4.4.4

     

     

    The example I posted doesn't actually SNAT the connection, but you can add that in using 'snat [lindex $line 1]' after the log statement. If you are able to test this please reply back with the results. We can then add this as an example to the IP::addr wiki page and/or the codeshare.

     

     

    Thanks,

     

    Aaron
  • Hi Aaron,

     

     

    Wouldn't it be easier to just modify my current iRule by replacing [IP::local_addr] with [IP::addr]? By doing that, my iRule would be as follows:

     

     

    when CLIENT_ACCEPTED {

     

     

    set syn_snat [findclass [IP::addr] $::my_snat " "]

     

     

    if { $syn_snat ne ""} {

     

     

    snat $syn_snat

     

     

    }

     

     

    }

     

     

    In my Data Group List called "my_snat", I would specify the various formats that we previously discussed. This should provide the results I need, right?

     

     

  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    I don't think so. The IP::addr command can be used to evaluate whether an IP address or subnet equals another IP address or subnet.

     

     

    You couldn't use it in combination with findclass. But give it a try if you feel like it. I assume you'll get a parser error when trying to save the rule.

     

     

    Aaron
  •  

    Hi Aaron,

     

     

    I'll give your iRule a try. I'll let you know what the results are. For the Data Group List, I just want to confirm that the string your using is arbitrarily called "ip_snat_class", right?

     

     

    Also, you stated that, in order to SNAT, I would have to add the syntax 'snat [lindex $line 1]' after the log statement. However, there are a couple of log statements, so I'm not exactly sure how it would be placed in the iRule. Just to make sure I do it correcty, can you rewrite the iRule to include the syntax 'snat [lindex $line 1]' after the log statement?

     

     

    Thanks,

     

     

    Rob
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    Hi Rob,

     

     

    Yeah, you can name the datagroup/class anything you want. Just update the iRule reference to the class.

     

     

    I edited the post above to include the snat command. It's just before the break statement to exit the foreach loop after a match is found in the datagroup. Hope that makes sense.

     

     

    Thanks,

     

    Aaron
  • Hi Aaron,

     

     

    One of our engineers modified the iRule a bit, and it works great for host IPs as well as supernets. Here is the iRule;

     

     

     

    when CLIENT_ACCEPTED {

     

     

    Loop through each line in the datagroup

     

     

    foreach line $::syniverse_snat {

     

     

    Check if the local IP equals the current line's subnet

     

     

    if {[IP::addr [IP::local_addr] equals [lindex $line 0]]}{

     

     

    log local0. "[IP::local_addr]:[TCP::local_port]: Matched [lindex $line 0], using SNAT [lindex $line 1]"

     

     

    Use the SNAT IP

     

     

    snat [lindex $line 1]

     

     

    Exit the loop as we've found a match

     

     

    break

     

     

    }

     

     

    }

     

     

    }

     

     

     

    Thanks a lot for your help!

     

     

    Rob