TCP/IP 原始套接字

原始套接字是一种允许访问基础传输提供程序的套接字。 本主题仅重点介绍原始套接字以及 IPv4 和 IPv6 协议。 这是因为除 ATM 以外的大多数其他协议不支持原始套接字。 若要使用原始套接字,应用程序需要具有有关正在使用的基础协议的详细信息。

IP 协议的 Winsock 服务提供商可能支持套接字类型的SOCK_RAW。 Windows 上包括的用于 TCP/IP 的 Windows 套接字 2 提供程序支持此 SOCK_RAW 套接字类型。

此类原始套接字有两种基本类型:

  • 第一种类型使用由 Winsock 服务提供程序识别的 IP 标头中写入的已知协议类型。 第一种类型的套接字的示例是 ICMP 协议的套接字 (IP 协议类型 = 1) 或 ICMPv6 协议 (IP procotol 类型 = 58) 。
  • 第二种类型允许指定任何协议类型。 第二种类型的示例是 Winsock 服务提供商不直接支持的实验性协议,例如流控制传输协议 (SCTP) 。

确定是否支持原始套接字

如果 Winsock 服务提供程序支持AF_INET或AF_INET6地址系列SOCK_RAW套接字,则SOCK_RAW的套接字类型应包含在 WSAEnumProtocols 函数为一个或多个可用传输提供程序返回的WSAPROTOCOL_INFO结构中。

WSAPROTOCOL_INFO 结构中的 iAddressFamily 成员应指定 AF_INET 或 AF_INET6 并且 WSAPROTOCOL_INFO 结构的 iSocketType 成员应为其中一个传输提供程序指定SOCK_RAW

WSAPROTOCOL_INFO 结构的 iProtocol 成员可以设置为 IPROTO_IP。 如果服务提供商允许应用程序对地址系列的 Internet 协议以外的其他网络协议使用 SOCK_RAW 套接字类型,则 WSAPROTOCOL_INFO 结构的 iProtocol 成员也可能设置为零。

WSAPROTOCOL_INFO 结构中的其他成员指示SOCK_RAW协议支持的其他属性,并指示应如何处理SOCK_RAW套接字。 SOCK_RAWWSAPROTOCOL_INFO的这些其他成员通常指定协议是无连接、面向消息、支持广播/多播 (dwServiceFlags1 成员) 中设置XP1_CONNECTIONLESS、XP1_MESSAGE_ORIENTED、XP1_SUPPORT_BROADCAST位和XP1_SUPPORT_MULTIPOINT位,最大消息大小可以为 65,467 字节。

在 Windows XP 及更高版本上,可以使用 NetSh.exe 命令来确定是否支持原始套接字。 从 CMD 窗口运行的以下命令将在控制台上显示来自 Winsock 目录的数据:

netsh winsock show catalog

输出将包含一个列表,其中包含本地计算机上支持的 WSAPROTOCOL_INFO 结构中的一些数据。 在“说明”字段中搜索“RAW/IP”或“RAW/IPv6”一词,查找支持原始套接字的协议。

创建原始套接字

若要创建 SOCK_RAW 类型的套接字,请使用 af 参数 (地址系列) 设置为 AF_INET 或 AF_INET6,类型参数设置为 SOCK_RAW,并将协议参数设置为所需的协议编号,调用套接字WSASocket 函数。 协议参数将成为 IP 标头中的协议值, (SCTP 为 132,例如) 。

注意

如果类型参数设置为 SOCK_RAW,则应用程序不得将零 (0 ) 指定为套接字WSASocketWSPSocket 函数的协议参数。

 

原始套接字提供操作基础传输的功能,因此它们可用于构成安全威胁的恶意目的。 因此,只有管理员组的成员才能在 Windows 2000 及更高版本上创建SOCK_RAW类型的套接字。

发送和接收操作

应用程序创建 SOCK_RAW类型的套接字后,此套接字可用于发送和接收数据。 在SOCK_RAW类型的套接字上发送或接收的所有数据包都被视为未连接的套接字上的数据报。

以下规则适用于 SOCK_RAW 套接字上的操作:

  • sendtoWSASendTo 函数通常用于在类型为 SOCK_RAW 的套接字上发送数据。 目标地址可以是套接字地址系列中的任何有效地址,包括广播或多播地址。 若要发送到广播地址,应用程序必须使用 启用了SO_BROADCAST的 setsockopt 。 否则, sendtoWSASendTo 将失败,错误代码 为 WSAEACCES。 对于 IP,应用程序可以发送到任何多播地址 (,而无需成为组成员) 。

  • 发送 IPv4 数据时,应用程序可以选择是否在数据包的传出数据报的前面指定 IPv4 标头。 如果 对于AF_INET) 的 IPv4 套接字 (地址系列,IP_HDRINCL套接字选项设置为 true,则应用程序必须在发送操作的传出数据中提供 IPv4 标头。 如果此套接字选项 (默认设置) 为 false,则 IPv4 标头不应包含在发送操作的传出数据中。

  • 发送 IPv6 数据时,应用程序可以选择是否在数据包的传出数据报的前面指定 IPv6 标头。 如果 对于AF_INET6) 的 IPv6 套接字 (地址系列,IPV6_HDRINCL套接字选项设置为 true,则应用程序必须在发送操作的传出数据中提供 IPv6 标头。 此选项的默认设置为 false。 如果此套接字选项 (默认设置) 为 false,则发送操作的传出数据中不应包含 IPv6 标头。 对于 IPv6,应该无需包含 IPv6 标头。 如果可以使用套接字函数获取信息,则不应包含 IPv6 标头,以避免将来出现兼容性问题。 IETF 发布的 RFC 3542 中讨论了这些问题。 不建议使用 IPV6_HDRINCL 套接字选项,将来可能会弃用。

  • recvfromWSARecvFrom 函数通常用于接收SOCK_RAW类型的套接字上的数据。 这两个函数都可选择返回发送数据包的源 IP 地址。 接收的数据是来自未连接的套接字的数据报。

  • 对于AF_INET) 的 IPv4 (地址系列,无论 IP_HDRINCL 套接字选项如何,应用程序都会在每个接收的数据报的前面接收 IP 标头。

  • 对于AF_INET6) 的 IPv6 (地址系列,无论 IPV6_HDRINCL 套接字选项如何,应用程序都会在每个接收的数据报中的最后一个 IPv6 标头之后接收所有内容。 应用程序不会使用原始套接字接收任何 IPv6 标头。

  • 接收的数据报将复制到满足以下条件的所有 SOCK_RAW 套接字中:

    • 创建套接字时 ,协议 参数中指定的协议编号应与接收的数据报的 IP 标头中的协议编号匹配。
    • 如果为套接字定义了本地 IP 地址,则它应对应于接收的数据报的 IP 标头中指定的目标地址。 应用程序可以通过调用 bind 函数来指定本地 IP 地址。 如果未为套接字指定本地 IP 地址,则无论接收的数据报的 IP 标头中的目标 IP 地址如何,数据报都会复制到套接字中。
    • 如果为套接字定义了一个外部地址,则它应对应于所接收数据报的 IP 标头中指定的源地址。 应用程序可以通过调用 connectWSAConnect 函数来指定外部 IP 地址。 如果未为套接字指定外部 IP 地址,则无论接收的数据报的 IP 标头中的源 IP 地址如何,数据报都会复制到套接字中。

请务必了解, SOCK_RAW 类型的某些套接字可能会收到许多意外的数据报。 例如,PING 程序可能会创建 SOCK_RAW 类型的套接字来发送 ICMP 回送请求和接收响应。 虽然应用程序需要 ICMP 回显响应,但所有其他 ICMP 消息 ((如 ICMP HOST_UNREACHABLE) )也可能传递到此应用程序。 此外,如果计算机上同时打开多个 SOCK_RAW 套接字,则相同的数据报可能会传递到所有打开的套接字。 应用程序必须具有一种机制来识别感兴趣的数据报并忽略所有其他数据报。 对于 PING 程序,此类机制可能包括检查收到的 IP 标头,以查找 ICMP 标头中的唯一标识符 (应用程序的进程 ID,例如) 。

注意

若要使用 SOCK_RAW 类型的套接字需要管理权限。 运行使用原始套接字的 Winsock 应用程序的用户必须是本地计算机上的 Administrators 组的成员,否则原始套接字调用将失败,并显示 WSAEACCES 错误代码。 在 Windows Vista 及更高版本上,在创建套接字时强制实施对原始套接字的访问。 在早期版本的 Windows 中,在其他套接字操作期间强制实施对原始套接字的访问。

 

原始套接字的常见用途

原始套接字的一个常见用途是对需要详细检查 IP 数据包和标头的应用程序进行故障排除。 例如,原始套接字可与 SIO_RCVALL IOCTL 一起使用,使套接字能够接收通过网络接口传递的所有 IPv4 或 IPv6 数据包。 有关详细信息,请参阅 SIO_RCVALL 参考。

原始套接字的限制

在 Windows 7、Windows Vista、具有 Service Pack 2 的 Windows XP (SP2) 以及具有 Service Pack 3 (SP3) 的 Windows XP 上,通过原始套接字发送流量的功能受到以下几种限制:

  • TCP 数据不能通过原始套接字发送。

  • 无法通过原始套接字发送具有无效源地址的 UDP 数据报。 任何传出 UDP 数据报的 IP 源地址必须存在于网络接口上,否则数据报将被删除。 进行此更改是为了限制恶意代码创建分布式拒绝服务攻击的能力,并限制使用伪造源 IP 地址) 发送欺骗数据包 (TCP/IP 数据包的能力。

  • 不允许使用IPPROTO_TCP协议的原始套接字调用 绑定 函数。

    注意

    (IPPROTO_IP、IPPROTO_UDP或IPPROTO_SCTP的其他协议(例如,) )允许使用具有原始套接字的 绑定 函数。

     

上述限制不适用于 Windows Server 2008 R2、Windows Server 2008、Windows Server 2003 或早于带 SP2 的 Windows XP 的操作系统版本。

注意

Windows 上的 TCP/IP 的 Microsoft 实现能够基于上述限制打开原始 UDP 或 TCP 套接字。 其他 Winsock 提供程序可能不支持使用原始套接字。

 

对于使用 类型为 SOCK_RAW 的套接字的应用程序,还有进一步的限制。 例如,侦听特定协议的所有应用程序都将接收为此协议接收的所有数据包。 使用协议的多个应用程序可能不需要这样做。 这也不适用于高性能应用程序。 若要解决这些问题,可能需要为特定网络协议编写 Windows 网络协议驱动程序 (设备驱动程序) 。 在 Windows Vista 及更高版本上,Winsock 内核 (WSK) ,新的独立于传输的内核模式网络编程接口可用于编写网络协议驱动程序。 在 Windows Server 2003 及更早版本中,可以编写传输驱动程序接口 (TDI) 提供程序和 Winsock 帮助程序 DLL 以支持网络协议。 然后,网络协议将作为支持的协议添加到 Winsock 目录中。 这允许多个应用程序打开此特定协议的套接字,设备驱动程序可以跟踪哪个套接字接收特定数据包和错误。 有关编写网络协议提供程序的信息,请参阅 Windows 驱动程序工具包 (WDK) 中有关 WSK 和 TDI 的部分。

应用程序还需要了解防火墙设置对使用原始套接字发送和接收数据包的影响。