预览加载中,请您耐心等待几秒...
1/6
2/6
3/6
4/6
5/6
6/6

在线预览结束,喜欢就下载吧,查找使用更方便

如果您无法下载资料,请参考说明:

1、部分资料下载需要金币,请确保您的账户上有足够的金币

2、已购买过的文档,再次下载不重复扣费

3、资料包下载后请先用软件解压,在使用对应软件打开

Linux网络编程:原始套接字的魔力【下】 星期四,8月232012,10:47下午 可以接收链路层MAC帧的原始套接字 前面我们介绍过了通过原始套接字socket(AF_INET,SOCK_RAW,protocol)我 们可以直接实现自行构造整个IP报文,然后对其收发。提醒一点,在用这种方式构 造原始IP报文时,第三个参数protocol不能用IPPROTO_IP,这样会让系统疑惑,不 知道该用什么协议来伺候你了。 今天我们介绍原始套接字的另一种用法:直接从链路层收发数据帧,听起来好 像很神奇的样子。在Linux系统中要从链路层(MAC)直接收发数帧,比较普遍的做法 就是用libpcap和libnet两个动态库来实现。但今天我们就要用原始套接字来实现这 个功能。 这里的2字节帧类型用来指示该数据帧所承载的上层协议是IP、ARP或其他。 为了实现直接从链路层收发数据帧,我们要用到原始套接字的如下形式: socket(PF_PACKET,type,protocol) 1、其中type字段可取SOCK_RAW或SOCK_DGRAM。它们两个都使用一种与 设备无关的标准物理层地址结构structsockaddr_ll{},但具体操作的报文格式不同: SOCK_RAW:直接向网络硬件驱动程序发送(或从网络硬件驱动程序接收)没有 任何处理的完整数据报文(包括物理帧的帧头),这就要求我们必须了解对应设备的 物理帧帧头结构,才能正确地装载和分析报文。也就是说我们用这种套接字从网卡 驱动上收上来的报文包含了MAC头部,如果我们要用这种形式的套接字直接向网卡 发送数据帧,那么我们必须自己组装我们MAC头部。这正符合我们的需求。 SOCK_DGRAM:这种类型的套接字对于收到的数据报文的物理帧帧头会被系 统自动去掉,然后再将其往协议栈上层传递;同样地,在发送时数据时,系统将会 根据sockaddr_ll结构中的目的地址信息为数据报文添加一个合适的MAC帧头。 2、protocol字段,常见的,一般情况下该字段 取ETH_P_IP,ETH_P_ARP,ETH_P_RARP或ETH_P_ALL,当然链路层协议很 多,肯定不止我们说的这几个,但我们一般只关心这几个就够我们用了。这里简单 提一下网络数据收发的一点基础。协议栈在组织数据收发流程时需要处理好两个方 面的问题:“从上倒下”,即数据发送的任务;“从下到上”,即数据接收的任务。数 据发送相对接收来说要容易些,因为对于数据接收而言,网卡驱动还要明确什么样 的数据该接收、什么样的不该接收等问题。protocol字段可选的四个值及其意义如 下: protocol值作用 ETH_P_IP0X0800只接收发往目的MAC是本机的IP类型的数据帧 ETH_P_ARP0X0806只接收发往目的MAC是本机的ARP类型的数据帧 ETH_P_RARP0X8035只接受发往目的MAC是本机的RARP类型的数据帧 ETH_P_ALL0X0003接收发往目的MAC是本机的所有类型(ip,arp,rarp)的 数据帧,同时还可以接收从本机发出去的所有数据 帧。在混杂模式打开的情况下,还会接收到发往目 的MAC为非本地硬件地址的数据帧。 protocol字段可取的所有协议参见/usr/include/linux/if_ether.h头文件里的定义。 最后,格外需要留心一点的就是,发送数据的时候需要自己组织整个以太网数 据帧。和地址相关的结构体就不能再用前面的structsockaddr_in{}了,而是struct sockaddr_ll{},如下: 点击(此处)折叠或打开 1.structsockaddr_ll{ 2.unsignedshortsll_family;/*总是AF_PACKET*/ 3.unsignedshortsll_protocol;/*物理层的协议*/ 4.intsll_ifindex;/*接口号*/ 5.unsignedshortsll_hatype;/*报头类型*/ 6.unsignedcharsll_pkttype;/*分组类型*/ 7.unsignedcharsll_halen;/*地址长度*/ 8.unsignedcharsll_addr[8];/*物理层地址*/ 9.}; sll_protocoll:取值在linux/if_ether.h中,可以指定我们所感兴趣的二层协议; sll_ifindex:置为0表示处理所有接口,对于单网卡的机器就不存在“所有”的概 念了。如果你有多网卡,该字段的值一般通过ioctl来搞定,模板代码如下,如果我 们要获取eth0接口的序号,可以使用如下代码来获取: 点击(此处)折叠或打开 1.structsockaddr_llsll;