一尘不染

如何安全地将net.Listener()的FD传递给子进程?

go

我已经被这个问题困扰了几个小时了:

我有一个主进程充当TCP服务器,主进程调用Fork(),将其net.Listener()的FD传递给子进程。然后,子进程可以使用net.Filelistener()继承此FD。

我已经通过许多开源代码研究了这个问题,还做了一些实验。但是不幸的是,这些解决方案目前尚不满足我的需要,因为它们不便于携带,您还需要许多危险的低级工作。

如果有任何将net.Listener()的FD传递给子进程SAFELY的解决方案,我很高兴知道。

我现在尝试过的是:

  1. 环境值(非可移植性)会导致许多FD混乱,这是不安全的,因为可以从外部进行更改。

  2. Dup FD&Clear FD_CLOEXEC然后是exec / fork,可移植,但不受Go API支持,syscall.NoCloseOnExec()提交给开发团队的更改被拒绝,因为他们希望保持syscall清洁。

  3. 设置为SO_REUSEADDR使子进程可以立即监听端口,然后关闭父监听器。失败,不可移植,Go API不支持,也不安全。

  4. exec.Command.ExtraFiles(),不知道如何从子进程中继承FD,我是否需要一个配置文件来保存FD和名称?此解决方案也有一个错误,有关更多详细信息,请阅读exec的文档。

好的,我已经写了这个问题的简单测试案例(使用解决方案4):

https://github.com/reckhou/go-fd-pass-test

还包括OS X和Linux上的2个可执行文件。我尝试了Go 1.1和Go 1.1.1,但此问题仍然存在。


阅读 307

收藏
2020-07-02

共1个答案

一尘不染

最简单的方法是在exec.Cmd的ExtraFiles字段中传递侦听器。

父母的例子:

var l *net.TCPListener
cmd := exec.Command(...)
f, err := l.File()
cmd.ExtraFiles = []*os.File{f}

孩子的例子:

l, err := net.FileListener(os.NewFile(3, "listener"))

您可能还需要对此进行概括,并让孩子接受PROGRAMNAME_LISTENER_FD作为环境变量。然后,父级将在启动子级之前将环境变量设置为3。

2020-07-02