This might be a trivial question: I have two hosts A and B that can access the internet behind NATs. Their NATs do not allow for hole-punching or any other way to connect them directly. Host C is a VPS with a public internet address. I would like to use C as a relay between A and B, such that every packet received by C from A at port P would be relayed to B (with only the dest IP changed to B's IP), and vice versa. Surely there's more than one way to do this, but I'm looking to get this done in the kernel, ideally with iptables.
2 Answers
To translate your question into network lingo (makes it easier to find answers in Internet searches), you want:
- your host C to act as a router for traffic from hosts A and B
- the iptables on host C to translate the addresses in the packets from host A's and host B's addresses to host C's public address.
This is where the initialism Network Address Translation (NAT) comes from, and is sometimes described as host C "masquerading" the traffic as coming from itself (host C) rather than the other hosts (A and B).
There's a pretty good overview of the host C configuration at this site. It assumes you want to translate any traffic that host A and B send through host C rather than only the traffic for certain ports. The overview also doesn't discuss how to configure host A and B to know they should send traffic to host C. It's usually easier to configure a default route in hosts A and B to send all Internet traffic to host C.
I think this would make a good start. Restricting the type of traffic that's sent to host C is a little more advanced, and easier to troubleshoot if you first have a working configuration for all types of traffic.
I would like to use C as a relay between A and B, such that every packet received by C from A at port P would be relayed to B (with only the dest IP changed to B's IP),
You can't; NAT won't allow you to establish a TCP connection or send a UDP packet to port P on B. You don't get to control which incoming ports get opened on the NAT'ting device!
So, you really need a simple VPN (which is really what you're describing).
Wireguard is part of the Linux kernel, quite simple to set up, and there's lots of tutorials out there how to make a VPN a central node with nodes behind VPNs connecting to it. This only works if your NAT devices can let through UDP bidirectionally. If not, you will need to use something like udp2raw to encapsulate wireguard's UDP packets (which themselves can contain UDP, TCP, or other protocols) in TCP.