用户态 tcpdump 怎样实现抓到内核网络包的?
今天聊聊大家工作中经常用到的 tcpdump。
在网络包的发送和接收过程中,绝大部分的工作都是在内核态完成的。那么问题来了,我们常用的运行在用户态的程序 tcpdump 是那如何实现抓到内核态的包的呢?有的同学知道 tcpdump 是基于 libpcap 的,那么 libpcap 的工作原理又是啥样的呢。如果让你裸写一个抓包程序,你有没有思路?
按照小编的风格,不搞到最底层的原理咱是不会罢休的。所以我对相关的源码进行了深入分析。通过本文,你将彻底搞清楚了以下这几个问题。
tcpdump 是如何工作的?ASP站长网 netfilter 过滤的包 tcpdump 是否可以抓的到? 让你自己写一个抓包程序的话该如何下手? 借助这几个问题,我们来展开今天的探索之旅!
网络包接收过程 在之前的文中我们详细介绍了网络包是如何从网卡到达用户进程中的。这个过程我们可以简单用如下这个图来表示。
找到 tcpdump 抓包点 我们在网络设备层的代码里找到了 tcpdump 的抓包入口。在 __netif_receive_skb_core 这个函数里会遍历 ptype_all 上的协议。还记得上文中我们提到 tcpdump 在 ptype_all 上注册了虚拟协议。这时就能执行的到了。来看函数:
//file: net/core/dev.c static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) { ...... //遍历 ptype_all (tcpdump 在这里挂了虚拟协议) list_for_each_entry_rcu(ptype, &ptype_all, list) { if (!ptype->dev || ptype->dev == skb->dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype; } } } 在上面函数中遍历 ptype_all,并使用 deliver_skb 来调用协议中的回调函数。
//file: net/core/dev.c static inline int deliver_skb(...) { return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); } 对于 tcpdump 来说,就会进入 packet_rcv 了(后面我们再说为啥是进入这个函数)。这个函数在 net/packet/af_packet.c 文件中。
//file: net/packet/af_packet.c static int packet_rcv(struct sk_buff *skb, ...) { __skb_queue_tail(&sk->sk_receive_queue, skb); ...... } 可见 packet_rcv 把收到的 skb 放到了当前 packet socket 的接收队列里了。这样后面调用 recvfrom 的时候就可以获取到所抓到的包!!
再找 netfilter 过滤点 (编辑:焦作站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |