40

Assume a legacy Linux application listening on a UNIX domain socket /tmp/foo.

In addition to communicating with this legacy application over the UNIX domain socket mechanism I want to be able to connect to it via a TCP-connection on port say 1234.

What is the easiest way to bind to TCP port 1234 and then redirect all incoming connections to the UNIX domain socket /tmp/foo?

knorv
  • 49,059
  • 74
  • 210
  • 294

5 Answers5

65

Turns out socat can be used to achieve this:

socat TCP-LISTEN:1234,reuseaddr,fork UNIX-CLIENT:/tmp/foo

And with a bit of added security:

socat TCP-LISTEN:1234,bind=127.0.0.1,reuseaddr,fork,su=nobody,range=127.0.0.0/8 UNIX-CLIENT:/tmp/foo

These examples have been tested and work as expected.

knorv
  • 49,059
  • 74
  • 210
  • 294
  • socat, netcat, either way. You could even wrap `stunnel` around it for more layers of complexity! – Conrad Meyer Nov 12 '10 at 20:01
  • If anybody wants to use that to share docker socket, he should remove ```su=nobody``` part – Dmitriusan Jun 21 '16 at 07:37
  • To share the docker socket, simply tell the Docker daemon to listen to a local port by passing `-H tcp://127.0.0.1:4321` (note that it allows access to the docker daemon for anyone that can open a connection to `127.0.0.1`. No uid/gid checks or anything, but that is also true for the `netcat`/`socat` approach) – svvac Jul 18 '16 at 15:19
  • @swordofpain Do you know how to do that with Docker for Mac? I have "Automatically start Docker when you log in" enabled, and there does not seem to be an option in preferences to listen on a socket instead of the Unix socket. – Troy Daniels Aug 25 '16 at 21:10
  • AFAIK, Docker for Mac virtualizes a linux kernel that does the container stuff. OSX's kernel isn't involved, really. That means that the docker daemon is running inside the VM, and that the configuration must be done there. Though probably whatever frontend they supply probably already talks to the daemon through the API, meaning that there already should be a listening socket for that. The main difference would be that it won't be listening on localhost, but on the virtual network interface of the VM, of which you would have to find the IP address. Hope this helps. – svvac Sep 08 '16 at 06:30
  • Aww, there doesn't seem to be an API port open, but [these guys](https://forums.docker.com/t/remote-api-with-docker-for-mac-beta/15639/7) are looking for the same thing. It still should be possible to achieve this by fiddling with the config inside the VM. But these are all wild guesses, I don't know OSX, nor Docker on that platform for that matter... – svvac Sep 08 '16 at 06:36
  • For Docker for Mac, I did not figure out how to use have the VM open the port, but the first command in this answer works. The second works if you remove `su=nobody`. – Troy Daniels Oct 27 '16 at 17:55
24

Easiest? Probably Netcat (aka nc):

nc -l 1234 | nc -U /tmp/foo

The first command listens on port 1234 for incoming connections, and pipes the resulting data to the second command. The second connects to the Unix domain socket /tmp/foo, and writes its input to that socket. Note that this will only accept a single connection, and exit as soon as that connection is dropped. If you want to keep listening for more connections, use the -k option:

nc -lk 1234 | nc -U /tmp/foo

You can test that this is working by setting up a listener for that socket in one terminal:

nc -lUk /tmp/foo

And writing to it in another:

nc localhost 1234

socat, as recommended by knorv, is more capable, but more complicated to use.

Community
  • 1
  • 1
Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
  • seems like nc under ubuntu (quantal) doesn't support unix sockets :( – gucki Nov 02 '12 at 15:07
  • @gucki Really? You don't have the `nc -U` option? I don't have a Quantal machine to test on, but on Precise `nc` has the `-U` option, and what I said in my comment works fine. Have you tried exactly what I wrote? If you aren't finding that `nc` works for you, I would recommend trying `socat`; it can do a lot more than `nc`, with much finer grained control of how it works, but it is a bit more complicated to figure out how to use. – Brian Campbell Nov 02 '12 at 15:28
  • 1
    Yes, I just tested again (netcat 1.10-40): `nc -l 1234 | nc -U /tmp/foo` gives `nc: invalid option -- 'U'` and `nc -h for help`. `socat` works fine :) – gucki Nov 02 '12 at 21:13
  • 2
    @gucki Looks like there are two nc packages on Ubuntu. `netcat-traditional` and `netcat-openbsd`. `netcat-openbsd` is the one I have installed, and seems to have more features than `netcat-traditional`. You can install them both at once, with `nc` and `netcat` symlinked to one or the other. – Brian Campbell Nov 02 '12 at 22:32
  • 4
    The problem with this approach is that the resulting pipeline is unidirectional. If we expect a response from the process listening on the unix-domain socket, the only way to communicate it via a TCP socket is `socat` which will forward the response back to us. – kostix Apr 14 '16 at 10:25
3

You should be able to bind to TCP 1234, get a socket fd for /tmp/foo and use the select call to 'listen' for data on both 1234, and /tmp/foo. Any data written to 1234, you rewrite to /tmp/foo and vice-versa.

You now act as a proxy and transfer data back and forth.

And here is a web-page which might help: http://osr507doc.sco.com/en/netguide/dusockC.io_multiplexing.html

1

In additons to @knorv's answer: with xinetd it can work like a daemon

# cat /etc/xined.d/mysrv
service mysrv
{
 disable = no
 type = UNLISTED
 socket_type = stream
 protocol = tcp
 wait = no
 server = /usr/bin/socat
 server_args = STDIN UNIX-CLIENT:/tmp/mysocket.sock
 bind = 127.0.0.1
 port = 1234
}
Community
  • 1
  • 1
hloroform
  • 133
  • 7
0

Not tried it : but it looks like 'lighttpd' can do this for you:

http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore

monojohnny
  • 5,894
  • 16
  • 59
  • 83