【数据包捕获技术】libpcap原理

在当前高速网络环境中,如何实时、高效、完整、快速捕获数据包是能否准确分析网络数据的基础和网络安全防护系统的关键技术。目前已经有从硬件/软件/软硬结合多种解决方案被不断的提出,用于提升数据包转发与捕获的性能。

libpcap (Packet Capture Library),即数据包捕获函数库,是 Unix/Linux 平台下的网络数据包捕获函数库。它是一个独立于系统的用户层包捕获的 API 接口,为底层网络监测提供了一个可移植的框架。

libpcap 工作原理

libpcap 主要由两部份组成:

  • 网络分接头(Network Tap)
  • 数据过滤器(Packet Filter)

网络分接头从网络设备驱动程序(NIC driver)中收集数据拷贝,过滤器决定是否接收该数据包。

Libpcap的工作原理可以描述为,当一个数据包到达网卡时,通过网络分接口(即旁路机制)将数据包发给BPF(BSD Packet Filter)过滤器,匹配通过的数据包可以被libpcap利用创建的套接字PF_PACKET从链路层驱动程序中获得。进而在用户空间提供独立于系统的用户级API接口。

libpcap 包处理路径

libpcap 包捕获机制是在数据链路层增加一个旁路处理,并不干扰系统自身的网路协议栈的处理,对发送和接收的数据包通过Linux内核做过滤和缓冲处理,最后直接传递给上层应用程序。因此libpcap在捕获到达网卡的数据包后绕开了传统linux协议栈处理,直接使用链路层PF_PACKET协议族原始套接字方式向用户空间传递报文。

  • 网卡

       接收网络报文。

  • 内核空间

网络设备在接收到一个报文之后,通过中断IRQ告知CPU。网卡驱动程序需要注册对该中断事件的处理函数,以处理接收到的报文。在中断中执行以下操作:

分配一个缓冲区sk_buff,把接收的数据拷贝进去;(第一次拷贝)
对缓冲区结构内的一些参数做初始化以告知协议数据是什么类型skb->protocol;
非NAPI:调用netif_rx( )函数通知内核,将帧放入CPU的softnet_data->input_pkt_queue。netif_rx会调用网络接口函数netif_rx_schedule(使用softdate_net结构中内嵌的backlog_dev作为dev参数)
NAPI:帧存放在每个设备自己的队列之中。调用netif_rx_schedule函数(直接以对应设备的dev结构为参数)

然后触发相关联的软IRQ--NET_RX_SOFTIRQ,此时网卡驱动程序已经将输入设备排入轮询列表poll_list,接下来执行net_rx_action函数:

浏览poll_list设备列表,这些设备的入口队列都有数据;
非NAPI:执行process_backlog函数(backlog_dev->poll)。若时间片用完或者配额用尽,将该设备放置列表尾部等待下一次中断到来时继续被调用;若处理完input_pkt_queue列表中的全部报文,则将设备退出poll_list同时打开设备中断服务继续监听下一个报文到来。

NAPI:执行poll函数。dev->poll可以做一些轮询的工作,如果网络设备已经接收了多个报文,可以一次性处理。就算设备此刻所接收到的报文都已经处理完了,驱动程序也可以根据某种方式预判设备在很短的一段时间内还将收到报文,于是依然将自己对应的dev结构留在poll_list中,处于轮询状态。增大了报文接收的平均延时,但避免了大量中断带来的开销。dev设备退出poll_list同时打开设备中断服务。

接着调用netif_receive_skb函数:

如果有抓包程序,由网络分接口进入BPF过滤器,将规则匹配的报文拷贝到系统内核缓存 (第二次拷贝)否则直接丢弃数据包;*注 : linux 在 PF_PACKET 类型的 socket 上支持内核过滤。Linux 内核允许我们把一个名为 LPF(Linux Packet Filter) 的过滤器直接放到 PF_PACKET 类型 socket 的处理过程中,过滤器在网卡接收中断执行后立即执行 
处理数据链路层的桥接功能;
根据skb->protocol字段确定上层协议并提交给网络层处理-->进入网络协议栈

  • 用户空间

libpcap绕过了Linux内核收包流程中协议栈部分的处理,使得用户空间API可以直接调用套接字PF_PACKET从链路层驱动程序中获得数据报文的拷贝,将其从内核缓冲区拷贝至用户空间缓冲区(第三次拷贝)

fd=socket(PF_PACKET,sock_RAW,htons(ETH_P_ALL))
libpcap 函数库注册的报文接收类型为 ETH_P_ALL,即接收所有的网络数据帧,其处理函数为 packet_rcv()。该函数工作在数据链路层。

进而调用recvfrom函数获得捕获的报文 (需要进行系统调用):

packet_rcv() 函数将直接调用 skb_queue_tail() 将数据报文存放在代表相应网络连接控制结构(struct sock)的接收队列 receive_queue 中。这样数据报文在接收过程中就绕过了 TCP 层和 IP 层繁琐的协议处理过程。最后,睡眠在 sk 等待队列上的函数 packet_recvmsg() 会接收链路层数据帧并将该数据帧直接拷贝到应用程序缓冲区中。

  • 最后libpcap面向用户空间提供独立于系统的可调用的函数接口

BPF过滤器

 BPF本质上来说是一个设备驱动(devicedriver),能够被应用程序用来读取网络上通过这个网络适配器的包。
BPF正常情况下被用作诊断工具去检查与本机相连的网络的流通状况。一个BPF设备能够配置一个filter,根据这个filter的特征,来忽略或者接收到来的包。
BPF拥有两个组件:thenetworktap和thepacketfilter。thenetworktap收集来自网络设备驱动的包的一个拷贝,并把它专递给监听程序。thepacketfilter决定是否接收这个包并且把它拷贝给监听程序
BPF为每一个要求服务的抓包程序关联一个filter和两个buffer。BPF分配buffer且通常情况下它的额度是4KBthestorebuffer被使用来接收来自适配器的数据;theholdbuffer被使用来拷贝包到应用程序
通常情况下,当一个包到达网络接口时,数据链路设备驱动将把它发送到系统协议栈。但是当BPF在这个接口上面监听时,网络设备驱动将首先调用BPF的networktap函数。这个tap函数将包送入每一个监听程序的filter。而用户定义的filter决定:是否接收这个包;每一个包有多少字节将会被保存。如果filter接收这个包,那么tap将会从数据链路层驱动的缓存中拷贝这个数目的字节数到与这个filter关联的storebuffer中(storebuffer在内核中定义)。同时,网络接口的设备驱动将会重新获得控制权,且正常的协议处理将会进行。

在这里插入图片描述

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wufeng无峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值