↓引荐关注↓ 前言 关于网络方向的内容,希望对部分读者有辅佐。 WinDivert:https://github.com/basil00/Divert WindivertDotnet:https://github.com/xljiulang/WindivertDotnet 一、WinDivert引见 WinDivert是windows下为数未几的十分优秀网络库,十分合适用于开发抓包或修正包的应用程序,其具有以下才干:
同时WinDivert还提供了完好的loopback(回环)IP、IPv6的支持,简约而强大的Api、高级别的过滤言语(能够想象为sql一样的东西)。 如此优秀的项目自然有着各个言语的二次封装项目,我在github上也找到了对应多个的dotnet封装项目,但无一例外,他们封装的比较粗陋或太过于粗陋,下面是封装项目的一些缺乏之处: 1、IPHeader、TcpHeader、UdpHeader等未提供网络和主机的Endian转换 2、局限于PInvoke,没有认识运用dotnet的对象(好比IPv4直接声明为uint类型) 3、没有面向对象的封装,以至粗陋到只需声明了static的PInvoke措施 4、过滤言语没有任何处置,运用时要翻阅WinDivert的文档(写手sql一个觉得) 5、没有异步IO封装,都是清一色的IO同步阻塞(异步IO封装难度大) 二、WindivertDotnet引见 WindivertDotnet是面向对象的WinDivert的dotnet异步封装,其坚持着完好的底层库才干,又提供dotnet的圆满语法来操作:
由于windows平台是LittleEndian,而规范的IPHeader、TcpHeader、UdpHeader网络定义都是BigEndian,假如未做任何处置,当接纳到一个SrcPort为80、DstPort为443的Tcp包时映射为结构体时,你调式会看到如下结果: 由于没有做Endian自动转换,在调试时看到的数据以至让人抓狂,此时假如你把SrcPort改为我们了解为81端口,你是不能直接写xxx.SrcPort = 81这样的csharp代码的,应该是xxx.SrcPort = 20736。 WindivertDotnet项目花了很大的时间肉体,为一切触及的结构体字段访问时都做了必要的Endian读取和写入自动转换,让调用者不再为Endian问题费脑子。 2.2、分离运用dotnet类型 IPv4地址占用4字节,IPv6地址占用16字节,所以一些封装项目直接在结构体声明为uint SrcAddr和fixed uint SrcAddr[4],当然这些声明是没有错误,但是你叫运用者怎样运用呢,运用者常常是var ipAddress = IPAddress.Parse("1.2.3.4)"得到一个IPAddress类型,他们没有肉体去研讨怎样把IPAddress转为你的uint或uint[4],或者从uint或uint[4]转换为IPAddress类型,再加上运用了uint,又得留意Endian的转换,构成这种封装离实践应用太悠远。 WindivertDotnet在声明字段类型时,当存在对应的dotnet高级类型时,优先运用这些高级类型,除了IPAddress之外,假如字段能够运用枚举的,也都声明为了枚举类型,以至在修正这些属性值时,有严厉的输入校验。 2.3、面向对象的封装 WindivertDotnet将零散的过程式c-api,包装为多种对象,而不是让你面对满天飞的各种静态措施PInvoke调用IntPrt句柄和维护这些句柄的生命周期,例如WinDivertPacket对象,其实质是一个非托管的缓冲区内存,在没有封装之前,它就是一个csharp的IntPrt类型,看到这个类型,你得加个八倍镜察看能够做为参数传给哪些静态Api措施,同时确保不要遗忘不运用之后,要手动去释放它,否则内存就不时占用。 2.4、Filter filter language是WinDivert引以为豪的设计,对WinDivert来说就像是从0到1发明了sql一样,它允许运用简单的文本表白式来让驱动层高性能地过滤得自己感兴味的数据包,好比outbound and !loopback and (tcp.DstPort == 80 or udp.DstPort == 53),这种filter的作用,想必运用过wireshark软件的都特别明白。 缺乏的是,人们在做dotnet封装时,仅仅做了Invoke(string filter)这种传话筒式的封装,好家伙,filter language一共100个字段左右,我保障运用者不翻看filter language宝典的话,肯定不知道怎样结构这个string内容,您好歹从语法层面超越一下,提供一下filter的Builder也好啊。 WindivertDotnet提供Filter类型运用Lambda来结构这个filter language,有了它您不再需求珍藏filter language葵花宝典了,就像运用了EF之后不会sql又何妨呢,由于如下的csharp代码,每个人都打得出: varfilter = Filter.True .And(f => f.Network.Outbound && !f.Network.Loopback) .And(f => f.Tcp.DstPort == 80|| f.Udp.DstPort == 53); 2.5、异步IO封装 没有async和await的IO,那不是圆满的IO,WinDivert提供了可选的LPOVERLAPPED,让上层能够运用IOCP模型,遗憾的是目前没有任何封装项目应用了这个参数,并分离IOCP模型包装为dotnet的Task或ValueTask异步模型。他们都是直接PInvoke运用了Send和Recv这两个api,或者是SendEx之后又同步阻塞等候LPOVERLAPPED的完成,这种和dotnet里的 Task.Wait其实是一个道理,调用工作线程在IO完成之前只能干等,而没法抽身回到线程池中。 WindivertDotnet将LPOVERLAPPED与IOCP模型分离,并封装为dotnet的TAP异步模型,凝结出下面两个中心措施: ValueTask< int> RecvAsync( WinDivertPacket, WinDivertAddress, CancellationToken) ; ValueTask< int> SendAsync( WinDivertPacket, WinDivertAddress, CancellationToken) ; Api措施是简单,但过程迂回,没有资料,受阻无数,哪怕是小小的CancellationToken参数,但它却能让pendding的IO操作撤销下来。 三、总结 因FastGithub项目的需求,所以本项目才得以降生,往常我是分离实践项目的中运用痛点来改进本项目,以至添加了一些WinDivert目前没有的功用,置信本项目越来越好用。
- EOF - 点击题目可跳转 树莓派经过 .NET 6 和libusb操作USB读写 .NET 中表白式动态解析和计算 Flee 用起来真香 .NET 6+微软反向代理组件开发的API网关 看完本文有收获?请转发分享给更多人 引荐关注「DotNet」,提升.Net技艺 点赞和在看就是最大的支持 |