这也许不是什么问题,很多人会觉得使用tcpdump抓包,然后用Wireshark来过滤即可,但如果不能那么做呢?如果必须要仅仅抓取特定URL访问的TCP包呢?也许你会说,这又有何难...
我先来告诉你直接的难度吧,间接且更加重要问题的后面再谈。直接的难度就是抓包这个动作发生在网卡层面,特别底层,BPF是无状态的,它能过滤的只能基于“每个包必有的字段”至于说HTTP协议,并不是每一个包都上都写着自己是个HTTP的包。每包必有的只是协议元组信息而已。要想识别HTTP协议,并且识别访问特定的URL,必须记录状态,问题是到底在内核记录还是在用户态记录。
要不是跟工作相关,换做以前,我可能一个通宵就能搞定N个实现,以下是想到的方法:
1.使用nf_conntrack机制,识别HTTP协议的Request,打上特定MARK,然后使用Netfilter钩子将数据包Log到Netlink进而导入用户态;
2.给socket添加一个opt,应用程序自己设置这个opt,告诉内核要不要抓这个包,这是在socket层面的解决方案;
3.在packet_rcv函数中调用conntrack钩子,类似net.bridge.bridge-nf-call-iptables所做的那样,这样可以天然过滤任何流;
但是事实上我并没有完成任意一个,工作和爱好不同,爱好可以随意但工作不能,要有所顾忌,不是要引发能怎么做的头脑风暴,而是要时刻提醒自己什么东西做了也没卵用。前两个我就不多说了,实现起来非常简单,但是不能用tcpdump所依赖的pcap了,因为机制完全不同,况且nf_conntrack也是大为诟病,即便你不接纳nf_conntrack,第二个方案要求修改应用程序,也是无法推动的。第三个方案呢,好像不错的选择,但是如果你知道在netif_receive_skb中,pcap逻辑和协议栈逻辑是串行执行的话,就会马上意识到conntrack的开销最终还是算在了协议栈的头上,这不划算。如果接纳了方案三,接下来就要考虑如何并行化处理协议栈和pcap,其实就是为packet套接字另辟一块生存空间,这个不难,但是作为你领薪水的工作的一部分,很难很难。要么你默默地搞,要么就不要开工,不然烂尾了会很痛苦。
上周四下班的路上,我在班车上跟之前的同事微信聊了一路,看看怎么能实现这个需求,我会感激不尽,同事直接说这有何难,这没有意义之类的,也有给我提出一些开源方案的,但是看后觉得不行,不过也还是谢谢他们,之后的一天,上周五下班后,我没有回家,直接去找A公司的一个朋友,喝酒聊技术,聊的就是这个需求,人家直接说,他们公司用的就是方案2,即用户态程序直接告诉内核哪些包需要搞上来!我们知道IP层有一个early demux机制,在IP层就可以将一个skb关联给一个socket,然后查看这个socket上有没有抓包标志,有的话就直接Netlink给用户态的dump程序,这简直跟我的想法一模一样啊。酒足饭饱,回家后我还在思考,一定要有一个不用改应用程序的方案,也不能改内核,如果必须要改,那就改tcpdump吧!
第二天是周末,大致看了tcpdump的代码,感觉比较简单,很像很像OpenVPN的代码,就一个大的while循环。我觉得很简单就能搞定,于是做出以下这个流程图:
本来想着花一个夜晚把代码实现,然后默默地用起来,但是周末的时间毕竟不是我自己的,用多了会被骂,于是就搁置了...我抱怨时间不足,这是实话。就这样,我的这个抓取访问特定URL的TCP包的代码就付诸流水了,昨天,我们又讨论起这个需求,起了个好听一点的名字,叫做HTTPDump,Linux名字应该叫做httpdump,urldump或者hdump吧。
好吧,一切都是往事了,我想说的最后一点就是性能问题。你知道libpcap的效率吗?请自行google。在万兆网络下,CPU才是瓶颈!不管BPF多么有效,也都是浮云!如果你要用tcpdump加-w参数存文件,请问你用的是SSD吗?如果可以用SSD,我为什么不直接用内存盘呢?还比SSD更快!事实上我可以告诉你,就算用内存盘,使用pcap还是会有10%的丢包,也就是“drop by kernel”。如果在tcpdump中加入了状态判断,也就是上面的那个流程图的处理,在纯万兆环境下能hold住吗?我心存疑!因此,我建议使用PF_RING来替换PF_PACKET,或者直接使用旁路的DPDK,要么就是直接做端口镜像,然后使用一台专门的机器捕捉数据包,事后离线分析,想在一台机器上既处理业务又无丢失地抓包,这是不可能的!
特意专项感谢,我的几位朋友,WEB高手,各种高性能代理服务器,SSL卸载专家,HTTPS专家,虚拟化专家,可以通过我与他们取得联系。西装皮鞋,终有所终。
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow