Forum Discussion

noahshelton_237's avatar
noahshelton_237
Icon for Nimbostratus rankNimbostratus
Aug 25, 2016

Combine IF and SWITCH to apply SNAT based on destination IP and/or TCP port

I use an irule applied to a L4 performance forwarding virtual server to serve as a sort of selective NAT based on a couple different criteria (in most cases just the TCP port for which I use a switch statement). I have an edge use case for a specific host that I need to match via IP however I am concerned that matches lower in the rule will override.(and also just looking for a more elegant way to perform this function).

My switch statement is matching TCP ports because I don't always know the destination network but I do know the sending port.

My irule :

 if destination IP is 10.10.10.10 SNAT to .15 regardless of TCP port
when CLIENT_ACCEPTED {if { [IP::addr [IP::local_addr] equals 10.10.10.10/32] } 
{log local0. "Export Server [IP::client_addr] sending outbound connection to [IP::local_addr]:[TCP::local_port], applying SNAT 10.10.70.15"
snat 10.10.70.15 }

 if tcp port matches anything in the switch list use .70 snat
switch [TCP::local_port] {
"104" -
"4000" -
"12000" -
"7400" {
snat 10.10.70.70
log local0. “Host with IP address [IP::client_addr] sending outbound connection to [IP::remote_addr]:[TCP::local_port], applying SNAT 10.10.70.70”
}
 otherwise don't do anything...
default {
}
}
}

So in this case if a connection hits my L4 VS/Irule with a destination of 10.10.10.10 and tcp port 104 will I get the first SNAT from within the IF statement, or will it continue to match and apply the second SNAT from withing the SWITCH statement?

The above irule does pass syntax check but unfortunately I do not have a lab environment to test with. Alas!

Any input and guidance is very much appreciated.

-Noah

  • when CLIENT_ACCEPTED {
      if { [IP::addr [IP::local_addr] equals 10.10.10.10/32] } {
        switch [TCP::local_port] {
          "104" -
          "4000" -
          "7400" -
          "12000" { snat 10.10.70.70 }
          default { snat 10.10.70.15 }
        }
      }
    }
    

    At this point, though, you're getting close to wanting to use a datagroup instead of switch.

  • So in this case if a connection hits my L4 VS/Irule with a destination of 10.10.10.10 and tcp port 104 will I get the first SNAT from within the IF statement, or will it continue to match and apply the second SNAT from withing the SWITCH statement?

     

    2nd SNAT - 10.10.70.70

     

    You can try using some kind of "return" statement if you want to stop processing after 1st match or you can change the order of matching depending on your requirements.

     

    If you want the port to take precedence, you can use it above the IP address check. For example: 10.10.10.10:104 - which SNAT do you want to use ?

     

  • Both of the statements would run. The return would end processing at that point.

    If you want the switch statement to run, but not if the IP address matches 10.10.10.10, why not add an if statement to your switch statement? There are probably more elegant ways to accomplish this:

     if destination IP is 10.10.10.10 SNAT to .15 regardless of TCP port
    when CLIENT_ACCEPTED {if { [IP::addr [IP::local_addr] equals 10.10.10.10/32] } 
    {log local0. "Export Server [IP::client_addr] sending outbound connection to [IP::local_addr]:[TCP::local_port], applying SNAT 10.10.70.15"
    snat 10.10.70.15 }
    
     if tcp port matches anything in the switch list use .70 snat
    switch [TCP::local_port] {
    "104" -
    "4000" -
    "12000" -
    "7400" {
        if {[IP::addr [IP::local_addr] not 10.10.10.10/32] }{
            snat 10.10.70.70
            log local0. “Host with IP address [IP::client_addr] sending outbound connection to [IP::remote_addr]:[TCP::local_port], applying SNAT 10.10.70.70”
        }
    }
     otherwise don't do anything...
    default {
    }
    }
    }
    
    • noahshelton_237's avatar
      noahshelton_237
      Icon for Nimbostratus rankNimbostratus

      This makes more sense, I'll test it.

       

      I always forget about checking for a negative match in my logic.

       

    • AJ_01_135899's avatar
      AJ_01_135899
      Icon for Cirrostratus rankCirrostratus

      Hmm, that's unfortunate. Mabye ne, not equals or != ? If none of those work I'd just flip the logic around.

       if destination IP is 10.10.10.10 SNAT to .15 regardless of TCP port
      when CLIENT_ACCEPTED {if { [IP::addr [IP::local_addr] equals 10.10.10.10/32] } 
      {log local0. "Export Server [IP::client_addr] sending outbound connection to [IP::local_addr]:[TCP::local_port], applying SNAT 10.10.70.15"
      snat 10.10.70.15 }
      
       if tcp port matches anything in the switch list use .70 snat
      switch [TCP::local_port] {
      "104" -
      "4000" -
      "12000" -
      "7400" {
          if {[IP::addr [IP::local_addr] equals 10.10.10.10/32] }{
              do nothing        
          }
          else{
              snat 10.10.70.70
              log local0. “Host with IP address [IP::client_addr] sending outbound connection to [IP::remote_addr]:[TCP::local_port], applying SNAT 10.10.70.70”
          }
      }
       otherwise don't do anything...
      default {
      }
      }
      }
      
  • when CLIENT_ACCEPTED {
      if { [IP::addr [IP::local_addr] equals 10.10.10.10/32] } {
        switch [TCP::local_port] {
          "104" -
          "4000" -
          "7400" -
          "12000" { snat 10.10.70.70 }
          default { snat 10.10.70.15 }
        }
      }
    }
    

    At this point, though, you're getting close to wanting to use a datagroup instead of switch.

    • noahshelton_237's avatar
      noahshelton_237
      Icon for Nimbostratus rankNimbostratus

      Yes just setup a data group to match ip:tcp port with a snat.... I'm waiting on a window to test with so I'll report back what I finally get working.

       

  • when CLIENT_ACCEPTED {
      if { [IP::addr [IP::local_addr] equals 10.10.10.10/32] } {
        switch [TCP::local_port] {
          "104" -
          "4000" -
          "7400" -
          "12000" { snat 10.10.70.70 }
          default { snat 10.10.70.15 }
        }
      }
    }
    

    At this point, though, you're getting close to wanting to use a datagroup instead of switch.

    • noahshelton_237's avatar
      noahshelton_237
      Icon for Nimbostratus rankNimbostratus

      Yes just setup a data group to match ip:tcp port with a snat.... I'm waiting on a window to test with so I'll report back what I finally get working.