Dynamic RAWNAT: Episode 2

Since I have blogged about the Dynamic RAWNAT that it's nearly 2 years ago. The problem that I could remember is it's always crash on the SMP system and at that time, I have no any experiences to solve the concurrent processing, eg. mutex lock, read/write lock, semaphore. Therefore, this code has not been used in any productions system yet, actually it is developed for the KKU Network (Khon Kaen University Network) but the quality is poor, thus should be pending.

Fortunately, there are big improvements in ipset which now leaps to the version 6.11. The code is easier to follow and the new redesigned userland tool is elegant. Thanks to Jozsef Kadlecsik and the people behind the ipset.

Hence, I have started to migrate the Dynamic RAWNAT code to ipset 6.x again.

First part: ipset hacked
I have to add the storage set. The first time, I have coded the hash:ipip which derived from hash:ipportip type and sent it to ipset team. I have got some advices that I could not use the hash:ipip for the purpose of lookup table since the hash code of ipset using both IP for the hash key calculation.

Therefore, I have started over again to create the hash:iplookup which modify the hash function of the original ipset. Then I have the storage set for both IPv4/IPv6.

# ipset -
ipset> create test hash:iplookup
ipset> list test
Name: test
Type: hash:iplookup
Header: family inet hashsize 1024 maxelem 65536 
Size in memory: 16504
References: 0
Members:
ipset> add test 192.168.11.165 map-to 192.168.11.64
ipset> add test 192.168.11.64 map-to 192.168.11.165
ipset> list test
Name: test
Type: hash:iplookup
Header: family inet hashsize 1024 maxelem 65536 
Size in memory: 16568
References: 0
Members:
192.168.11.165 map-to 192.168.11.64
192.168.11.64 map-to 192.168.11.165
ipset> test test 192.168.11.165
192.168.11.165 is in set test.

Second part: modify RAWNAT target
The SETRAWNAT was inspired by the RAWNAT target (RAWSNAT, RAWDNAT) which included in the xtables-addons package. I have also started to get the SETRAWNAT done by migrate the old code to new ipset APIs.
This time, ipset also provides the APIs to access the set data which I have no need to hack the core APIs anymore :).

# iptables -t raw -A PREROUTING -m set --match-set test dst -j SETRAWDNAT --bind-set test
# iptables -t rawpost -A POSTROUTING -m set --match-set test src -j SETRAWSNAT --bind-set test

Lab test:
In the lab test, I used farpd to spoof the arp reply for the router arp request for the IP 192.168.11.165 and it's work like a charm.

# farpd -i wlan0 192.168.11.0/24
# tcpdump -i wlan0 host 192.168.11.165
=== 8< ===
...
...
11:24:25.401992 IP channel-138-143.01.snc6.tfbnw.net.https > 192.168.11.165.35544: Flags [.], ack 127139, win 181, options [nop,nop,TS val 881459662 ecr 24205990], length 0
11:24:26.293708 IP 192.168.11.165.57338 > baymsg1010827.gateway.edge.messenger.live.com.msnp: Flags [P.], seq 1099:1104, ack 31585, win 64800, options [nop,nop,TS val 24206278 ecr 208471411], length 5
11:24:26.554042 IP baymsg1010827.gateway.edge.messenger.live.com.msnp > 192.168.11.165.57338: Flags [P.], seq 31585:31593, ack 1104, win 63683, options [nop,nop,TS val 208476039 ecr 24206278], length 8
11:24:26.554183 IP 192.168.11.165.57338 > baymsg1010827.gateway.edge.messenger.live.com.msnp: Flags [.], ack 31593, win 64800, options [nop,nop,TS val 24206343 ecr 208476039], length 0
...
...
=== >8 ===

And also the packets pass-through the iptables rules

# watch -n5 'iptables -t raw -nvL PREROUTING; iptables -t rawpost -nvL POSTROUTING'
Every 5.0s: iptables -t raw -nvL PREROUTING; iptabl...  Tue Feb 14 11:26:19 2012

Chain PREROUTING (policy ACCEPT 560K packets, 297M bytes)
 pkts bytes target     prot opt in     out     source               destination

 226K  233M SETRAWDNAT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
          match-set test dst bind-set test
Chain POSTROUTING (policy ACCEPT 483K packets, 71M bytes)
 pkts bytes target     prot opt in     out     source               destination

 198K   26M SETRAWSNAT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
          match-set test src bind-set test

I have to review the code before commit to git.rahunas.org as it should be included in the RahuNAS 2.0 development.

There are a lot of works to get the RahuNAS 2.0 done but it's a good starting point to get the old problem solved :P