常用的tcp和udp编程只能读写tcp和udp的数据,而原始套接字则具有下述三种能力:
1、可以读写ICMPV4、IGMPV4和IGMPV6的数据。
这样的话就不用自己组包了,就像tcp一样填充一些套接字就可以了,比较简便。
2、可以处理内核不认识的ip数据报,大部分的内核只处理ip协议字段值为1(icmp)、2(igmp)、6(tcp)和17(udp)的分组。像OSPF路由协议直接使用ip协议,将ip协议字段值填充为89,这样内核就不认识了,只能采用原始套接字来处理。
3、可以自行构造ipv4首部。
后面会举例说明
一、创建原始套接字
socket函数原型:
int socket(int domain, int type, int protocol);
原始套接字的编程主要是t注意ype和protocol的赋值,type取值为SOCK_RAW,而protocol得取值一般为IPPROTO_XXX,
如IPPROTO_IGMP。
int fd;
fd=socket(AF_INET,SOCK_RAW,IPPROTO_IGMP);
二、原始套接字的输入
就是内核把ip数据报输入给原始套接字。在这之前先讨论下内核会把什么样子的ip数据报交给套接字。
(1)若接收到的ip分组协议字段说明其数据部分是tcp或udp分组则不会将该ip分组交给套接字。
(2)对于ICMP分组,大多数内核在处理完ICMP分组中的消息后传递到原始套接字(这个不太理解,内核既然处理完为何还要交给原始套接字呢?),而Berkeley 则是内核处理ICMp回射请求、时间戳请求和地址掩码请求,剩下的icmp消息传递给原始套接字。
(3)所有的IGMP分组在内核处理完其中的IGMP消息后交给原始套接字。
(4)内核将所有协议字段不认识的ip报文交给原始套接字处理,内核只对这些ip报文做最基本的处理:目的ip检测、首部监测等。
(5)如果ip报文有分片,在所有的分片没有全部到来重组成完整的ip报文之前,内核不会把单个ip分片交给原始套接字。
接下来说内核会把收到的ip报文交给哪个原始套接字呢?
内核会对所有进程的所有原始套接字做检查,只有以下三个测试均为真内核才会把ip报文交给这个原始套接字。
(1)创建原始套接字时第三个参数protocol非0时,收到的ip分组的协议字段值必须与该protocol相同。
(2)如果该原始套接字已经被bind绑定到某个ip,则收到的ip分组的目的地址必须与该ip相同。
(3)如果该原始套接字已经被connect调用指定了对端ip,则收到的ip分组的源地址与该ip相同
在ipv4中传递给原始套接字所在进程的都是完整的ip报文,而在ipv6中传递的是净菏。
阅读(713) | 评论(0) | 转发(0) |