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

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

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

netsh winsock show catalog

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

创建原始套接字

若要创建类型为SOCK_RAW的套接字,请使用 af 参数 (地址系列调用套接字WSASocket 函数) 设置为AF_INET或AF_INET6,类型参数设置为SOCK_RAW并将协议参数设置为所需的协议编号。 协议参数将成为 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 标头。 如果 IP_HDRINCL 套接字选项设置为 true, (地址系列AF_INET) 的 IPv4 套接字,则应用程序必须在传出数据中提供 IPv4 标头,以便发送操作。 如果此套接字选项为 false (默认设置) ,则 IPv4 标头不应包含在发送操作的传出数据中。

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

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

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

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

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

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

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

注意

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

 

原始套接字的常见用途

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

原始套接字的限制

在 Windows 7 Windows Vista 上,Windows SERVICE Pack 2 (SP2) 的 XP,使用 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 部分。

应用程序还需要注意防火墙设置在使用原始套接字发送和接收数据包时可能具有的影响。