RAW - Linux手册页
Linux程序员手册 第7部分
更新日期: 2020-08-13
名称
raw-Linux IPv4原始套接字
语法
#包括
#包括
raw_socket =套接字(AF_INET,SOCK_RAW,int协议);
说明
原始套接字允许在用户空间中实现新的IPv4协议。原始套接字接收或发送不包含链接级别标头的原始数据报。
除非在套接字上启用了IP_HDRINCL套接字选项,否则IPv4层在发送数据包时会生成IP头。启用后,数据包必须包含IP标头。为了接收,IP报头始终包含在数据包中。
为了创建原始套接字,进程必须在控制其网络名称空间的用户名称空间中具有CAP_NET_RAW功能。
与原始套接字指定的协议号匹配的所有数据包或错误都将传递到此套接字。有关允许的协议的列表,请参阅IANA分配的协议编号列表,网址为和getprotobyname(3)。
IPPROTO_RAW协议表示已启用IP_HDRINCL,并且能够发送在传递的标头中指定的任何IP协议。使用原始套接字无法通过IPPROTO_RAW接收所有IP协议。
- 通过IP_HDRINCL发送时修改的IP标头字段 IP校验和始终填写 源地址填写为零 数据包ID为零时填写 总长度总是填写
如果指定了IP_HDRINCL,并且IP标头具有非零的目标地址,则套接字的目标地址将用于路由数据包。指定MSG_DONTROUTE时,目标地址应引用本地接口,否则无论如何都会进行路由表查找,但忽略网关路由。
如果未设置IP_HDRINCL,则可以使用setsockopt(2)在原始套接字上设置IP标头选项。有关更多信息,请参见ip(7)。
从Linux 2.2开始,可以使用IP套接字选项设置所有IP标头字段和选项。这意味着通常仅对于新协议或没有用户界面的协议(例如ICMP)才需要原始套接字。
收到数据包后,它会先传递到已绑定到其协议的任何原始套接字,然后再传递给其他协议处理程序(例如内核协议模块)。
Address format
为了发送和接收数据报(sendto(2),recvfrom(2)等),原始套接字使用ip(7)中定义的标准sockaddr_in地址结构。 sin_port字段可用于指定IP协议号,但是在Linux 2.2及更高版本中,它将被忽略以进行发送,并且应始终设置为0(请参阅BUGS)。对于传入数据包,sin_port设置为零。
Socket options
原始套接字选项可以通过setockopt(2)进行设置,并可以通过传递IPPROTO_RAW系列标志来使用getsockopt(2)进行读取。
- ICMP_FILTER
- 为绑定到IPPROTO_ICMP协议的原始套接字启用特殊的过滤器。该值为每种ICMP消息类型设置了一个位,应将其过滤掉。缺省为不过滤ICMP消息。
此外,支持对数据报套接字有效的所有ip(7)IPPROTO_IP套接字选项。
Error handling
仅当连接了套接字或启用了IP_RECVERR标志时,来自网络的错误才会传递给用户。对于连接的插槽,仅传递EMSGSIZE和EPROTO以实现兼容性。使用IP_RECVERR,所有网络错误都保存在错误队列中。
错误说明
- EACCES
- 用户尝试在没有在套接字上设置广播标志的情况下发送到广播地址。
- EFAULT
- 提供了无效的内存地址。
- EINVAL
- 无效的论点。
- EMSGSIZE
- 包太大。启用了路径MTU发现(IP_MTU_DISCOVER套接字标志),或者数据包大小超过了允许的最大IPv4数据包大小64kB。
- EOPNOTSUPP
- 无效标志已传递给套接字调用(如MSG_OOB)。
- EPERM
- 用户无权打开原始套接字。只有有效用户ID为0或CAP_NET_RAW属性的进程才可以这样做。
- EPROTO
- ICMP错误已到来,报告参数问题。
版本
IP_RECVERR和ICMP_FILTER在Linux 2.2中是新的。它们是Linux扩展,不应在可移植程序中使用。
当设置SO_BSDCOMPAT套接字选项时,Linux 2.0在原始套接字代码中启用了与BSD的一些bug到bug的兼容性。从Linux 2.2开始,此选项不再具有此作用。
备注
默认情况下,原始套接字执行路径MTU(最大传输单元)发现。这意味着内核将跟踪到特定目标IP地址的MTU,并在原始数据包写入超出该值时返回EMSGSIZE。发生这种情况时,应用程序应减小数据包的大小。也可以使用IP_MTU_DISCOVER套接字选项或/ proc / sys / net / ipv4 / ip_no_pmtu_disc文件关闭路径MTU发现,有关详细信息,请参见ip(7)。关闭时,原始套接字将对超出接口MTU的传出数据包进行分段。但是,出于性能和可靠性的原因,不建议禁用它。
可以使用bind(2)调用将原始套接字绑定到特定的本地地址。如果未绑定,则将接收所有具有指定IP协议的数据包。另外,可以使用SO_BINDTODEVICE将原始套接字绑定到特定的网络设备。参见套接字(7)。
仅发送IPPROTO_RAW套接字。如果您确实要接收所有IP数据包,请使用具有ETH_P_IP协议的packet(7)套接字。请注意,与原始套接字不同,数据包套接字不会重组IP片段。
如果要接收数据报套接字的所有ICMP数据包,则通常最好在该特定套接字上使用IP_RECVERR;否则,请执行以下操作:参见ip(7)。
原始套接字可以使用Linux中的所有IP协议,甚至包括在内核中具有协议模块的ICMP或TCP之类的协议。在这种情况下,数据包将同时传递到内核模块和原始套接字。在便携式程序中不应依赖于此,许多其他BSD套接字实现在此都有局限性。
Linux永远不会更改从用户传递的标头(除了按照IP_HDRINCL所述填充一些清零字段外)。这与原始套接字的许多其他实现不同。
原始套接字通常相当不可移植,应在旨在可移植的程序中避免使用。
在原始套接字上发送应该从sin_port获取IP协议;此功能在Linux 2.2中丢失。解决方法是使用IP_HDRINCL。
BUGS
没有描述透明的代理扩展。
设置IP_HDRINCL选项时,数据报将不会被分段,并且仅限于接口MTU。
在Linux 2.2中丢失了设置用于发送sin_port的IP协议的操作。始终使用套接字绑定到的协议或在初始socket(2)调用中指定的协议。
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。