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, whenclient
attempts to connect toserver
on port B, it actually connects tointerceptor A
(acting as server) on port X. interceptor A
then connects tointerceptor B
. It does any processing before "forwarding" the bytes fromclient
.interceptor B
connects toserver
. However, at point(b)
, also use nftables to transform source IP/port to that ofclient
instead ofinterceptor B
. Soserver
thinks 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 addressclient
was originally trying to communicate with? This is necessary so it can create a connection tointerceptor B
on 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.