MSYS/Cygwin使用什么机制来模拟Unix域套接字

本文关键字:模拟 Unix 套接字 机制 什么 Cygwin MSYS | 更新日期: 2023-09-27 17:58:21

我正试图(用C#)编写一个软件,通过(模拟MSYS的)Unix域套接字与另一个用MSYS构建的软件进行通信。我了解到"套接字服务器"(我不清楚正确的术语是什么)创建了一个临时文件,其中包含以下内容:

!<socket >59108 282F93E1-9E2D051A-46B57EFC-64A1852F

59108对应于一个TCP端口,"套接字服务器"正在环回接口上侦听该端口。使用数据包捕获工具,我已经能够确定"套接字客户端"连接到此端口,并且通过环回接口交换信息。

我在软件中复制了这种行为,"套接字客户端"连接到我的侦听端口,但没有传输任何信息。我相信还有另一个步骤,很可能涉及"套接字"文件中的GUID,但我一直无法确定它是什么。我需要做什么才能触发客户端的通信?

MSYS似乎在使用Cygwin的机制,该机制涉及一个命名事件,该事件(可能?)由"服务器"创建,并由"服务器(显然)发出信号,但我对实现的天真尝试似乎没有奏效。

我找到了Conrad Scott写的一封电子邮件,其中描述了"握手"过程中的各种缺点,并提出了一个据称可以解决这些缺点的补丁。在这封电子邮件中,Conrad描述了所使用的过程,他指出实际上有两个事件,一个由"服务器"管理,一个则由"客户端"管理。我已经使用API Monitor来查找对CreateEvent()的调用,虽然有几个调用,但我在这里找不到一个看起来像"确凿证据"的调用。对CreateSemaphore()也没有有趣的调用,所以Conrad的补丁似乎从未应用过(或者,至少,它是在MSYS分叉Cygwin之后的一段时间应用的)。

MSYS/Cygwin使用什么机制来模拟Unix域套接字

看起来divB和Mark的答案都是正确的,但他们都遗漏了一些细节,所以希望这会更完整一点。

这里有两种不同的实现方式。我还没有对谁实现了哪个实现进行详尽的调查,但截至本文撰写之时,cygwin的当前版本使用divB描述的实现,MsysGit使用Mark描述的实现。

初始化服务器:

  1. 创建一个套接字(AddressFamily=IPv4,Type=Stream,Protocol=TCP)。(.NET/MFC)
  2. 将其绑定到环回(127.0.0.1)。(.NET/MFC)
  3. 告诉插座听。(.NET/MFC)
  4. 生成一个随机的16字节GUID
  5. 根据TCP端口和GUID创建一个包含以下内容的文件。使用原始示例,其中59108是TCP端口,282F93E1-9E2D051A-46B57EFC-64A1852F是GUID。

    在cygwin实现中,套接字文件的内容是:

    !<socket >59108 s 282F93E1-9E2D051A-46B57EFC-64A1852F
    

    在msysgit实现中,套接字文件的内容是:

    !<socket >59108 282F93E1-9E2D051A-46B57EFC-64A1852F
    

    区别在于端口和GUID之间的额外"s"。

  6. 设置此文件的"系统"属性。

  7. 仅在msysgit实现中,创建一个名为cygwin.local_socket.secret.58598.282F93E1-9E2D051A-46B57EFC-64A1852F的命名等待句柄(InitalState=False,Reset=AutoReset)。(.NET/MFC)

    58598是通过在端口上使用HostToNetworkOrder函数导出的(作为16位无符号整数)。即59108==0xE6E4和58598==0xE4E6。

处理连接:

  1. 接受传入的套接字。(.NET/MFC)
  2. 仅在cygwin实现的情况下,进行握手,握手包括:
    1. 读取16个字节。如果这些与GUID不匹配,则失败
    2. 发送相同的16个字节
    3. 将12个字节读取为3个32位整数。它们是调用进程的pid、uid和gid
    4. 发回12个字节(3个32位整数)。使用服务器的pid以及收到的uid和gid
  3. 仅在msysgit实现的情况下,通过以下方式与客户端同步:
    1. 获取传入套接字的端口。对于这个例子,我们将说它是63524
    2. 打开客户端的现有等待句柄。(.NET/MFC)。您需要将端口转换为网络字节顺序,就像我们对服务器所做的那样。因此,对于本例,名称为cygwin.local_socket.secret.9464.282F93E1-9E2D051A-46B57EFC-64A1852F
    3. 向服务器发送信号并等待客户端(ToSignal=服务器,WaitOn=客户端,Timeout=10000毫秒,ExitContext/Allertable=False)。(.NET/MFC)。对ExitContext/Alertable参数不是100%确定,但False似乎有效
  4. 将套接字交给(希望已经存在的)代码,无论您正在做什么(在我们三个人的情况下,它似乎是ssh代理)

因此,至少对于cygwin,我现在可以回答您的问题:我刚刚使用MFC实现了一个与cygwin兼容的套接字服务器。我是通过调查赛格温的来源来做到这一点的。似乎连事件都没有。因此,您提到的修补程序似乎尚未实现。

所发生的只是:

1.)套接字文件已创建,GUID("共享密钥")只是随机数。2.)文件必须具有"系统"属性。如果cygwin代码在NTFS上,它会做一些奇怪的权限操作,还没有研究过。3.)使用套接字文件中指示的端口在localhost上创建一个网络套接字。

因此,当客户端连接到套接字(通过TCP/IP)时:

4.)它首先将这4个随机数发送到服务器;服务器检查它们是否有效5.)服务器将它们发回6.)客户端发送3个32位的数字:pid、uid和gid7.)服务器发回他自己版本的这些数字。

我不明白这次握手的目的是什么,因为从安全角度来看,它完全没有价值。

我已经为Git:附带的OpenSSH(ssh agent.exe)的构建找到了正确的功能

服务器端的安装程序包括以下步骤:1.创建一个"秘密字符串",由四组八个十六进制数字组成,用短划线("-")分隔2.在本地端口上侦听3.创建一个模式为EventResetMode.AutoResetEventWaitHandle,名为cygwin.local_socket.securt.[secret string]。[此处侦听端口号,字节顺序颠倒]4.写出"socket"文件,该文件由字符串组成![此处为端口号,字节顺序未反转][机密字符串]

当连接进来时,必须执行以下步骤:1.使用EventWaitHandle.OpenExisting()打开客户端的事件句柄,使用事件名称cygwin.local_socket.secret。[字节顺序颠倒的远程端口号]。[秘密字符串]2.用信号通知服务器的事件句柄,并用`EventWaitHandle.SignalAndWait()等待客户端的等待句柄

我同意邮件列表上讨论的补丁似乎从未应用过。我计算出的序列似乎更接近列表中讨论的序列,而且它与我从Cygwin中挖掘出的代码相匹配。

我不明白我发现的工作与divB发现的工作之间的差异,但我确实确认了它与我使用的软件(Git的OpenSSH)

一起工作