3

Given the following installation:

old router  192.168.1.1     with NAT forward of tcp port 80 to 192.168.1.10:80
new router  192.168.1.2     with NAT forward of tcp port 80 to 192.168.1.10:80
web server  192.168.1.10    with default gateway 192.168.1.1

Currently, the DNS entry for my service points to the external address of the old router. The router does a port forwarding of the traffic to the web server which returns the answer back to the old gateway.

For a seamless migration to a new router (with another external IP), I want to setup a new router first, test the whole thing with both connections active, and then change the DNS IP to the new external address.

Now, with the above setup, the old router still works. But tcp connections which are addressed to the new router, are also answered to the old router which cannot handle them.

I thought about using nat with masquerading but then all traffic which is addressed to the new router will look like local traffic. This tricks out server ip-based filters and logging.

Now, my plan is to use a helper PC with Debian and iptables for a temporary solution:

old router  192.168.1.1     with NAT forward of tcp port 80 to 192.168.1.10:80
new router  192.168.1.2     with NAT forward of tcp port 80 to 192.168.1.20:80
web server  192.168.1.10    with default gateway 192.168.1.20
helper pc   192.168.1.20

the helper pc is now responsible for finding the correct gateway:

  • keep state of connections which were forwarded by 192.168.1.2 and forward them without modifying to 192.168.1.10 (i think about identifying them by their origin mac address and SYN)
  • forward packets of tracked connections to 192.168.1.2
  • forward packets of not-tracked connections to 192.168.1.1

I found a lot of input in the internet and especially serverfault.com (especially this one), but all of them cover only a single part of this problem. I guess it needs a combination of mac address based filter rules -m mac --mac-source <mac>, NAT, states and rt_tables --set-mark / ip rule add fwmark (--gw doesn't seem to be supported by Debian).

  • There are several possible solutions I can think of, and one of them doesn't even require a 'helper PC' provided that the webserver is a Linux machine. What's the OS of the webserver? – pepoluan Jan 21 '14 at 18:46
  • The webserver is a windows machine, and I have to use the same scenario for a Barracuda Spam Filter. That's why I'm looking for a 'helper pc' solution. Your answer below is going in the direction I'm looking for (Solution 2). Hope I find the time to check that out tomorrow. – Daniel Alder Jan 22 '14 at 20:00
  • ah, I see. I'll re-review my answer and update it to help. – pepoluan Jan 23 '14 at 8:44
  • I've edited my answer. – pepoluan Jan 23 '14 at 9:02
3

There are two effective solutions, depending on the scenario.

Solution 1: The webserver is Linux and fully under your control.

First, ensure that /etc/iproute2/rt_tables contains the following lines:

201     gw1
202     gw2

Second, populate the tables

ip route add table gw1 default via $GW1_IP dev $ETH metric 100
ip route add table gw2 default via $GW2_IP dev $ETH metric 100

Third, create two iproute2 rules to 'shunt' processing to those custom tables:

ip rule add prio 100 from all fwmark 1 lookup gw1
ip rule add prio 110 from all fwmark 2 lookup gw2

Finally, create the set of iptables commands to mark the corresponding packets properly:

# Make sure mark exists before routing happens
#   The first handles incoming packets
-t mangle -A PREROUTING -j CONNMARK --restore-mark
#   The second handles outgoing packets
-t mangle -A OUTPUT     -j CONNMARK --restore-mark

# Mark packets and save the mark    
-t mangle -A INPUT -m mac --mac-source $GW1_MAC -j MARK --set-mark 1
-t mangle -A INPUT -m mac --mac-source $GW2_MAC -j MARK --set-mark 2
-t mangle -A INPUT -j CONNMARK --save-mark

Solution 2: The webserver is not Linux and/or it is not fully under your control

This solution is very similar to the previous solution. The difference is in the set of iptables rules:

# Make sure mark exists before routing happens
-t mangle -A PREROUTING -j CONNMARK --restore-mark

# Mark packets and save the mark    
-t mangle -A FORWARD -m mac --mac-source $GW1_MAC -j MARK --set-mark 1
-t mangle -A FORWARD -m mac --mac-source $GW2_MAC -j MARK --set-mark 2

-t mangle -A POSTROUTING -j CONNMARK --save-mark

Edit: Modified Solution 2

Still the same as the above, but add:

ip rule add prio 10 to 192.168.1.0/24 lookup main

this ensures that packets destined for the local network (I'm assuming 192.168.1.0/24) will not be handled by the gateways.

Also, add another iptables rule:

-t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10

Finally, have both gateways forward port 80 to the 'helper pc'; it will save a great deal of headache trying to troubleshoot 'half-open' connections (because, in your current plan the 'helper pc' can only see traffic originating from the webserver instead of traffic going bothways).

  • 1
    Thanks, this works perfectly. There was only a little piece missing, which is probably totally clear for you: echo 1 > /proc/sys/net/ipv4/ip_forward. Btw the best command for debugging for me was tcpdump -pfe -n tcp port 80 (it helped to find out that I used the wrong mac address :-) ) – Daniel Alder Jan 24 '14 at 17:47
  • Glad to hear the rules work :-) – pepoluan Jan 26 '14 at 14:32
  • 1
    Final report: At the end, I didn't use this solution because of different off-topic problems like ip blacklists on remote side which made debugging extremely complicated. Finally I was happy for every possible source of problems which I was able to exclude, so I chose a hard switchover with a short downtime. – Daniel Alder Sep 21 '14 at 20:57
0

If it's for a local test only you could use -s option of iptables to tell your old router that if the traffic originate from that source IP, forward it to the new router. Then your new router will be forwarding your request to the web server (based on the configuration you provided).

Even if you are testing from outside you setup, you can still filter your source address ip with -s.

Example:

iptables -I PREROUTING -i eth0 -s x.x.x.x -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.1.2:80
  • 1) I guess you mean 192.168.1.10 as destination? 2) it's not only a test: changes in dns can take very long time, and I even have to request the change externally. And if something goes wrong, I have to change back, and all this with minimal downtime – Daniel Alder Jan 15 '14 at 21:23
  • Nop I meant 192.168.1.2 but I think I'm missing some info to fully guide you on what you want to achieve. The main idea of what I was suggesting can be shown with this flow. IP > Old Router > New Router > Web Server 1) Are both routers configured with a public IP or they are behind a nat? (Is this a hosted server or it's a computer at your home) 2) Is yes than you can only test your local computer host file to point to the IP of your new router instead of changing the DNS entry. – typositoire Jan 15 '14 at 22:30
  • 1) Both routers are connected to the internet. Old Router > New router will not work because packets will be returned with a different external IP than the original one 2) The test will fail. Because NAT will fail. I will test the new route by using the IP, not the DNS, so the whole question is not a DNS question. – Daniel Alder Jan 16 '14 at 8:32
  • You misunderstood my question: Both routers have their own public ip assign to them ? – typositoire Jan 16 '14 at 11:06
  • oh. yes, both are connected to the internet and have their own official ip address. but from different providers. 192.168.1.2 is planned to become the new default gateway for the network. the old router and the helper pc will be removed after switchover – Daniel Alder Jan 16 '14 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.