网络系统管理之应用层截包方案与实现
作者:mobiledu2502860487 | 来源:互联网 | 2017-06-19 18:16
文章标题:网络系统管理之应用层截包方案与实现。Linux是中国IT实验室的一个技术频道。包含桌面应用,Linux系统管理,内核研究,嵌入式系统和开源等一些基本分类
引言
截包的需求一般来自于过滤、转换协议、截取报文分析等。
过滤型的应用比较多,典型为包过滤型防火墙。
转换协议的应用局限于一些特定环境。比如第三方开发网络协议软件,不能够与原有操作系统软件融合,只好采取“嵌入协议栈的块”(BITS)方式实施。比如IPSEC在Windows上的第三方实现,无法和操作系统厂商提供的IP软件融合,只好实现在IP层与链路层之间,作为协议栈的一层来实现。第三方PPPOE软件也是通过这种方式实现。
截取包用于分析的目的,用“抓包”描述更恰当一些,“截包”一般表示有截断的能力,“抓包”只需要能够获取即可。实现上一般作为协议层实现。
本文所说的“应用层截包”特指在驱动程序中截包,然后送到应用层处理的工作模式。
截包模式
用户态下的网络数据包拦截方式有
1.Winsock Layered Service Provider;
2.Windows 2000 包过滤接口;
3.替换系统自带的WINSOCK动态连接库;
利用驱动程序拦截网络数据包的方式有
1.TDI过滤驱动程序(TDI Filter Driver)
2.NDIS中间层驱动程序(NDIS Intermediate Driver)
3.Win2k Filter-Hook Driver
4.NDIS Hook Driver
用户态下拦截数据包有一些局限性,“很显然,在用户态下进行数据包拦截最致命的缺点就是只能在Winsock层次上进行,而对于网络协议栈中底层协议的数据包无法进行处理。对于一些木马和病毒来说很容易避开这个层次的防火墙。”
我们所说的“应用层截包”不是指上面描述的在用户态拦截数据包。而是在驱动程序中拦截,在应用层中处理。要获得一个通用的方式,应该在IP层之下进行拦截。综合比较,本文选用中间层模式。
为什么要在应用层处理截取的报文
一般来说,网络应用如防火墙,协议类软件都是工作在内核,我们为什么要反过来,提出要在应用层处理报文呢?理由也可以找出几点(哪怕是比较牵强):
众所周知,驱动程序开发有一定的难度,对于一个经验丰富的程序员来说,或许开发过程中不存在技术问题,但是对初学者,尤其是第一次接触的程序员简直是痛苦的经历。
另外,开发周期也是一个不得不考虑的问题。程序工作在内核,稳定性/兼容性都需要大量测试,而且可供使用的函数库相对于应用层来说相当少。在应用层开发,调试修改相对要容易地多。
不利的因素也有:
性能影响,在应用层工作,改变了工作模式,每当驱动程序截到数据,送到应用层处理后再次送回内核,再向上传递到IP协议。因此,性能影响非常大,效率非常低,在100Mbps网络上,只有80%的性能表现。
综合来看,在特定的场合应用还是比较适合的:
台式机上使用,台式机的网络负载相当小,不到100Mbps足以满足要求,尤其是主要用于上网等环境,网络连接的流量不到512Kbps,根本不用考虑性能因素。作为单机防火墙或其他一些协议实现,分析等很容易基于这种方式实现。
方案
模型
上图描述了应用层截包的模型,主要的流程如下:
接收报文过程:
1.网络接口收到报文,中间层截取,通过2送到应用层处理;
2.应用层处理后,送回中间层处理结果;
3.中间层根据处理结果,丢弃该报文,或者将处理后的报文通过1送到IP协议;
4.IP协议及上层应用接收到报文;
发送报文过程:
1.上层应用发送数据,从而IP协议发送报文;
2.报文被中间层截取,通过2送到应用层处理;
3.应用层处理后,送回中间层处理结果;
4.中间层根据处理结果,丢弃该报文,或者将处理后的报文发送到网络上;
实现细节探讨
IO与通讯
有一个很容易的方式,在驱动程序和应用程序之间用一个事件。
在应用程序CreateFile的时候,驱动程序IoCreateSynchronizationEvent一个有名的事件,然后应用程序CreateEvent/OpenEvent此有名事件即可。
注意点:
1,不要在驱动初始化的时候创建事件,此时大多不能成功创建;
2,让驱动先创建,那么此后应用程序打开时,只能读(Waitxxxx),不能写(SetEvent/ResetEvent)。反之,如果应用程序先创建,则应用程序和驱动程序都有读写权限;
3,用名字比较理想,注意驱动中名字在\BaseNamedObjects\下,例如应用程序用“xxxEvent”,那么驱动中就是“\BaseNamedObjects\xxxEvent”;
4,用HANDLE的方式也可以,但是在WIN98下是否可行,未知。
5,此后,驱动对读请求应立即返回,否则就返回失败。不然将失去用事件通知的意义(不再等待读完成,而是有需要(通知事件)时才会读);
6,应用程序发现有事件,应该在一个循环中读取,直到读取失败,表明没有数据可读;否则会漏掉后续数据,而没有及时读取;
处理线程优先级
应用层处理线程应该提高优先级,因为该线程为其他上层应用程序服务,如果优先级比其他线程优先级低的话,将会发生类似死锁的等待状态。
另外,提高优先级的时候必须注意,线程尽量缩短运行时间,不要长期占用CPU,否则其他线程无法得到服务。优先级不必提高到REALTIME_PRIORITY_CLASS级,此时线程不能做一些磁盘IO之类的操作,而且也影响到鼠标、键盘等工作。
驱动程序也可以动态地提高线程的优先级。
缓存
在驱动程序接收到报文后,至少应该有一个缓冲以便临时存储,等待应用层处理。缓冲不必很大,只要能在应用层得到时间片之前缓冲区不溢出就可以了,实践中大约能存储几十个报文就够了。
缓冲的使用方式,是一个先进先出的队列。考虑方便实现为静态存储的环形队列,也就是说,不必每次分配内存,而是一次性分配好一大块内存,环形的使用。
初始,head==tail==0;
tail和head都是无限增长的。
Tail ? head <= size;
放入一个报文时, tail=tail + packetlen;
取出一个报文时,head=head + packetlen;
tail== head表明空;
tail>head表明有数据;
tail + input packet length - head >size表明满;
取数据时:
ppacket GetPacket()
{
ASSERT(tail>=head);
if(tail==head)
return NULL;
//else
ppacket = &start[head % SIZE];
if(head % size + ppacket->length > size )
//数据不连续(一部分在尾部,一部分在头部);
else
//数据是连续的
return ppacket;
}
放入数据:
bool InputPacket(ppacket)
{
if(tail + input packet length - head >size) //满
return false;
//copy packet to &start[tail % SIZE]
//if(tail % SIZE + packet length > SIZE)
//数据不连续(一部分在尾部,一部分在头部);
//else
//数据是连续的
tail = tail + packet length;
return true;
}
上面这种方式采用数组的方式组织,为每个报文提供一个最大报文长度的空间。因为缓冲区数目有限,因此这种方式可以满足需要。如果要考虑到减少空间的浪费,那么可以按每个报文的实际长度存储,上面的算法不能够适应这种方式。
应用层和驱动程序的通信
在网卡接收/IP发送过程中,驱动程序缓存报文,用事件通知应用层有报文需要处理。那么应用层可以通过IO方式或者共享内存方式取得此报文。
实践说明,在100Mbps速率下,以上两种方式都可以满足需要,最为简便的方式就是使用有缓冲的IO方式。
应用层处理完毕,也可以使用以上两种方式之一来向驱动程序递交结果。不过,IO方式因为一次只能发送一个报文,100Mbps网络速度下降为70%~80%网络速度,10Mbps不会有影响。也就是说,主机发出的最大速度只有70%的网络速度,这和应用程序发送不超过MTU的UDP数据报的速度是一样的。对TCP来说,由于是双向通信,损失更加大一些,大约40%~60%速度。
这时候,使用共享内存方式,因为减少了系统调用的开销,可以避免速度下降。
报文发送的速度控制
当IP协议发送报文的时候,一般来说,我们的中间层驱动必须把这些报文缓存起来,告诉IP软件发送成功,然后让应用层处理完毕之后再做决定。显然,存储报文的速度远远超过网卡能够发送的速度,然而IP软件(特别是UDP)将以我们存储的速度发送报文。造成缓存迅速耗尽。后续的报文只好丢弃。这样一来,UDP发送将不能正常工作。TCP由于可以自行适应网络状况,依然可以在这种情况下工作,速度在70%左右。在Passthru里,可以转发至低层驱动,然后用异步或同步方式返回,从而达到网卡的发送速度一致。
因此,必须有一个办法避免这种状况。中间层驱动把这些报文缓存起来,告诉IP软件发送状态未决(Pending)。等到最后处理完毕,告诉IP软件发送完成。从而协调了发送速度。这种方式带来一个问题,就是驱动程序必须在发送超时的情况下放弃对这些缓冲报文的所有权。具体来说,就是MiniportReset被调用的时候,就有可能是NDIS察觉到发送超时,从而放弃所有未完成的发送操作,如果没有正确处理这种情况,将会导致严重问题。如果中间层在Miniport初始化的时候通过调用NdisMSetAttributesEx函数设置了NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT标志,那么中间层驱动程序将不会得到报文超时通知,中间层必须自行处理缓存的报文。
与Passthru协同工作
当上层应用不再需要截包时,驱动程序应该完全是Passthru行为。这就要
推荐阅读
-
本文介绍了提升Python编程效率的十点建议,包括不使用分号、选择合适的代码编辑器、遵循Python代码规范等。这些建议可以帮助开发者节省时间,提高编程效率。同时,还提供了相关参考链接供读者深入学习。 ...
[详细]
蜡笔小新 2023-12-14 21:51:04
-
本文是一位90后程序员分享的职业发展经验,从年薪3w到30w的薪资增长过程。文章回顾了自己的青春时光,包括与朋友一起玩DOTA的回忆,并附上了一段纪念DOTA青春的视频链接。作者还提到了一些与程序员相关的名词和团队,如Pis、蛛丝马迹、B神、LGD、EHOME等。通过分享自己的经验,作者希望能够给其他程序员提供一些职业发展的思路和启示。 ...
[详细]
蜡笔小新 2023-12-14 15:22:09
-
-
本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ...
[详细]
蜡笔小新 2023-12-14 14:53:02
-
本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ...
[详细]
蜡笔小新 2023-12-14 12:05:06
-
本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ...
[详细]
蜡笔小新 2023-12-13 17:45:15
-
篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ...
[详细]
蜡笔小新 2023-12-13 13:04:08
-
本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ...
[详细]
蜡笔小新 2023-12-13 10:00:57
-
本文介绍了在Mac上安装Xamarin并使用Windows上的VS开发iOS app的方法,包括所需的安装环境和软件,以及使用Xamarin.iOS进行开发的步骤。通过这种方法,即使没有Mac或者安装苹果系统,程序员们也能轻松开发iOS app。 ...
[详细]
蜡笔小新 2023-12-11 19:13:35
-
近日,OpenAI发布了最新的NLP模型GPT-3,该模型在GitHub趋势榜上名列前茅。GPT-3使用的数据集容量达到45TB,参数个数高达1750亿,训练好的模型需要700G的硬盘空间来存储。一位开发者根据GPT-3模型上线了一个名为debuid的网站,用户只需用英语描述需求,前端代码就能自动生成。这个神奇的功能让许多程序员感到惊讶。去年,OpenAI在与世界冠军OG战队的表演赛中展示了他们的强化学习模型,在限定条件下以2:0完胜人类冠军。 ...
[详细]
蜡笔小新 2023-12-11 11:04:43
-
svnWebUI是一款图形化管理服务端Subversion的配置工具,适用于非程序员使用。它解决了svn用户和权限配置繁琐且不便的问题,提供了现代化的web界面,让svn服务端管理变得轻松。演示地址:http://svn.nginxwebui.cn:6060。 ...
[详细]
蜡笔小新 2023-12-11 11:01:10
-
SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ...
[详细]
蜡笔小新 2023-12-11 08:21:41
-
本文讨论了读书的目的以及学习算法的重要性,并介绍了两个算法:除法速算和约瑟夫环的数学算法。同时,通过具体的例子和推理,解释了为什么x=x+k序列中的第一个人的位置为k,以及序列2和序列3的关系。通过学习算法,可以提高思维能力和解决问题的能力。 ...
[详细]
蜡笔小新 2023-12-10 20:15:26
-
本文介绍了学习恶意软件分析和逆向工程领域时最适合的编程语言,并重点讨论了Python的优点。Python是一种解释型、多用途的语言,具有可读性高、可快速开发、易于学习的特点。作者分享了在本地恶意软件分析中使用Python的经验,包括快速复制恶意软件组件以更好地理解其工作。此外,作者还提到了Python的跨平台优势,使得在不同操作系统上运行代码变得更加方便。 ...
[详细]
蜡笔小新 2023-12-10 18:39:23
-
本文介绍了Java集合库的使用方法,包括如何方便地重复使用集合以及下溯造型的应用。通过使用集合库,可以方便地取用各种集合,并将其插入到自己的程序中。为了使集合能够重复使用,Java提供了一种通用类型,即Object类型。通过添加指向集合的对象句柄,可以实现对集合的重复使用。然而,由于集合只能容纳Object类型,当向集合中添加对象句柄时,会丢失其身份或标识信息。为了恢复其本来面貌,可以使用下溯造型。本文还介绍了Java 1.2集合库的特点和优势。 ...
[详细]
蜡笔小新 2023-12-10 17:57:40
-
本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ...
[详细]
蜡笔小新 2023-12-10 15:40:37
-
mobiledu2502860487
这个家伙很懒,什么也没留下!