How to setup NAT on a linux host connecting two cloned networks

by Johannes Braunias   Last Updated July 12, 2019 12:00 PM - source

I have two cloned networks (lan1 and lan2) used for testing purposes, each with the same address space 10.20.80.0/22:

# 10.20.80.0/22
10.20.80.0    # first address
...
10.20.83.254  # last address

They are not connected and not meant to be connected in terms of switches.
But I want to have a means to move between lan1 and lan2 through SSH. (From lan1 on host alpha, do an ssh mars and from there on do an ssh alpha.lan2.) So I use a (CentOS 7) linux host named mars as an SSH hop:

  • mars is attached to both lans lan1and lan2 and listed in both lans’ /etc/hosts with the address 10.20.80.55 mars
  • Has the two NICs em1 and em2.
    em1 belongs to lan1.
    em2 belongs to lan2.

/etc/hosts of all computers on lan1 and on lan2:

10.20.80.1  alpha
10.20.80.2  beta
...
10.20.80.55 mars  # ssh gateway connected to lan1 and lan2

Approach 1: ip netns (working)

(Quick readers skip to approach 3)

I used ip network namespaces to separate the network interfaces

It looks like that:

Host 'mars' with 3 network namespaces
|------------------------------------------------------------------------|
|[default/root netns]                                                    |
|                                                                        |
|                                                               lo       |
|                                                               127.0.0.1|
|------------------------------------------------------------------------|
|---------------------------------|    |---------------------------------|
|[netns lan1]                     |    |[netns lan2]                     |
|                          lo     |    |                          lo     |
|                        127.0.0.1|    |                        127.0.0.1|
|      sshd1                      |    |     sshd2                       |
|                                 |    |                                 |
|10.20.80.55/22 em1 (physical)    |    |10.20.80.55/22 em2 (physical)    |
|----------|----------------------|----|----------|----------------------|
           |                                      |
  Network 10.20.80.0/22 (lan1)           Network 10.20.80.0/22 (lan2)

This basically works and now I can go do the following from host alpha in lan1:

ssh mars
ip netns exec lan2 bash    # Opens a bash in the network namespace 'lan2'
ssh alpha

Voilà, I arrived at host alpha in lan2!

Drawbacks:

  • Services on host mars (like ntpd) run in the default network namespace, which only has the loopback interface lo and therefore cannot contact any other ntp peer.
  • sshd has to be started for each namespace
  • No proxy jumping with ssh from lan1 to lan2

Code:

Remove all netns (for repeated attempts):

#!/bin/bash
for netns in $(ip netns | awk '{print $1}'); do
  for pid in $(ip netns pids $netns); do
    kill $pid
  done
  ip netns del $netns
done

Setup netns lan1:

ip netns add lan1
ip link set em1 netns lan1
ip netns exec lan1 ip addr add 10.20.80.55/22 dev em1
ip netns exec lan1 ip link set em1 up
ip netns exec lan1 link set lo up
ip netns exec lan1 /usr/sbin/sshd -o PidFile=/var/run/sshd.lan1.pid

Setup netns lan2:

ip netns add lan2
ip link set em1 netns lan2
ip netns exec lan2 ip addr add 10.20.80.55/22 dev em1
ip netns exec lan2 ip link set em1 up
ip netns exec lan2 link set lo up
ip netns exec lan2 /usr/sbin/sshd -o PidFile=/var/run/sshd.lan2.pid

This created two network namespaces (netns lan1 and netns lan2), added a loopback interface to each netns and moved the hardware interfaces em1 and em2 to each respective netns (network namespace). Moreover it started an SSH Daemon so that each NIC is reachable.

Approach 2: use NAT on the host-in-the-middle

Instead of using network namespaces, I want to ssh mars from lan1 and from mars continue with another ssh alpha.lan2 into lan2 (and vice versa). So I can use host 'mars' as a proxy for ssh and do ssh jumping with ssh -J mars alpha.lan2, also for scp or X-forwarding.

Host 'mars'
|------------------------------------------------------------------------|
|[default/root netns]                                                    |
|                                                               lo       |
|                                                               127.0.0.1|
|                                                                        |
|192.168.4.55 em1 (physical)            192.168.8.55 em2                 |
|iptables NAT to 10.20.80.55/22?        iptables NAT to 10.20.80.55/22?  |
|----------|--------------------------------------|----------------------|
           |                                      |
  Network 10.20.80.0/22 (lan1)           Network 10.20.80.0/22 (lan2)

I want to use NAT for that on mars. /etc/hosts on mars (not on the hosts on lan1 and lan2):

192.168.4.1  alpha.lan1
192.168.4.2  beta.lan1
192.168.4.55 mars.lan1  # ssh gateway connected to lan1 and lan2
192.168.8.1  alpha.lan2
192.168.8.2  beta.lan2
192.168.8.55 mars.lan2  # ssh gateway connected to lan1 and lan2

My idea is to map lan1 and lan2 to two distinct networks:

# 10.20.80.0/22 (lan1) -> 192.168.4.0/22  via NIC em1
# 10.20.80.0/22 (lan2) -> 192.168.8.0/22  via NIC em2
iptables -A PREROUTING  -i em1 -j NETMAP --to 192.168.4.0/24
iptables -A POSTROUTING -o em1 -j NETMAP --to 10.20.80.0/24

This fails. Questions:

  1. Could it work this way? Which IP addresses do I assign to em1 and em2? I assume I can’t assign the actual 10.20.80.55 to both em1 and em2 without using network namespaces, so I tried to assign the “mapped” addresses 192.168.4.55 (to em1) and 192.168.8.55 (to em2). But that means the NICs can’t be reached from neither lan1 nor lan2 (10.20.80.0/22).
    Or does it make sense to do the following?
ip address add 192.168.4.55/22 dev em1
ip address add 192.168.8.55/22 dev em2
ip address add 10.20.80.55/22 dev em1
ip address add 10.20.80.55/22 dev em2
  1. Which iptables rules do I need?
  2. Which routes do I set up finally?
  3. Or should I follow an approch 3 (below)?

Approach 3: use NAT with network namespaces

I think I probably need the following approach: I need 3 network namespaces (one for each of the two lans and one root namespace) in the following way:

3 network namespaces on host 'mars':

    |------------------------------------------------------------------------------------------------------|
    |127.0.0.1 lo                                                                      [default/root netns]|
    |                                                                                                      |
    |192.168.4.0/22                                       192.168.8.0/22                                   |
    |      ↓↑ (NAT with iptables NETMAP)                          ↓↑ (NAT with iptables NETMAP)              |
    |10.20.80.0/22                                        10.20.80.0/22                                    |
    |                                                                                                      |
    |192.168.0.1/24 v-root-em1 (virtual)                  192.168.0.2/24 v-root-em2 (virtual)              |
    |-------|----------------------------------------------------|-----------------------------------------|
            |                                                    |
    |-------|-----------------------------------------|  |-------|-----------------------------------------|
    |192.168.1.1/24 v-peer-em1 (virtual)  [netns lan1]|  |192.168.1.1/24 v-peer-em2 (virtual)  [netns lan2]|
    |                                                 |  |                                                 |
    |                                     127.0.0.1 lo|  |                                     127.0.0.1 lo|
    |                                                 |  |                                                 |
    |192.168.1.2/24                                   |  |192.168.1.2/24                                   |
    |      ↓↑ (NAT)                                   |  |      ↓↑ (NAT)                                   |
    |10.20.80.55/22 em1 (physical)                    |  |10.20.80.55/22 em2 (physical)                    |
    |----------|--------------------------------------|  |----------|--------------------------------------|
               |                                                    |
     Network 10.20.80.0/22 (lan1)                         Network 10.20.80.0/22 (lan2)

Used code to setup this approach:

# Setup netns lan1:
ip netns add lan1
ip link set em1 netns lan1
ip netns exec lan1 ip addr add 10.20.80.55/22 dev em1
ip netns exec lan1 ip link set em1 up
ip netns exec lan1 link set lo up

# Create virtual interfaces and bridges to connect the namespace lan2 to the default (root) namespace:
ip link add v-root-em1 type veth peer name v-peer-em1
ip link set v-peer-em1 netns lan1
ip                 addr add 192.168.0.1/24 dev v-root-em1
ip netns exec lan1 addr add 192.168.1.1/24 dev v-peer-em1
ip                 link set v-root-em1 up
ip netns exec lan1 link set v-peer-em1 up


# Setup netns lan2:
ip netns add lan2
ip link set em2 netns lan2
ip netns exec lan2 ip addr add 10.20.80.55/22 dev em2
ip netns exec lan2 ip link set em2 up
ip netns exec lan2 link set lo up


# Create virtual interfaces and bridges to connect the namespace lan2 to the default (root) namespace:
ip link add v-root-em2 type veth peer name v-peer-em2
ip link set v-peer-em2 netns lan2
ip                 addr add 192.168.0.2/24 dev v-root-em2
ip netns exec lan2 addr add 192.168.1.1/24 dev v-peer-em2
ip                 link set v-root-em2 up
ip netns exec lan2 link set v-peer-em2 up


# Configure lan1:
ip route add 192.168.4.0/22 via 192.168.0.1 dev v-root-em1
ip netns exec lan1 ip route add 192.168.4.0/22 dev em1                         # Outgoing to lan1 (10.20.80.0/22)
ip netns exec lan1 ip route add 192.168.0.0/24 via 192.168.1.1 dev v-peer-em1  # Route into default/root namespace

# Configure lan2:
ip route add 192.168.8.0/22 via 192.168.0.2 dev v-root-em2
ip netns exec lan2 ip route add 192.168.8.0/22 dev em1                         # Outgoing to lan1 (10.20.80.0/22)
ip netns exec lan2 ip route add 192.168.0.0/24 via 192.168.1.1 dev v-peer-em2  # Route into default/root namespace

### Code missing to set up NAT
  1. How and where would I need to set up iptables rules then?
  2. Would I need also a /22 network for the two namespaces 'lan1' and 'lan2' instead of a /24 one?

Thanks for your contributions.

Remarks:
I recommend to disable saving ssh host keys on 'mars' when using network namespaces because hosts keys from lan1 will conflict with host keys from lan2.



Related Questions


NAT to a network namespace in Linux

Updated August 18, 2017 07:00 AM

Forward port to virtual IP in namespace

Updated August 30, 2015 18:00 PM

Where find any docs about VRF in linux?

Updated March 15, 2019 21:00 PM

Restore namespace for adapters lost to LXC

Updated April 10, 2018 00:00 AM

How can I ping to namespace IP from outside?

Updated January 12, 2018 21:00 PM