Linux下实现通过抓包获取VLAN ID

2015-01-01 03:05
网络安全技术与应用 2015年10期
关键词:字段网卡内核

0 引言

由于Linux系统强大的网络管理功能,很多网络设备都是基于Linux开发的,通过Linux自带的netfilter模块,以及丰富的开源软件可以打造出功能完善的网络接入设备。其中典型的运用就是虚拟子网VLAN,在交换机上划分多个VLAN子网,并且汇聚到中继口Trunk上,同时网关启用VLAN模块,通过配置对应的VLAN虚拟网卡实现与交换机的互联通讯。目前大多数网卡为了提高数据包的处理能力,直接对报文的VLAN Tag进行移除和插入操作,因此到达内核中的数据包已经不包含VLAN Tag。为了实现对数据包的分析审计等需求,需要知道每个数据包是属于哪个VLAN的。基于这个目的本文通过对数据包的收发流程,抓包原理的分析,提出了一种通过直接修改内核让数据包带上VLAN ID的方法。

1 VLAN概述

现在使用最广泛的VLAN协议标准是 IEEE 802.1Q,许多厂家的交换机,路由器产品都支持IEEE 802.1Q标准。802.1Q Tag的长度是4 bytes,它位于以太网帧中源MAC地址和长度类型之间。802.1Q Tag包含4个字段。

(1)Type:长度为2 bytes,表示帧类型,802.1Q tag帧中Type字段取固定值 0x8100,如果不支持 802.1Q的设备收到802.1Q帧,则将其丢弃。

(2)PRI:priority字段,长度为3 bit,表示 以太网帧的优先级,取值范围是0~7,数值越大,优先级越高。当交换机,路由器发生传输拥塞时,优先发送优先级高的数据帧。

(3)CFI:Canonical Format Indicator,长度为 1bit,表示MAC地址是否是经典格式。CFI为0说明是经典格式,CFI为1表示为非经典格式。该字段用于区分以太网帧、FDDI帧和令牌环网帧,在以太网帧中,CFI取值为0。

(4)VID:VLAN ID,长度为12 bit,取值范围是0~4095,其中0和4095是保留值,不能给用户使用。

图1 VLAN Tag报文格式

2 数据包收发流程

数据包到达网卡以后,网卡判断数据包是否为802.1Q报文,如果是的话则移除VLAN Tag,修改以太网帧,同时把VLAN信息储存在 sk_buff中。网卡驱动从网卡收到的报文,已经不带VLAN tag了。接着通过 netif_rx进入协议栈,netif_rx调用napi_schedule调度,发送 NET_RX_SOFTIRQ软中断,触发net_rx_action执行其 poll操作 process_backlog,接着调用netif_receive_skb来处理收到的skb数据。VLAN模块通过调用dev_add_pack注册了802.1Q的协议类型,将自己的prot_hook 挂到了ptype_all链表中。在netif_receive_skb遍历ptype_all找到对应的VLAN钩子,于是进入了vlan的接收函数vlan_skb_recv,这个函数会移除 VLAN Tag重置以太网层的 proto,再调用netif_rx重新进入协议栈处理流程。由于VLAN Tag已经在网卡上被移除了,实际上并不会进入vlan_skb_recv。不过网卡只会移除第一层VLAN Tag,如果你的报文是QINQ这种双层VLAN的协议,那么第二层VLAN Tag将由vlan_skb_recv来移除。

数据包进入ip_crv以后,根据目的IP进行路由判断,如果是发往本地的报文则进入ip_local_deliver后发往本地应用。如果目的IP不是本机则根据默认路由进入转发模块ip_forward,如果需要 NAT则内核修改数据包的源 IP等信息,接着协议栈通过dev_queue_xmit调用 dev_hard_start_xmit,关联到了具体的网络设备处理函数,从而调用了vlan_dev_hard_start_xmit,在这里插入VLAN Tag头,并压入sk_buffer中,找到真实的网络设备,再次调用dev_queue_xmit,进入网卡驱动,这里只有双层VLAN协议才会由内核插入内层的VLAN TAG,最外层的VLAN TAG由网卡完成插入。

3 Libpcap抓包原理

Libpcap通过创建 AF_PACKET类型的套接字,把自己的prot_hook挂到了ptype_all链表上,AF_PACKET套接字注册的钩子函数是packet_rcv。可以看出无论是接收还是发送的报文,内核都会对ptype_all链表进行遍历,最终会调用到packet_rcv函数,把数据包加入到了 AF_PACKET套接字的接收队列。当应用程式调用recv接收数据包时内核最终会调用packet_recvmsg从接收队列中取出skb,将数据包内容skb->data拷贝到用户空间。

4 修改内核插入VLAN ID

通过上面的分析,我们只要在packet_recvmsg函数里在将数据包拷贝到用户空间的时候将VLAN ID插入到报文的结尾,再通过libpcap等AF_PACKET套接字接口获取数据的时候就可以得到VLAN ID。代码修改如下。

修改前:

修改后:

以发送带有VLAN ID为100的报文为例,下图是交换机发出的报文:

图2 VLAN报文

Linux网关接收到数据包以后将VLAN ID插入结尾:

图3 修改后的VLAN报文

5 总结

通过修改内核的方式使得 AF_PACKET套接字获取的报文携带VLAN ID,为数据包的分析审计提供了基础。

猜你喜欢
字段网卡内核
图书馆中文图书编目外包数据质量控制分析
多内核操作系统综述①
强化『高新』内核 打造农业『硅谷』
活化非遗文化 承启设计内核
部署Linux虚拟机出现的网络故障
Server 2016网卡组合模式
Linux内核mmap保护机制研究
挑战Killer网卡Realtek网游专用Dragon网卡
CNMARC304字段和314字段责任附注方式解析
无正题名文献著录方法评述