I have the following network:
~~~~~~~ MACHINE A ~~~~~~~ ~~~~~~~~ MACHINE B ~~~~~~~~
+--------+ +--------+
| client |----(a) (b)----------| server |
+--------+ | | [port Z]+--------+
| |
| |
|[port X] |
+---------------+ +---------------+
| interceptor A |-------------------| interceptor B |
+---------------+ [port Y]+---------------+
For context:
- All machines are Raspberry Pi's running Raspberry Pi OS, Linux kernel 5.15.
- The solution should be language agnostic, if possible. However, I am using C.
- IP addresses are statically assigned.
- There are more than two machines on the network that need to communicate in this fashion.
- All processes need to run in user space.
On Machine A, process client needs to communicate with process server (listening on port Z) on Machine B on the same local network. This would normally occur via a simple TCP socket. However, I want to intercept the bytes sent from client to server (and vice versa, since TCP is bidirectional) and do some "magic" with processes interceptor A and interceptor B before "forwarding" the data to server. Importantly, the actual TCP connection between the machines must be independently handled by client interceptor A and server interceptor B (listening on port Y). However, client and server need to think they're communicating with each other directly.
My initial solution is the following:
- Use nftables at point
(a)to modify destination IP/port so that packets are redirected tointerceptor A(listening on port X) instead ofserver. So, whenclientattempts to connect toserveron port B, it actually connects tointerceptor A(acting as server) on port X. interceptor Athen connects tointerceptor B. It does any processing before "forwarding" the bytes fromclient.interceptor Bconnects toserver. However, at point(b), also use nftables to transform source IP/port to that ofclientinstead ofinterceptor B. Soserverthinks it just accepted a connection withclient.
TL;DR: I need to redirect an outgoing socket connection to localhost, do some processing with the bytes and retransmit those bytes over a new connection to endpoint. Endpoints should not know there are intermediate processes managing the real inter-machine connection.
Questions:
- Is setting NAT rules in nftables a proper solution? It seems that the normal usage of NAT (transforming private IP to global IP) does the operations in the opposite order, but it seems that it would work.
- More importantly, how can
interceptor A, as an application-layer process, know which IP addressclientwas originally trying to communicate with? This is necessary so it can create a connection tointerceptor Bon the correct machine.
This project is in the planning phase, so I don't have a minimum working example. I'm willing to edit the question to add one, but I think the minimum working example is really just what I'm trying to achieve.