Ckpool proxy mode dual-ISP balancing

Experience shows that planning 24/7 availability systems requires great attention to detail and sometimes use of black magic. Especially when you prefer to sleep instead of manually switching between ISPs. Sometimes software has limitations on setups, and one such limitation was found in CKPool software, that didn’t allow to setup source addresses for Pool connections. And here is an example of one magic trick

Let’s assume the following setup:

  1. One destination address and one destination port for the application (e.g. 54.205.207.15 port 3333)
  2. Two (or more) gateways, each is a separate logical connection (not necessary to be a separate interface)

Principal topology diagram:

1. Let’s create “virtual” destination addresses, e.g:

  • 10.210.0.1/32
  • 10.210.0.2/32

2. Each virtual destination we route via different gateways:

ip route add 10.210.0.1/32 via 192.168.0.1
ip route add 10.210.0.2/32 via 192.168.1.1

3. Now we add magic, and masquerade the virtual destinations to the original one:

iptables -I OUTPUT -d 10.210.0.1/32 -p tcp -j DNAT –to-destination 54.205.207.15 -t nat
iptables -I OUTPUT -d 10.210.0.2/32 -p tcp -j DNAT –to-destination 54.205.207.15 -t nat

4. In our application, setup two connections, each to the virtual address:

“proxy” : [
{
“url” : “10.210.0.1:3333”,
“auth” : “username.worker”,
“pass” : “pass”
},
{
“url” : “10.210.0.2:3333”,
“auth” : “username.worker”,
“pass” : “pass”
},
]

Explanation:
In the Linux sybsystem, the routing decision is performed at an early stage, so the gateway for the  packets to our virtual destinations will be chosen prior to any manipulation or filtering. Here is a good visual explanation – https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg

By setting up Destination NAT we change the packet so it gets the right destination address and will be the same as if it wasn’t altered at all. And since the routing decision is already in place, it will be send to the necessary gateway.

It is fair to say that this solution will create some additional overhead in the process, but it is much faster that enhancing code, isn’t it?