在Linux下将TCP流量重定向到UNIX域套接字

40
假设有一个遗留的 Linux 应用程序正在监听 UNIX 域套接字 /tmp/foo
除了通过 UNIX 域套接字机制与该遗留应用程序通信外,我还希望能够通过端口 1234 上的 TCP 连接连接到它。
如何最简单地绑定到 TCP 端口 1234,并将所有传入连接重定向到 UNIX 域套接字 /tmp/foo
5个回答

65

原来发现可以使用 socat 来实现此目的:

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

再加上一点安全性:

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

这些示例已经经过测试并按预期工作。


socat, netcat,两者都可以。你甚至可以将 stunnel 包装在它周围,增加更多层次的复杂性! - Conrad Meyer
如果有人想使用它来共享Docker套接字,他应该删除su=nobody部分。 - Dmitriusan
要共享Docker套接字,只需通过传递-H tcp://127.0.0.1:4321告诉Docker守护程序监听本地端口(请注意,这允许任何可以打开到127.0.0.1的连接的人访问Docker守护程序。没有uid / gid检查或任何其他内容,但对于netcat/socat方法也是如此)。 - svvac
@swordofpain 你知道如何在Docker for Mac上实现这个吗?我已经启用了“登录时自动启动Docker”,但是在首选项中似乎没有监听套接字而不是Unix套接字的选项。 - Troy Daniels
据我所知,Docker for Mac虚拟化了一个Linux内核来处理容器相关的事情。实际上,OSX的内核并没有参与其中。这意味着Docker守护进程在VM中运行,并且必须在那里进行配置。尽管他们提供的任何前端可能已经通过API与守护进程通信,这意味着已经应该有一个用于监听的套接字。主要区别在于它不会在localhost上侦听,而是在VM的虚拟网络接口上侦听,您需要找到其IP地址。希望这可以帮助到您。 - svvac
显示剩余2条评论

24

最简单的工具?可能是Netcat(又称nc):

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

第一个命令监听端口1234以便接收传入的连接,并将结果数据传输给第二个命令。第二个命令连接到Unix域套接字/tmp/foo,并将其输入写入该套接字。请注意,这只接受单个连接,并在连接断开后立即退出。如果您想继续监听更多连接,请使用-k选项:

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

您可以在一个终端中设置一个侦听器来测试它是否工作:

nc -lUk /tmp/foo

并在另一个中写入:

nc localhost 1234

socat,正如knorv推荐的那样,它更加强大,但使用起来更加复杂。


似乎在Ubuntu(Quantal)下,nc不支持Unix套接字 :( - gucki
@gucki 真的吗?你没有 nc -U 选项吗?我没有 Quantal 机器来测试,但在 Precise 上,nc-U 选项,并且我在评论中说的话很好用。你是否尝试过我写的内容?如果你发现 nc 对你不起作用,我建议尝试 socat;它可以做比 nc 更多的事情,并且对它的控制更加精细,但是它使用起来会更加复杂。 - Brian Campbell
1
是的,我刚刚再次测试了一下(使用netcat 1.10-40):nc -l 1234 | nc -U /tmp/foo会提示nc: invalid option -- 'U'并且显示nc -h for help。但是socat可以正常工作 :) - gucki
2
@gucki 看起来Ubuntu上有两个nc软件包。netcat-traditionalnetcat-openbsd。我安装的是netcat-openbsd,似乎比netcat-traditional具有更多功能。您可以同时安装它们,并将ncnetcat链接到其中一个。 - Brian Campbell
4
采用这种方法的问题在于,生成的管道是单向的。如果我们期望从监听 Unix 域套接字的进程获得响应,那么通过 TCP 套接字通信的唯一方式是使用 socat 工具将响应转发回来。 - kostix

3

您应该能够绑定到TCP 1234端口,获取/tmp/foo的套接字fd,并使用select调用在1234和/tmp/foo上监听数据。将任何写入1234端口的数据重写到/tmp/foo中,反之亦然。

现在您充当代理并传输数据。

这里有一个可能有帮助的网页:http://osr507doc.sco.com/en/netguide/dusockC.io_multiplexing.html


1
除了@knorv的答案之外,使用xinetd可以像守护进程一样工作。
# 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
}

0

3
很遗憾,对于发帖者的需求来说,lighttpd 太过臃肿了。 - Conrad Meyer
这对任意TCP协议都有效,而不仅仅是HTTP吗? - Anton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接