huyc

导航

raw(7)

RAW(7) 2008-11-20

NAME
raw, SOCK_RAW —— Linux IPv4原始套接字

SYNOPSIS

#include <sys/socket.h>
#include <netinet/in.h>
raw_socket = socket(AF_INET, SOCK_RAW, int protocol);

DESCRIPTION
原始套接字允许在用户空间实现新的IPv4协议。一个原始套接字收发原始数据报不包括链路层头部。

当发送一个数据包时IPv4层自动生成一个IP报头,除非启用了IP_HDRINCL套接字选项。当它被启用后,发送的数据包必须包括一个IP报头。接收时,IP报头总是包含在数据包里面。

只有有效用户ID为0或具备CAP_NET_RAW特权的进程才允许打开一个原始套接字。

所有与原始套接字指定的协议号相关的数据包或错误都将发送到这个原始套接字。允许的协议列表参见RFC 1700分配的数字和getprotobyname(3)。

协议IPPROTO_RAW意味着启用IP_HDRINCL,且能发送任何在IP报头中指定的IP协议。但如果想通过IPPROTO_RAW在原始套接字上接收所有IP协议是不可能的。

┌─────────────────────────────────┐
│带IP_HDRINCL选项发送IP头时修改的字段│
├─────────────┬───────────────────┤
│IP校验和 │总是填写 │
├─────────────┼───────────────────┤
│源地址 │全0时填写 │
├─────────────┼───────────────────┤
│数据包ID │全0时填写 │
├─────────────┼───────────────────┤
│总长 │总是填写 │
└─────────────┴───────────────────┘

如果指定了IP_HDRINCL且IP报头的目标地址非0,则使用套接字的目标地址路由数据包。当指定了MSG_DONTROUTE时,目标地址应该引用到本地接口,否则将遍历除网关外的所有路线。 

如果未指定IP_HDRINCL,则可在原始套接字上用setsockopt设置IP报头选项。参见ip(7)了解更多信息。

Linux 2.2下,IP报头的所有字段和选项都可以用IP套接字选项设置。这意味着通常只有那些新协议或没有用户接口的协议才需要原始套接字。(如ICMP协议)

当接收到一个数据包时,它将在被传递给其他协议处理模块(比如,内核协议模块)之前,先传递给任何绑定了其协议的原始套接字。

地址格式
原始套接字使用定义在ip(7)中的标准的sockaddr_in地址结构。sin_port字段可以用于指定IP协议号,但是它在Linux 2.2下发送时是被忽略的,而且应该总是设置为0(参见BUGS)。对于传入的数据包,sin_port被设置为该数据包的协议。参见<netinet/in.h>头文件查找有效的IP协议。

套接字选项
原始套接字选项可以通过setsockopt设置,通过getsockopt读取。协议指定为IPPROTO_RAW。

ICMP_FILTER
启用一个特殊的ICMP消息过滤器,针对绑定到IPPROTO_ICMP协议的原始套接字。该值是一个过滤ICMP消息类型的位模板,说明那些消息应该被过滤。默认是没有ICMP消息过滤。

此外,所有level为IPPROTO_IP的,有关数据报套接字的套接字选项都是被支持的。

错误处理
当套接字已经连接,或IP_RECVERR标记启用时,网络上生成的错误只传递给用户。对于已经连接的套接字,出于兼容性考虑,只有EMSGSIZE和EPROTO被传递。对于IP_RECVERR,所有网络错误都在错误队列中保存。

ERRORS
EACCES 用户尝试向一个广播地址发送,但套接字没有广播标记。

EFAULT 提供了非法内存地址。

EINVAL 无效参数。

EMSGSIZE
包太大。要么启用了MTU路径探查(IP_MTU_DISCOVER套接字标记),要么数据包的大小超过了IPv4限制值64kb。

EOPNOTSUPP
传递了非法标记给套接字调用(比如MSG_OOB)

EPERM 用户没有权限打开原始套接字。只有有效用户ID为0或CAP_NET_RAW特权的进程可以打开。

EPROTO 收到一个ICMP错误,报告参数问题。

VERSIONS
IP_RECVERR和ICMP_FILTER在Linux 2.2以后可用。它们是Linux的扩展,不可移植。

当设置了SO_BSDCOMPAT选项后,Linux 2.0会启用一些原始套接字bug-to-bug的代码以兼容BSD。Linux 2.2以后,此选项不再有效。

NOTES
默认情况下,原始套接字会执行路径MTU探查。这意味着内核将保留指定目标IP地址的MTU,并且在原始数据包过大时返回EMSGSIZE。如果发生了这样的事情,应用进程应该减小数据包大小。路径MTU探查可以通过IP_MTU_DISCOVER关闭或访问/proc/sys/net/ipv4/ip_no_pmtu_disc文件,参见ip(7)了解详细。关闭之后,原始套接字会将超过接口MTU值的外出数据包分片。然而,出于性能和可靠性的考虑,不建议禁用此特性。

一个原始套接字可以用bind调用绑定到一个本地地址。如果没有绑定,将收到所有与指定协议有关的数据包。此外,一个RAW套接字可以用SO_BINDTODEVICE绑定到一个网络设备,参见socket(7)。

一个IPPROTO_RAW套接字只能发送。如果确实需要接收所有IP数据包,用一个PACKET套接字并配上ETH_P_IP协议即可。注意,PACKET套接字不会像原始套接字那样重组IP报文分片。 

如果你希望在一个报文套接字上收到所有ICMP数据包,IP_RECVERR通常是更好的选择,参见ip(7)。

Linux的原始套接字可以窃听所有IP协议。即便是像ICMP或TCP那样在内核中有协议模块。这种情况下,数据包既传递给内核模块,也传递给原始套接字。这在可移植的程序中是靠不住的,许多BSD套接字实现对此有所限制。

Linux从不修改用户传递的报头(除了填写一些全0字段像IP_HDRINCL描述的那样)。这不同于许多其他的原始套接字实现。 

RAW套接字通常是不可移植的,应该避免在移植程序中使用。

在原始套接字上发送应该在sin_port中取出IP协议,在Linux 2.2不被支持。解决方法是使用IP_HDRINCL。

BUGS
没有描述透明代理扩展。

当IP_HDRINCL选项被设置,数据报不会被分片且被接口的MTU限制。

Linux 2.2下,发送时在sin_port设置的IP协议将被忽略。内核总是使用套接字绑定的协议或调用socket初始化时指定的协议。

SEE ALSO
recvmsg(2), sendmsg(2), capabilities(7), ip(7), socket(7)

RFC 1191 for path MTU discovery.

RFC 791 and the <linux/ip.h> include file for the IP protocol.

COLOPHON
This page is part of release 3.23 of the Linux man-pages project. A
description of the project, and information about reporting bugs, can
be found at http://www.kernel.org/doc/man-pages/.

posted on 2011-10-29 16:34  huyc  阅读(966)  评论(0编辑  收藏  举报