Forum Discussion

branfarm_139474's avatar
branfarm_139474
Icon for Nimbostratus rankNimbostratus
May 01, 2014

SNAT and NAT on difference vlans

Hi,

I have a few questions about SNATs and NAT's and trying to get traffic to either SNAT or NAT based on the destination. Here's the diagram:

I want traffic from 10.8.4.26 destined to 10.8.8.0/24 to use a SNAT of 10.8.8.22. I want traffic from 10.8.4.26 destined to 10.8.6.0/24 to use a NAT of 10.8.6.26. I also want traffic from 10.8.6.0/24 to be able to reach 10.8.4.26 on TCP/5600.

Here's what I've tested:

  1. Configured NAT for 10.8.4.26 <> 10.8.6.26, enabled on Pubdmz vlan only. a. Ping works from internal (10.8.4.26) to pubdmz (10.8.6.104). NAT is correctly applied. b. Inbound connection from 10.8.6.104 to 10.8.6.26:5600 works c. Ping fails from 10.8.4.26 to 10.8.8.78 (external). 10.8.8.78 sees traffic from 10.8.6.26 NAT address. This would be expected at this point since no other configuration has been applied.
  2. Tried configuring second NAT for 10.8.4.26 <> 10.8.8.26 enabled on external only a. Configuration failed with error "Requested origin address already exists.
  3. Since I couldn't create second NAT, I deleted first NAT and tried VS with iRule.
  4. Created new irule data group called 'external_network' and added 10.8.8.0/24 as a record.
  5. Created new virtual server: a. Name: vs-internal-networks b. Source: 10.0.0.0/8 c. Destination: 0.0.0.0/0.0.0.0 d. Enabled on Internal e. All protocols
  6. Created new iRule called 'check_destination_snat' with following code:

    when CLIENT_ACCEPTED {
     if {[class match [IP::local_addr] equals external_network] } {
        snat 10.8.8.22
        }
    }
    
  7. Tried to ping 10.8.8.78 from 10.8.4.26. tcpdump on destination host shows that traffic is being SNAT'd, but when server attempts to ARP for SNAT address, nothing answers, so no response is ever sent.
  8. Added SNAT list called 'external-10.8.8.22, enabled on external interface. Tested ping again and this time was successful.
  9. Tried pinging pubdmz network again, but this failed due to lack of NAT. (Destination host saw traffic from original IP address)
  10. Added NAT back for 10.8.4.26 <> 10.8.6.26 enabled on Pubdmz only. Tried pinging without success -- destination host still saw traffic from original IP. Ping to 10.8.8.78 still works, and SNAT is correctly applied.

This setup leads me to a few questions:

  1. We know that the LTM will evaluate objects in the order of VS > SNAT > NAT before routing. Is there a way to tell an irule to stop processing and then have the traffic move to the next item in the list? In this case, I'd want the VS to check if it can apply a SNAT, and if not, move on to check the NAT list.
  2. From step 2, does that error mean that an origin address can only appear in one NAT rule system-wide?

15 Replies

  • probably you do not need irule. 🙂

    e.g.

     

     internal to external
    
    ltm virtual internal-to-external {
        destination 10.8.8.0:0
        ip-forward
        mask 255.255.255.0
        profiles {
            fastL4 { }
        }
        source 10.8.4.26/32
        source-address-translation {
            pool snat-10.8.8.22
            type snat
        }
        translate-address disabled
        translate-port disabled
        vlans {
            internal
        }
        vlans-enabled
        vs-index 15
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snatpool snat-10.8.8.22
    ltm snatpool snat-10.8.8.22 {
        members {
            10.8.8.22
        }
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snat-translation 10.8.8.22
    ltm snat-translation 10.8.8.22 {
        address 10.8.8.22
        inherited-traffic-group true
        traffic-group traffic-group-1
    }
    
     internal to pubdmz
    
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm virtual internal-to-pubdmz
    ltm virtual internal-to-pubdmz {
        destination 10.8.6.0:0
        ip-forward
        mask 255.255.255.0
        profiles {
            fastL4 { }
        }
        source 10.8.4.26/32
        source-address-translation {
            pool snat-10.8.6.26
            type snat
        }
        translate-address disabled
        translate-port disabled
        vlans {
            internal
        }
        vlans-enabled
        vs-index 16
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snatpool snat-10.8.6.26
    ltm snatpool snat-10.8.6.26 {
        members {
            10.8.6.26
        }
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snat-translation 10.8.6.26
    ltm snat-translation 10.8.6.26 {
        address 10.8.6.26
        inherited-traffic-group true
        traffic-group traffic-group-1
    }
    
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm virtual pubdmz-to-internal
    ltm virtual pubdmz-to-internal {
        destination 10.8.6.26:0
        mask 255.255.255.255
        pool pool-10.8.4.26
        profiles {
            fastL4 { }
        }
        source 10.8.6.0/24
        translate-port disabled
        vlans {
            pubdmz
        }
        vlans-enabled
        vs-index 17
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm pool pool-10.8.4.26
    ltm pool pool-10.8.4.26 {
        members {
            10.8.4.26:0 {
                address 10.8.4.26
            }
        }
    }
    
     pubdmz to 10.8.4.26 on port 5600
    
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm virtual pubdmz-to-10.8.4.26
    ltm virtual pubdmz-to-10.8.4.26 {
        destination 10.8.4.26:5600
        ip-forward
        ip-protocol tcp
        mask 255.255.255.255
        profiles {
            fastL4 { }
        }
        source 10.8.6.0/24
        translate-address disabled
        translate-port disabled
        vlans {
            pubdmz
        }
        vlans-enabled
        vs-index 18
    }
    

     

    • branfarm_139474's avatar
      branfarm_139474
      Icon for Nimbostratus rankNimbostratus
      Thanks, Nitass. Those are very thorough examples. My intent is to have something that's more generic -- my diagram was more of a conceptual example. The real need for the external interface is to allow outbound traffic to the internet -- all prefixes. However, the dmz and other interfaces will need more specific prefixes, possibly hundreds of different prefixes per interface. I can't create virtual-servers for each destination prefix however. In that case, it seems like I might not be able to use this method for a production system since the virtual servers you reference are very specific to the source and destination networks. In your opinion, is this a case of "trying to make a square peg fit a round hole?"
  • probably you do not need irule. 🙂

    e.g.

     

     internal to external
    
    ltm virtual internal-to-external {
        destination 10.8.8.0:0
        ip-forward
        mask 255.255.255.0
        profiles {
            fastL4 { }
        }
        source 10.8.4.26/32
        source-address-translation {
            pool snat-10.8.8.22
            type snat
        }
        translate-address disabled
        translate-port disabled
        vlans {
            internal
        }
        vlans-enabled
        vs-index 15
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snatpool snat-10.8.8.22
    ltm snatpool snat-10.8.8.22 {
        members {
            10.8.8.22
        }
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snat-translation 10.8.8.22
    ltm snat-translation 10.8.8.22 {
        address 10.8.8.22
        inherited-traffic-group true
        traffic-group traffic-group-1
    }
    
     internal to pubdmz
    
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm virtual internal-to-pubdmz
    ltm virtual internal-to-pubdmz {
        destination 10.8.6.0:0
        ip-forward
        mask 255.255.255.0
        profiles {
            fastL4 { }
        }
        source 10.8.4.26/32
        source-address-translation {
            pool snat-10.8.6.26
            type snat
        }
        translate-address disabled
        translate-port disabled
        vlans {
            internal
        }
        vlans-enabled
        vs-index 16
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snatpool snat-10.8.6.26
    ltm snatpool snat-10.8.6.26 {
        members {
            10.8.6.26
        }
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm snat-translation 10.8.6.26
    ltm snat-translation 10.8.6.26 {
        address 10.8.6.26
        inherited-traffic-group true
        traffic-group traffic-group-1
    }
    
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm virtual pubdmz-to-internal
    ltm virtual pubdmz-to-internal {
        destination 10.8.6.26:0
        mask 255.255.255.255
        pool pool-10.8.4.26
        profiles {
            fastL4 { }
        }
        source 10.8.6.0/24
        translate-port disabled
        vlans {
            pubdmz
        }
        vlans-enabled
        vs-index 17
    }
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm pool pool-10.8.4.26
    ltm pool pool-10.8.4.26 {
        members {
            10.8.4.26:0 {
                address 10.8.4.26
            }
        }
    }
    
     pubdmz to 10.8.4.26 on port 5600
    
    root@(ve11a)(cfg-sync In Sync)(Active)(/Common)(tmos) list ltm virtual pubdmz-to-10.8.4.26
    ltm virtual pubdmz-to-10.8.4.26 {
        destination 10.8.4.26:5600
        ip-forward
        ip-protocol tcp
        mask 255.255.255.255
        profiles {
            fastL4 { }
        }
        source 10.8.6.0/24
        translate-address disabled
        translate-port disabled
        vlans {
            pubdmz
        }
        vlans-enabled
        vs-index 18
    }
    

     

    • branfarm_139474's avatar
      branfarm_139474
      Icon for Nimbostratus rankNimbostratus
      Thanks, Nitass. Those are very thorough examples. My intent is to have something that's more generic -- my diagram was more of a conceptual example. The real need for the external interface is to allow outbound traffic to the internet -- all prefixes. However, the dmz and other interfaces will need more specific prefixes, possibly hundreds of different prefixes per interface. I can't create virtual-servers for each destination prefix however. In that case, it seems like I might not be able to use this method for a production system since the virtual servers you reference are very specific to the source and destination networks. In your opinion, is this a case of "trying to make a square peg fit a round hole?"
  • i am still thinking it can be done using virtual server, snat and irule. you can have wildcard virtual server matching all traffic and use irule to granular control whatever network address translation you want.

     

    • branfarm_139474's avatar
      branfarm_139474
      Icon for Nimbostratus rankNimbostratus
      Ok. Thinking about traffic from internal to somewhere else (external, pubdmz, etc). Would you create one virtual-server as a catch-all, and then one virtual-server that used an irule that attempted to match on a number of different data groups? Each data group would contain the destination prefixes for each NAT? Or would everything have to be done in one virtual-server?
  • i am still thinking it can be done using virtual server, snat and irule. you can have wildcard virtual server matching all traffic and use irule to granular control whatever network address translation you want.

     

    • branfarm_139474's avatar
      branfarm_139474
      Icon for Nimbostratus rankNimbostratus
      Ok. Thinking about traffic from internal to somewhere else (external, pubdmz, etc). Would you create one virtual-server as a catch-all, and then one virtual-server that used an irule that attempted to match on a number of different data groups? Each data group would contain the destination prefixes for each NAT? Or would everything have to be done in one virtual-server?
  • Would you create one virtual-server as a catch-all, and then one virtual-server that used an irule that attempted to match on a number of different data groups? Each data group would contain the destination prefixes for each NAT? Or would everything have to be done in one virtual-server?

     

    we cannot have multiple virtual servers with the same destination and source. in that case, we can use one wildcard virtual server and use irule to selectively snat.

     

    • branfarm_139474's avatar
      branfarm_139474
      Icon for Nimbostratus rankNimbostratus
      Would this be the right irule for the outbound snat portion? when CLIENT_ACCEPTED { if {[class match [IP::local_addr] equals pubdmz_prefixes] } { snatpool snat-pubdmz-10.8.6.26 } elseif {[class match [IP::local_addr] equals dmz_prefixes] } { snatpool snat-dmz-10.8.5.26 } elseif {[class match [IP::local_addr] equals partner_prefixes] } { snatpool snat-partner-10.8.7.26 } else { snatpool snat-external-10.8.8.22 } }
  • Would you create one virtual-server as a catch-all, and then one virtual-server that used an irule that attempted to match on a number of different data groups? Each data group would contain the destination prefixes for each NAT? Or would everything have to be done in one virtual-server?

     

    we cannot have multiple virtual servers with the same destination and source. in that case, we can use one wildcard virtual server and use irule to selectively snat.

     

    • branfarm_139474's avatar
      branfarm_139474
      Icon for Nimbostratus rankNimbostratus
      Would this be the right irule for the outbound snat portion? when CLIENT_ACCEPTED { if {[class match [IP::local_addr] equals pubdmz_prefixes] } { snatpool snat-pubdmz-10.8.6.26 } elseif {[class match [IP::local_addr] equals dmz_prefixes] } { snatpool snat-dmz-10.8.5.26 } elseif {[class match [IP::local_addr] equals partner_prefixes] } { snatpool snat-partner-10.8.7.26 } else { snatpool snat-external-10.8.8.22 } }
  • Would this be the right irule for the outbound snat portion?

     

    it looks okay to me.

     

    anyway, if there is only one member in snatpool, you can just use snat command instead but you have to create snat translation and enable arp. snatpool automatically creates snat translation.

     

  • First off, thank you for your assistance with this -- I really appreciate the time you're taking to respond.

     

    I think I'm confusing myself though -- the above irule assumes everything coming through that wildcard virtual-server will only ever use a traditional SNAT. What if some of the source servers need a 1:1 snat? Does this have to become one giant monolithic irule, where every case specific case is handled in an elseif clause? Or would you then create more source-specific virtual servers for anything that needed a 1:1 SNAT on any of the interfaces?

     

  • What if some of the source servers need a 1:1 snat?

     

    i think using snat instead of nat is easier to control because, you want, some client has multiple ip (e.g. one nat and one snat). since you are going to use snat for 1-to-1, you also need to create another virtual server to accept traffic initiated from external (inbound traffic).

     

    Does this have to become one giant monolithic irule, where every case specific case is handled in an elseif clause? Or would you then create more source-specific virtual servers for anything that needed a 1:1 SNAT on any of the interfaces?

     

    each has pro and cons. if i were you, i would pick the one i feel comfortable in maintaining it. :)