I am trying to learn a bit about NAT translations in Linux, but I havent seen any proof-of-concept that was boiled down to as basic as possible.
Anyway. Here is a drawing of my setup:
I have a very basic router to the Internet. It can basically only do 2 things:
- Make a connection to the internet.
- Handout ip address on 1 subnet alone.
It cannot do static routing at all.
... and it does not even know what a IPv6 address looks like! (No kidding!)
What I want is to be able to connect to the Internet from Raspberry 3, but also being able connect from My Computer to the Raspberry 3 or any other device on the other subnet.
That gave me the idea to implement a 1:1 NAT on my Raspberry 4, where all ip adresses from the 192.168.10.x/24 range gets translated into 192.168.1.x/24 range.
That way it appears at least from my routers point of view that all hosts on the network belongs to the same subnet, since the address pool of 192.168.0.0/23 is from 192.168.0.0 to 192.168.1.255.
But how to go about it?
Is it enough to just add two rules to iptables on the raspberry 4 like:
iptables -t nat -A PREROUTING -d 192.168.10.0/24 -j NETMAP --to 192.168.1.0/24
iptables -t nat -A POSTROUTING -d 192.168.1.0/24 -j NETMAP --to 192.168.10.0/24Or do I need to be a bit more explicit about the direction of ip packages?
Update:
In order to help with the troubleshooting I can inform that the Raspberry 4 acts as a DHCP server for both my subnets.
It advertises itself as the first hop, when doing a traceroute from any machine to the Internet - on either net.
A traceroute from My computer to lets say Google will show something like:
- 1: Raspberry 4
- 2: Primitive Router
- 3: ISP gateway
- 4: ...
- ...
- n: Google.com
However traceroute goes bad when done from my Raspberry 3.
First jump will be the Raspberry 4, so no surprice there, but the route wont give a reply on ping, as it does not know how to reach the 192.168.10.0/24 subnet.
For your information my Raspberry 4 already acts a site-2-site VPN client, so if all other things fail, then I can just do sourced based routing and send all traffic via my VPN connection, though at a significant speed penalty (around 70% speed drop).
Update 2:
Output from the Raspberry 4:
# ip rule show
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
# ip route show table main
default via 192.168.0.1 dev eth0 src 192.168.0.136 metric 202
192.168.0.0/23 dev eth0 proto dhcp scope link src 192.168.0.136 metric 202
192.168.100.0/24 dev tun-ipv6 proto kernel scope link src 192.168.100.10- The router resides at 192.168.0.1.
- The subnet 192.168.100.0/24 is inside my VPN.
That part works fine as I have no intentions to send all traffic through my VPN.
It is trivial for me to create a new routing table to redirect from 192.168.10.0/24 via VPN as I have already done that particual trick one time before in order to use IPv6 on my local lan. :-)
However Tom Yan solution looks quite a bit what I was aiming for particularly his hint about "AnyIP". :-)
I need todo a bit of testing, but I will accept his answer. :-)
43 Answers
First of all, the source NAT should be:
iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j NETMAP --to 192.168.1.0/24(POSTROUTING with an -s match)
and the destination NAT should be:
iptables -t nat -A PREROUTING -d 192.168.1.0/24 -j NETMAP --to 192.168.10.0/24(PREROUTING with a -d match)
Note: AFAIK the destination NAT rule is only needed for "NEW" traffics (from within the LAN). The source NAT rule is sufficient for return traffics, as destination NAT for any of those is "implied" by it.
But then there's the problem: how will My Computer and Primitive Router know that traffics for 192.168.1.0/24 (which are"actually" 192.168.10.0/24) should go to Raspberry Pi 4 for further routing?
The answer is, you need Raspberry Pi 4 to response to ARP requests for 192.168.1.0/24.
One of the ways to achieve that is to set up something called "AnyIP" (at least that's term I heard of). Essentially that means adding a subnet route of type local for 192.168.1.0/24:
ip r add local 192.168.1.0/24 dev eth0Note: I don't exactly remember if this would work with the arp_ignore sysctl set to e.g. 1.
Make sure you enabled IP(v4) forwarding with sysctl and no firewall on Raspberry Pi 4 blocks forwarding traffics that you desire (as per a rule or the chain policy).
No, adding the NAT rules is not enough. Because discovery of IPv4 hosts on the local network (broadcast segment) works using ARP. The broadcast traffic of ARP would not cross your inner NAT box and the NAT box would not respond either. To make it respond you need proxy_arp.
However, it is unclear what this kind of setup would achieve. Just put everything in one network or add routes to PCs (instead of the router) and MASQUERADE only to the outer router.
I am trying to learn a bit about NAT translations in Linux, but I havent seen any proof-of-concept that was boiled down to as basic as possible.
Here's my basic-as-possible script that I use on my desktop PC to "share internet" when I connect another device up to it via LAN:
#!/bin/bash
# masquerade $1 (e.g. eth0, ppp0) as $2 (default wlan0)
INTIF="$1"
EXTIF=${2:-wlan0}
echo $INTIF $EXTIF
echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -P INPUT ACCEPT
iptables -F INPUT
iptables -P OUTPUT ACCEPT
iptables -F OUTPUT
iptables -P FORWARD DROP
iptables -F FORWARD
iptables -t nat -F
iptables -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT
iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADEYou need to call it with the "internal" interface (the network with clients that need NAT) and the "external" interface (towards the internet). Setup of the internal interface, and DHCP etc. is not included (you were only asking about NAT).
That gave me the idea to implement a 1:1 NAT on my Raspberry 4, where all ip adresses from the 192.168.10.x/24 range gets translated into 192.168.1.x/24 range.
That's a lot more difficult than "basic NAT".
But you don't have to do that, and in fact, it wouldn't work well with your primitive router / Raspberry Pi 4 combination. Instead, just do basic NAT on the Raspberry Pi 4. This will mean everything on 192.168.10.*/24 will NAT to 192.168.0.0, and the router will understand that just fine.
(And in real life, you'd just connect the two switches, and have a single subnet provided from your router. BTW, if your primitive router can be re-flashed with OpenWRT etc., it'll also be able to do, well, routing).
1