无聊看看网络驱动,资料来源于 NT4 ROS 毛德操 以及网络上搜到的乱七八糟。。。没玩过win7不涉及WFP..
数据结构名称都来自NT4和DDK,流程主要参考NT4,只是围观一下设计思路,顺便记录点要点,与现在的xp版本肯定有不少细节上的出入~ 
ROS的网络部分只是实现到将就能用的程度,很多不健全,各种BUKOP,比如UDP丢包率很大。。

应用程序调用winsock函数实现于Msafd.dll ,由afd.sys对socket对象的数据进行整合和存储,然后将相应的操作向传输层下发。Winsock函数和afd.sys的函数功能基本是有对应关系的。。

看过应用层部分基本可以围观传说中的TDI过滤了。。。

一、初始化

建立一个socket

SOCKET WSASocket(
__in          int af,     //地址族  AF_INET是IPV4
__in          int type,    //传输类型 SOCK_STREAM 是传输协议方式
__in          int protocol, //传输规程。。IPPROTO_TCP 用于 TCP IPv4 & 6
__in          LPWSAPROTOCOL_INFO lpProtocolInfo,
__in          GROUP g,
__in          DWORD dwFlags
);

据af type protocol  找到相对应的协议驱动(SockGetTdiName),例如TCPIP.sys

Socket是设备对象\device\afd\endpoint 的一个文件对象的对应句柄,SOCKET就是文件对象的句柄
其EA信息中记录了属性,EA包含一个AFD_OPEN_PACKET 和传输协议名,由NtCreateFile带入内核.

进入了AfdCreate,其重要工作就是权限检查、初始化ENDPOINT结构、将EA等信息整合于文件对象的FsContext中(AFD_ENDPOINT)。
并且将endpoint记录于AfdEndpointListHead。

二、操作

endpoint->Context是一个上下文,存储着socket对象的一些状态信息,结构如下
SOCKET_INFORMATION structure

Helper DLL Context Length

Local Address

Remote Address

Helper DLL Context

接下来的操作中,用户态的函数在操作前后分别用IOCTL_AFD_GET_CONTEXT 和 IOCTL_AFD_SET_CONTEXT来查询和变更状态。

将Sock绑定于一个本地地址,Tcp中服务的一方会调用此函数绑定地址和端口号

int
WSPBind(
IN SOCKET  s,
IN const struct sockaddr FAR  *name,    //地址
IN int  namelen,
OUT LPINT  lpErrno
);

将数据处理一下,构成PTRANSPORT_ADDRESS  发送IOCTL_AFD_BIND。
绑定成功之后还要发送一个 IOCTL_AFD_GET_ADDRESS,是否因为应用程序可以不关心本地地址由系统指派,所以绑定完还要查询一下?

afd!AfdBind
首先判断是否是重复链接相同端口且协议相同,如是则返回STATUS_SHARING_VIOLATION

传入的PTRANSPORT_ADDRESS将记录于 endpoint->LocalAddressLength

用EA信息记录 链接地址(名字是TdiTransportAddress,一般tdi过滤是从这开始:记录进程,请求地址和端口),用ZwCreateFile打开协议驱动(tcpip.sys)
将其文件对象记录于 endpoint->AddressFileObject ,句柄endpoint->AddressHandle(这一操作在attach到系统进程才进行) 。
进入tcpip!TCPCreate将为endpoint->AddressFileObject->FsContext填充一个 _TCP_CONTEXT结构,FsContext2设置为TDI_TRANSPORT_ADDRESS_FILE
最后调用AfdSetEventHandler设置其各种事件处理例程。

作为服务端,绑定之后可以监听了

int
WSPListen(
IN SOCKET  s,
IN int  backlog,    //设置了监听队列未处理 的对大数量
OUT LPINT  lpErrno
);

填充一个AFD_LISTEN_INFO,发送IOCTL_AFD_START_LISTEN

AfdStartListen
根据backlog准备好足够的连接对象AFD_CONNECTION,挂入Endpoint->Common.VcListening.FreeConnectionListHead的链表中
向tcpip发送TDI_SET_EVENT_HANDLER,设置一个回调事件TDI_EVENT_CONNECT为AfdConnectEventHandler(TDI过滤时可以替换这个回调),当tcpip接收到一个连接请求时会调用这个函数。
AfdConnectEventHandler
如果有一个IOCTL_WAIT_FOR_LISTEN的irp(由WSPAccept发送),将完成之。如果没有,将填充AFD_CONNECTION并把它挂入队列。

SOCKET            服务端接受链接请求
WSPAccept
(
IN SOCKET Handle,OUT struct sockaddr *SocketAddress,OUT int *SocketAddressLength,IN LPCONDITIONPROC lpfnCondition,IN DWORD dwCallbackData,OUT LPINT lpErrno
)

IOCTL_WAIT_FOR_LISTEN
缓冲是一个AFD_LISTEN_RESPONSE_INFO结构
如果没有现成的链接(即Endpoint->Common.VcListening.UnacceptedConnectionListHead是空的),就把irp挂入endpoint->Common.VcListening.ListeningIrpListHead
将一个connection地址填充到AFD_LISTEN_RESPONSE_INFO中,连接对象也挂入了endpoint->Common.VcListening.ReturnedConnectionListHead

在irp成功完成之后,如果 lpfnCondition不为空:
发送 IOCTL_AFD_GET_UNACCEPTED_CONNECT_DATA,取回connection->ConnectDataBuffers中的数据,回调lpfnCondition让服务器判断是否响应

创建一个新的socket,放到AFD_ACCEPT_INFO结构中,发送 IOCTL_AFD_ACCEPT接受连接

AfdAccept得到新建立socket的endpoint
AfdAcceptCore建立连接,填充AcceptEndpoint的结构,大多是由ListenEndpoint继承而来,connection->Endpoint = AcceptEndpoint;

int
WSPConnect(
IN SOCKET  s,
IN const struct sockaddr FAR  *name,
IN int  namelen,
IN LPWSABUF  lpCallerData,
OUT LPWSABUF  lpCalleeData,
IN LPQOS  lpSQOS,
IN LPQOS  lpGQOS,
OUT LPINT  lpErrno
);

初始化一个TDI_REQUEST_CONNECT结构,发送IOCTL_AFD_CONNECT

AfdConnect
调用AfdCreateConnection创建一个连接对象,并且向传输层ZwCreateFile,EA名字是TdiConnectionContext,内容是连接对象(connection object)

进入TCPCreate,这里也是可TDI过滤的地方。

然后还要发送IOCTL_TDI_ASSOCIATE_ADDRESS 将endpoint和 连接的addr联系起来。

接着调用TdiBuildConnect,发送一个TDI_CONNECT 到传输层,tcp连接的细节比较复杂,等到看传输层的时候再看

三、收发
在应用层 收数据和发数据没太大区别

发送数据

int WSPSend(
__in          SOCKET s,
__in          LPWSABUF lpBuffers,
__in          DWORD dwBufferCount,
__out         LPDWORD lpNumberOfBytesSent,
__in          DWORD dwFlags,
__in          LPWSAOVERLAPPED lpOverlapped,
__in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
__in          LPWSATHREADID lpThreadId,
__out         LPINT lpErrno
);

填充AFD_SEND_INFO,发送IOCTL_AFD_SEND

AfdSend  数据的发送,可能来自DeviceIoCtrl 也可能来自于WriteFile

TdiBuildSend,向下层发送 TDI_SEND ,完成函数AfdRestartSend中会对尚未发送完的数据继续调用TdiBuildSend进行发送

接收数据

int
WSPRecv(
IN SOCKET  s,
IN/OUT LPWSABUF  lpBuffers,
IN DWORD  dwBufferCount,
OUT LPDWORD  lpNumberOfBytesRecvd,
IN/OUT LPDWORD  lpFlags,
IN LPWSAOVERLAPPED  lpOverlapped,
IN LPWSAOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine,
IN LPWSATHREADID  lpThreadId,
OUT LPINT  lpErrno
);

大同小异

填充AFD_RECV_INFO,发送IOCTL_AFD_RECEIVE

AfdReceive,TdiBuildReceive,AfdRestartReceive

UDP方式
int WSPSendTo(
__in          SOCKET s,
__in          LPWSABUF lpBuffers,
__in          DWORD dwBufferCount,
__out         LPDWORD lpNumberOfBytesSent,
__in          DWORD dwFlags,
__in          const struct sockaddr* lpTo,
__in          int iTolen,
__in          LPWSAOVERLAPPED lpOverlapped,
__in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
__in          LPWSATHREADID lpThreadId,
__out         LPINT lpErrno
);

IOCTL_AFD_SEND_DATAGRAM

AfdSendDatagram,TdiBuildSendDatagram

当然UDP方式比较和谐,发送的都是数据报,不存在一次没发完还要在完成函数里Restart的问题,所以AfdRestartSendDatagram是一个打酱油的函数。

int WSPRecvFrom(
__in          SOCKET s,
__in_out      LPWSABUF lpBuffers,
__in          DWORD dwBufferCount,
__out         LPDWORD lpNumberOfBytesRecvd,
__in_out      LPDWORD lpFlags,
__out         struct sockaddr* lpFrom,
__in_out      LPINT lpFromlen,
__in          LPWSAOVERLAPPED lpOverlapped,
__in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
__in          LPWSATHREADID lpThreadId,
__in_out      LPINT lpErrno
);

IOCTL_AFD_RECEIVE_DATAGRAM

AfdReceiveDatagram
endpoint->ReceiveDatagramBufferListHead,挂入链表就成了
AfdReceiveDatagramEventHandler
蛋疼的是这个函数。。收到数据后tcpip回对这个函数进行回调。。先检查endpoint->ReceiveDatagramBufferListHead,有东西则万事大吉,完成之。
没有的话,就要缓冲它,当然这个缓冲是有最大限额的,所以这里可能丢包。
BytesIndicated == BytesAvailable 时,数据存放好之后果断放入endpoint->ReceiveDatagramBufferListHead。
不然还要TdiBuildReceiveDatagram  重发 TDI_RECEIVE 给传输层

这一层的结构是一堆一堆的,但主要的是代表着socket的endpoint 还有代表连接的 connection object ,其他结构大多包含于这两个之中。。。

看过这些,在SSDT中 NtDeviceIoControlFile 和 NtRead/WriteFile 做拦截挺方便,TDI过滤当然是最常见的。。。总之要看是什么应用。。。

下回可以说说TDI过滤的例子了。下次记录下之前已经逆过的360netmon。。迅雷传说中的底层智能限速还没看过,不知真假~

围观网络之一 —— 初步看看应用层:Winsock AFD相关推荐

  1. 网络爬虫初步:从一个入口链接开始不断抓取页面中的网址并入库

    前言: 在上一篇<网络爬虫初步:从访问网页到数据解析>中,我们讨论了如何爬取网页,对爬取的网页进行解析,以及访问被拒绝的网站.在这一篇博客中,我们可以来了解一下拿到解析的数据可以做的事件. ...

  2. 网络工程师——初步了解

    网络工程师 [http://baike.baidu.com/view/24738.htm?fr=ala0_1] 概述 网络工程师是通过学习和训练,掌握网络技术的理论知识和操作技能的网络技术人员.网络工 ...

  3. Windows网络编程初步

    1. OSI/RM和TCP/IP 国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)制定OSI/RM OSI/RM:Open SystemInterconnect/Recommended ...

  4. 工作事件五点作法和网络中所产生的Winsock连接与互动

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任. http://1572091hyl10.blog.51cto.com/1562091/6626 ...

  5. 网络基础 2-1(应用层,HTTP三点注意,HTTP协议格式, 最简单的HTTP服务器)

    应用层 应用层 负责应用程序之间的数据沟通-----协议都是用户自己定的 自定制协议: 结构化数据传输 序列化: 将数据对象以指定的协议(数据格式)进行可用于持久化存储或者数据传输时的数据组织 例如在 ...

  6. 网络***检测初步探测方法

    经过精心配置的Win2000服务器可以防御90%以上的***和***,但是,就象上一章结束时所提到的:系统安全是一个连续的过程,随着新漏洞的出现和服务器应用的变化,系统的安全状况也在不断变化着;同时由 ...

  7. K8S之Flannel的vxlan网络模式初步源码解析

    简介 之前详细解析过Flannel的vxlan模式的网络通信原理,本篇将继续深入结合源码进行探索 前情提要 阅读本文需要知道flannel vxlan网络模式的网络请求路径,可以参考以前博主写的文章: ...

  8. 复习计算机网络day1-计算机网络的初步了解

    1计算机网络的功能: 数据通信[较重要] 资源共享[较重要] 分布式处理 提高可靠性 负载均衡 计算机网络分类: 按照范围: 广域网WAN 作用范围通常为几十到几千公里 城域网MAN  作用范围通常为 ...

  9. Linux网络编程基础_6_应用层(下)--E-mail,WWW(大结局)

    应用层(下) --E-mail,WWW 一.E-mail/电子邮件系统 1.电子邮件系统的组成结构 1)MTS(MessageTansfer System),邮件传输系统. 2)UA(UserAgen ...

最新文章

  1. A winner is a dreamer who never gives up
  2. Leetcode 138. 复制带随机指针的链表 解题思路及C++实现
  3. python发红包实现
  4. AD中按Y使器件竖直方向上镜像翻转
  5. 知名视频编辑工具:达芬奇剪辑调色软件 DaVinci Resolve Studio Mac v17.3.1
  6. apply族函数应用指南
  7. 十年磨一剑——一夜成名背后是十年的努力
  8. Redis集群管理工具redis-trib
  9. RS/CQI/SINR/RSRP/RSSI都是什么意思?
  10. (转)国内外三个不同领域巨头分享的Redis实战经验及使用场景
  11. 03 Jme3和Nifty1.4.2中文显示
  12. 【Java基础总结】类加载顺序,new关键字,访问权限修饰符与方法重载等【二】
  13. mysql关系图查看
  14. 我是一个怎样的人,我可以提供什么价值
  15. MySQL ERROR 1709 (HY000)
  16. ARM与X86架构的对决[整编]
  17. 生成带大写英文字母和数字的验证码(手机或邮箱)
  18. 如何计算 R 中的变异系数
  19. 2019.9.21-冒泡排序代码
  20. 软件测试性能测试安全测试

热门文章

  1. wps里表格中间的字怎么置顶_怎么把wps文字放在最中间
  2. 批处理命令和常用脚本
  3. xp sp3关闭PAE(物理内存扩展)
  4. win11强行退回win10
  5. Python处理视频文件的实用姿势
  6. LDF转Excel;LDF转位定义;Excel转LDF;Excel转位定义;MatrixCreat(一)之LIN矩阵详解
  7. Python_删除TXT文件中不想要的内容
  8. 研究生计算机方面有哪些专业,计算机类研究生有哪些专业?
  9. 数据结构HashTab
  10. TCP/IP英文缩写汇总