Reputation: 11
I'm wondering how feasible it is to be able to convert an AF_INET socket to use an AF_UNIX instead. The reason for this is that I've got a program which will open a TCP socket, but which we cannot change. To reduce overhead we would therefore like to instead tie this socket to use an AF_UNIX one for its communication instead.
So far, my idea has been to use LD_PRELOAD to achieve this---intercepting bind() and accept(), however it is not clear how best to achieve this, or even if this is the best approach.
So far, bind in bind(), if the socket type is AF_INET and its IP/port is the socket I wish to convert to AF_UNIX, I then close the sockd here, and open an AF_UNIX one. However, this seems to be causing problems further on in accept() -- because I am unsure what to do when the sockfd in accept() matches the one I wish to tell to use an AF_UNIX socket.
Any help kindly appreciated.
Jason
Upvotes: 1
Views: 953
Reputation: 3106
I had a similar problem and came up with unsock, a shim library that does what you describe, and more.
unsock supports other address types like AF_VSOCK
and AF_TIPC
, and the Firecracker VM multiplexing proxy as well.
There are three key insights I want to share:
Since sockets are created for a particular address family using socket(2)
, and then later connected or bound using connect(2)
/bind(2)
, you may be tempted to simply intercept socket
and fix the address there.
One problem is that you may want to selectively intercept certain addresses only, which you don't know at the time of the call.
The other problem is that file descriptors may be passed upon you from another process (e.g., via AF_UNIX
auxiliary mes, so you may not be able to intercept socket(2)
in the first place.
In other words, you need to intercept connect(2)
, bind(2)
, and sendto(2)
.
When you intercept connect(2)
, bind(2)
, and sendto(2)
, you need to retroactively change the address family for socket(2)
. Thankfully, you can just create a new socket and use dup3(2)
to reassign the new socket to the existing file descriptor. This saves a lot of housekeeping!
accept(2)
and recvfrom(2)
also need to be intercepted, and the returned addresses converted back to something the caller understands. This will inevitably break certain assumptions unless you do maintain a mapping back to the actual, non-AF_INET
address.
Upvotes: 0
Reputation: 22261
Your idea sounds perfectly feasible. In fact, I think it sounds like the best way to achieve what you want. I wouldn't expect very different, or even measurably different, overhead/performance though.
Of course you'd also have to intercept socket()
in addition to bind()
and accept()
. In bind()
, you could, for example, converted the requested TCP port to a fixed pathname /tmp/converted_socket.<port-number>
or something like that.
Upvotes: 1