How to set up a persistent TCP gender-changer proxy?
I have a provider (A) that wants to send us data through an incoming TCP connection. Unfortunately the consuming service (B) cannot receive inbound TCP connections. Also it does not have a static IP, another requirement.
One way to solve this would be a service that connects the incoming TCP A port to another TCP port B, so that the consumer can make an outbound connection to B.
This is not a unique problem [1] [2], and with socat I can make something very close to what I want:
socat -d -d -d -u TCP4-LISTEN:PORT-A,reuseaddr TCP4-LISTEN:PORT-B,reuseaddr
However, this has the following problems:
- If B disconnects, it cannot re-connect. With
TCP4-LISTEN:PORT-B,reuseaddr,fork
, it can connect but does not receive data. - B cannot connect before A has established a connection (surmountable)
- Only one connection can be established to
PORT-B
(surmountable)
Is there a way to adjust the command so that is becomes "permament" and resistent to failures?
The important question is, how will A react to loss of connection, or to connection being refused? Anything that just assumes that a single TCP connection will stay up forever is going to be fragile; that's just the nature of internet.
How about setting up the socat
as a [x]inetd
service?
You would set xinetd
to listen in PORT-B, and start the socat -u TCP4-LISTEN:PORT-A,reuseaddr STDIO
as soon as the B-side connects.
xinetd
will pass the incoming traffic from B-side to standard input of socat
, and catch the standard output of socat
and pass it to the B-side.
If B disconnects, then the socat
process can be allowed to end; xinetd
will start a new one as soon as B connects again. While B is disconnected, A will be getting "connection refused" errors.
I once had to do something quite similar on an old HP-UX system.
The real world is messy.
In the real world sometimes TCP connections die, this may happen for example if a stateful firewall or NAT is rebooted, if the connection goes too long without traffic, if the underlying connection is down for too long.
Furthermore sometimes when connections die they don't die symmetrically. If a connection carrying a lot of data dies then it is likely that the sender will notice that it is dead long before the recipiant does so. This has a couple of side effects.
- If the connection is initiated from sender to recipiant then a new connection may come in while the old connection is apparently still alive.
- If the connection is initiated from recipiant to sender then there may be a substantial delay between the sender detecting the connection is broken and the recipiant detecting that fact and triggering a reconnection.
Furthermore TCP connections are a stream of bytes, NOT a stream of messages, so when your connection dies you may receive a partial message.
The net result of this leads me to conclude that a robust solution requires an understanding of the application protocol so that your solution can understand.
- How to splice the streams when a new connection comes in.
- Whether or not messages should be stored when the data source is connected by the data recipient is not.
- Whether an end to end acknowledgement mechanism is appropriate to prevent message loss.
- Whether some kind of application level "ping" mechanism is needed to speed up detection of dead connections.