tcp filter例子

tcp filter例子,第1张

tcp filter例子

我先描述一下2000/nt下的tcp/ip协议的一些情况。2000/nt下,ip,tcp,udp是在 
一个驱动程序里实现的,叫做tcp.sys,这个驱动程序创建了3个设备,就是ip,tcp,udp 
。 
 首先描述一下driverentry。首先当然是iocreatedevice,用file_device_unknown, 
因为tcp设备就是用的这个参数。代码如下: 
    RtlInitUnicodeString( &usDeviceName, FILTER_NAME ); 
    status = IoCreateDevice( DriverObject, 
                            sizeof(DEVICE_EXTENSION), 
                            &usDeviceName, 
                            FILE_DEVICE_UNKNOWN, 
                            0, 
                            FALSE, 
                            &pDevObj ); 
然后就调用iogetdeviceobjectpointer来得到tcp设备的指针。 
代码如下: 
    RtlInitUnicodeString( &usTargetName, TARGET_NAME ); 
    status = IoGetDeviceObjectPointer( &usTargetName, 
                                      FILE_ALL_ACCESS, 
                                      &pTargetFileObj, 
                                      &pTargetDevObj ); 
注意TARGET_NAME是大小写区分的,我是用#define TARGET_NAME L"\\Device\\Tcp", 
不能写成#define TARGET_NAME L"\\Device\\tcp"。 
然后我们就开始调用IoAttachDeviceToDevieStatck插入到tcp设备。 
调用完成后,我们要让我们的设备表现的和tcp一样,于是把它的所有 
特性都从tcpobj复制(pdevobj->xxx=ptcpobj->xxx)。 
再扫描他tcpdriverobject的majorfuncTIon,我们的driver必须都 
支持。最后设置driverunload,因为为了方便调试,我们必须写一个 unload

前面已经讲过driverentry了,经过driverentry,所有的原来应该发送到 
tcp设备的irp现在都发送到我们的设备的处理函数了,如果什么事情都不做, 
那么可以简单的调用iocalldriver把这个irp发到tcp设备去让它处理。 
当然,我们是要做些事情的,于是代码如下: 
    UCHAR MajorFuncTIon,MinorFuncTIon; 
    PDEVICE_EXTENSION  pDevExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExt 
ension; 
    PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( Irp ); 
    MajorFunction = pIrpStack->MajorFunction; 
    MinorFunction = pIrpStack->MinorFunction; 
    //DBGPRINT( ...) 
    ParseIrp(Irp); 
    IoCopyCurrentIrpStackLocationToNext( Irp ); 
    IoSetCompletionRoutine( Irp, 
                            CompletionRoutine, 
                            NULL,   // context 
                            TRUE,   // InvokeOnSuccess 
                            TRUE,   // InvokeOnError 
                            TRUE ); // InvokeOnCancel 
    return IoCallDriver( pDevExt->TargetDevObj, Irp); 
代码很简单,除了parseirp之外,其他都是例行公事。对于tcp设备的前期处理 
就在这个函数里。后期处理的函数可以放在completionroution里。 
好了,我们已经得到了发向tcp设备的所有irp了,这个时候我们的任务就是要了解 
tcp设备到底是如何工作的. 

这种情况下数据不经过tcp设备,filter也就无从得到了。 
为了了解如何从发向tcp设备的irp中得到信息,首先我先描述一下tdi client是如何 
与tcp通讯以及tdi client一般是如何工作的。 
driverstdio里面有好几个例子都是关于tdi client的,但是这些例子都是基于它自己 
的类库的,不过这些例子功能都很强大,其中一个usb+web的温度计的创意简直让我目瞪 
口呆。 
因为我也做过pci温度计的driver,但是我从来就没有想到还可以加上一个web server在 
里面。 
因为driverstdio里的例子太复杂,我在这里简单描述一下,给一个小例子。 
因为发送过程较为简单,先描述发送。 
首先调用pIrp = TdiBuildInternalDeviceControlIrp ( 
                     TDI_SEND_DATAGRAM,                              // sub  
function 
                     pDeviceObject,                                  // poin 
ter to device object 
                     pTransportObject,                               // poin 
ter to udp object 
                     NULL,                                           // poin 
ter to event 
                     NULL );                                         // poin 
ter to return buffer 
分配一块irp,然后调用 
  TdiBuildSendDatagram ( 
                           pIrp,                                     // poin 
ter to irp 
                           pDeviceObject,                            // poin 
ter to device object 
                           pTransportObject,                         // poin 
ter to file object 
                           NULL,                                     // comp 
letion routine 
                           NULL,                                     // comp 
letion context 
                           pMdl,                                     // poin 
ter to data 
                           dBufferSize,                              // size 
 of data 
                           pConnectInfo );                           // conn 
ection information 
不用我说也应该知道,数据是放在一个buf里面,调用这个函数之前,要先构件一个mdl 
,把这个buf 
放进去。 
然后...irp已经好了,只要IoCallDriver(pUDPObject,PIrp)就行了... 
上面用的是UDP的例子(Datagram),但是tcp也是一样,虽然函数有点差别,但是也是大 
同小异(TdiBuildSend)。 
为了搞清楚上面的两个函数到底做了些什么(到底构建的irp是什么样子),没有必要去 
跟踪,实际上,tdibuildxxx 
都不过是一个宏,你可以在tdikrnl.h里找到。打开tdikrnl.h看看,发现每个宏里都有 
这么一句: 
        _IRPSP->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 
于是我们知道tdi client就是通过majorfunction=IRP_MJ_INTERNAL_DEVICE_CONTROL,m 
inorfunction=send/recv/... 
和tcp通讯的。这就使得我们确信,这种方法是可行的。(不是直接调用tdi函数,而是 
发irp) 

接收的过程较为复杂(tdi client的选择较多,因此要考虑各种情况) 
开始的时候,我在ddk document里看到这么一个宏:tdibuildreceive,我想ok, 
和send一样,我当时想的很简单,以为tdi client要接受数据了,它就向tcp发一个 
irp,然后返回pending,当有数据来的时候,tcp处理完这个irp,然后tdi client只要在 
这个irp的 
irp_complete里处理得到的数据就行了。这的确是tdi client的一个选择,但是 
当我试验的时候,我发现至少wsock不是这样做的,因为我打开了一个ie,浏览了一个网 
页, 
但是我发现我发出的数据都很好的捕获到了,但是接收的数据一个也没有,而且事实上 
, 
tcp似乎就没有受到minorfunction=tdi_receive的irp。我因为这件事苦恼了一段时间, 
 
后来我仔细的读了读ddk document,发现tdi client还有第2种选择,首先向tcp发送一 
个 
irp,minorfunction=tdi_sethandler,设置一些回调函数,然后当事情发生的时候,tc 

就会调用这些回调函数,这些函数名字是clientEventxxx。这个过程可以仔细看ddk do 
cument, 
看TdiBuildSetEventHandler,就知道哪些过程可以用这个方法。receive也是其中的一 
个,于是 
我们的方法得到了。首先我们得到了irp,如果是set_eventhandler,那么就修改tdi c 
lient 
向tcp设置的回调函数的入口,把它指向我们自己写的一个函数,同时保留原来的入口, 
 
然后在我们自己写的函数里里调用它。 
代码如下: 
       PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( Irp ); 
 MajorFunction = pIrpStack->MajorFunction; 
 MinorFunction = pIrpStack->MinorFunction; 
 FileObject = pIrpStack->FileObject ; 
       .... 
 switch(MajorFunction) 
 { 
  ... 
  case IRP_MJ_INTERNAL_DEVICE_CONTROL  : 
  { 
   switch(MinorFunction) 
   { 
    ... 
    case TDI_SET_EVENT_HANDLER: 
    pRequestSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT)(&(pIrpStack->      Pa 
rameters.DeviceIoControl)) ; 
    EventType=pRequestSetEvent->EventType; 
    EventHandler=pRequestSetEvent->EventHandler; 
          EventContext=pRequestSetEvent->EventContext; 
    ... 
    switch(EventType) 
    { 
     ... 
     case TDI_EVENT_RECEIVE : 
      pRequestSetEvent->EventHandler = OurClientEventReceive; 
      g_EventReceive = EventHandler; 
      break; 
     ... 
值得注意的是,就算是set_eventhandler,也不一定就是tdi_event_receive里接受数据 
, 
这个tdi_client的选择很多,还有ClientEventChainedReceive 什么的,详情可看ddk, 
 
winsock似乎都是没有用过这个。不过这个不影响,我们可以把ddk里面所有可能的情况 
 
全部列出来,一一判断,然后分别处理。对于clienteventreceive,这里还有几句话要 
说 
清楚,并不是每次调用这个函数就得到了数据,这还要根据ReceiveFlags参数,tdi cl 
ient 
要根据这个参数决定是否要发tdi_receive irp得到数据。于是我们的处理函数就要判断 
这个 
参数,以便做出相应的处理,我自己的代码在实际的环境中运行了一段时间,似乎没有 
问题,但是 
我也不敢说,对于各种情况我都考虑到了。 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/dianzi/2463320.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-04
下一篇 2022-08-04

发表评论

登录后才能评论

评论列表(0条)

保存