Forum Discussion
RoutingLoop_179
Cirrus
Mar 07, 2013Dynamic 1:1 SNAT irule
Hi guys - looking for some feedback regarding my irule for 1:1 dynamic NAT. e.g we might use 10/8 on the client inside but then have only have a /17 pool on public outside, although over allocated t...
RoutingLoop_179
Cirrus
Aug 19, 2013cont...
loop through subnet until octet3 has reached it's maximum allocated value
while {$::oct3 <= $static::oct3end} {
set ip 217.39.$::oct3.$::oct4
if { [table lookup -notouch -subtable "DynNatAddreses" $ip] eq "" } {
log local0. "Free IP: $ip found added to clientDynNat table"
reserve the Free IP
table add -subtable "DynNatAddreses" $ip [IP::client_addr] $static::timeout
allocate the Free IP as client SNAT address
table add -subtable "ClientDynNat" [IP::client_addr] $ip $static::timeout
debugging
if {$static::debug} {
log local0. "table lookup in DynNatAddress for $ip: [table lookup -notouch -subtable "DynNatAddreses" $ip]"
log local0. "table remaining ClientDynNat for [IP::client_addr]: [table timeout -subtable "ClientDynNat" -remaining [IP::client_addr]]"
log local0. "table timeout DynNatAddreses for $ip: [table timeout -subtable "DynNatAddreses" -remaining $ip]"
}
SNAT the client to the free IP
snat $ip
break the loop - found and allocated a address so no point in cycling through rest of Pool of IP's
break
}
increment the last octect of pool
incr ::oct4
if last octect has reached the end of the range increment next octet of IP and start looping through again
if {$::oct4 > $static::oct4end} {
incr ::oct3
set ::oct4 0
}
}
}
}
- Vladimir_Bojko1Nov 26, 2013Historic F5 AccountHi, I have checked your iRule and it works quite well. the only thing that can happen is a race condition when two clients at the same time lookup the same IP and then write their IPs in the sable. to prevent this you anc use following statemen instead: if { [table add -subtable "DynNatAddreses" $ip [IP::client_addr] $static::timeout] eq "[IP::client_addr]" } { log local0. "Free IP: $ip found added to clientDynNat table" allocate the Free IP as client SNAT address table add -subtable "ClientDynNat" [IP::client_addr] $ip $static::timeout When you use the "table add" statement instead. If the entry already exists it is not inserted. If the entry does not exist it will add the table entry. Anyhow the response is the key value. You hae to check if the response equals the client IP you try to acces. If so add the second table entry, if not go to the next step.
- Vladimir_Bojko1Nov 26, 2013Historic F5 Accounthere my iRule: timing on for testing timing on when RULE_INIT { set ::oct3 1 set ::oct4 1 set static::oct3end 1 set static::oct4end 255 set static::timeout 60 set static::debug 1 } when CLIENT_ACCEPTED { debugging if {$static::debug} { foreach key [table keys -subtable "ClientDynNat" -notouch] { log local0. "table ClientDynNat key: $key" } } if { [set SnatTo [table lookup -subtable "ClientDynNat" [IP::client_addr]]] ne "" } { to reset idle timeout of dynamic NAT address so it's not re-allocated until client SNAT times out. table lookup -subtable "DynNatAddreses" $SnatTo log local0. "Found exisiting snat in ClientDynNat for [IP::client_addr]: [table lookup -notouch -subtable "ClientDynNat" [IP::client_addr]]" debugging if {$static::debug} { log local0. "table lookup in DynNatAddress for $SnatTo: [table lookup -notouch -subtable "DynNatAddreses" $SnatTo]" log local0. "table remaining ClientDynNat for [IP::client_addr]: [table timeout -subtable "ClientDynNat" -remaining [IP::client_addr]]" log local0. "table remaining DynNatAddress for $SnatTo: [table timeout -subtable "DynNatAddreses" -remaining $SnatTo]" } snat $SnatTo log local0. "deleting dynnats in tables" table delete -subtable "ClientDynNat" -all table delete -subtable "DynNatAddreses" -all } else { debugging if {$static::debug} { foreach key [table keys -subtable "DynNatAddreses" -notouch] { log local0. "table DynNatAddreses key: $key" } log local0. "DynNatAddress table count -- [table keys -subtable "DynNatAddreses" -count]" log local0. "no snat for [IP::client_addr]" } loop through subnet until octet3 has reached it's maximum allocated value while {$::oct3 <= $static::oct3end} { set ip 217.39.$::oct3.$::oct4 if { [table add -subtable "DynNatAddreses" $ip [IP::client_addr] $static::timeout] eq "[IP::client_addr]" } { log local0. "Free IP: $ip found added to clientDynNat table" allocate the Free IP as client SNAT address table add -subtable "ClientDynNat" [IP::client_addr] $ip $static::timeout debugging if {$static::debug} { log local0. "table lookup in DynNatAddress for $ip: [table lookup -notouch -subtable "DynNatAddreses" $ip]" log local0. "table lookup in ClientDyn Nat for [IP::client_addr]: [table lookup -subtable "ClientDynNat" [IP::client_addr]]" log local0. "table remaining ClientDynNat for [IP::client_addr]: [table timeout -subtable "ClientDynNat" -remaining [IP::client_addr]]" log local0. "table timeout DynNatAddreses for $ip: [table timeout -subtable "DynNatAddreses" -remaining $ip]" } SNAT the client to the free IP snat $ip break the loop - found and allocated a address so no point in cycling through rest of Pool of IP's break } increment the last octect of pool incr ::oct4 if last octect has reached the end of the range increment next octet of IP and start looping through again if {$::oct4 > $static::oct4end} { incr ::oct3 set ::oct4 0 } } } }
- Vladimir_Bojko1Nov 26, 2013Historic F5 AccountIn my case I needed also to allow incomming connections on to the clinet IPs. So I had to do only Address translation without port translation. To do this I defined one network virtual server on the external VLAN of type performanceL4. Destination IP is the IP range you defined in the iRule, here: 217.39/16. Important: You have to enable Address translation, which is per default disabled with netwrok virtuals here an example: ltm virtual CGNAT1-incomming { destination 217.39.0.0:any mask 255.255.0.0 profiles { fastL4 { } } rules { dynamic_NAT_incomming } source 0.0.0.0/0 translate-port disabled vlans { external } vlans-enabled vs-index 29 } then you add following iRule to it: when CLIENT_ACCEPTED { node [table lookup -subtable "DynNatAddreses" [IP::local_addr]] } now the 1:1 IP address translations works bidirectional. btw, testet with 11.4.1 regards
- Vladimir_Bojko1Nov 26, 2013Historic F5 AccountHi, I kept working on the iRule and I have a version that uses the session tables instead of subtables and therefore it is more CMP friendly. In your version of code there was no translation exhaustion mechanism protection included. In case all IPs were used the system just forwarded the client to the internet without NAT and without any feedback to admin. In my code the client will be droppd and a log to admin will be fired. here is my code. any comments are welcome. Dynamic_1:1 NAT iRule this iRule bases on the iRule https://devcentral.f5.com/s/feed/0D51T00006i7QuuSAE changes in the iRule in comparison to the Web 1. moving all global variables to session variables 2. fixing race condition 3. adding check if IP address range is exhausted and dropping connection instead of forwarding without NAT 4. replacing subtables with table variables timing on for testing timing on when CLIENT_ACCEPTED { set oct3 1 set oct4 1 set oct3end 1 set oct4end 255 set timeout 180 set debug 1 debugging if {$debug} { foreach key [table keys -subtable "ClientDynNat" -notouch] { log local0. "table ClientDynNat key: $key" } } if { [set SnatTo [table lookup [IP::client_addr]]] ne "" } { to reset idle timeout of dynamic NAT address so it's not re-allocated until client SNAT times out. table lookup $SnatTo log local0. "Found exisiting snat for [IP::client_addr]: [table lookup [IP::client_addr]]" snat $SnatTo } else { loop through subnet until octet3 has reached it's maximum allocated value while {$oct3 <= $oct3end} { set ip 217.39.$oct3.$oct4 log local0. "Current tested SNAT IP: $ip" if { [table add $ip [IP::client_addr] $timeout] eq "[IP::client_addr]" } { log local0. "Free IP: $ip found added to clientDynNat table" allocate the Free IP as client SNAT address table add [IP::client_addr] $ip $timeout SNAT the client to the free IP snat $ip break the loop - found and allocated a address so no point in cycling through rest of Pool of IP's break } increment the last octect of pool incr oct4 if last octect has reached the end of the range increment next octet of IP and start looping through again if {$oct4 > $oct4end} { incr oct3 set oct4 0 } if {($oct3 > $oct3end)}{ log local0. "translation IP addresses exhauseted. No transpation IP for [IP::client_addr] available." drop } } } }
- Vladimir_Bojko1Nov 26, 2013Historic F5 Accounthere is the changed iRule for incomming traffic. I identified that there are error log messages if users from the internet try to access not mapped translation addresses. In this code you can decide if you want this to be logged with more information or if it should be dropped silently (just comment the log statement). as before: any comments are welcome: This iRule is used together with dynamic_NAT 1:1 iRule from Devcentral https://devcentral.f5.com/s/feed/0D51T00006i7QuuSAE The use case of this iRule is to make sure that inbound connections from the Internet are send to the internal IP that created the address reservation. This incomming iRule does not uses subtables, it uses the session table instead. The advantage of this irule is that connections to non translates IP addresses are not creating log messages in LTM log as long as the log statement is not uncommented. when CLIENT_ACCEPTED { switch -glob [table lookup [IP::local_addr]] { "" { log local0. "dropping packet for not translated IP [IP::local_addr] from [IP::client_addr]" drop} default {node [table lookup [IP::local_addr]]} } }
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects
