庖丁解牛---winpcap源码彻底解密系列的续集(6)

 

如何设置混合模式,本文是庖丁解牛---winpcap源码彻底解密系列的续集:

 

static int

pcap_activate_win32(pcap_t *p)

{

     NetType type;

 

#ifdef HAVE_REMOTE

     char host[PCAP_BUF_SIZE + 1];

     char port[PCAP_BUF_SIZE + 1];

     char name[PCAP_BUF_SIZE + 1];

     int srctype;

     int opensource_remote_result;

 

     /*

         Retrofit; we have to make older applications compatible with the remote capture

         So, we're calling the pcap_open_remote() from here, that is a very dirty thing.

         Obviously, we cannot exploit all the new features; for instance, we cannot

         send authentication, we cannot use a UDP data connection, and so on.

     */

     if (pcap_parsesrcstr(p->opt.source, &srctype, host, port, name, p->errbuf) )

         return PCAP_ERROR;

 

     if (srctype == PCAP_SRC_IFREMOTE)

     {

         opensource_remote_result = pcap_opensource_remote(p, NULL);

 

         if (opensource_remote_result != 0)

              return opensource_remote_result;

 

         p->rmt_flags= (p->opt.promisc) ? PCAP_OPENFLAG_PROMISCUOUS : 0;

 

         return 0;

     }

 

     if (srctype == PCAP_SRC_IFLOCAL)

     {

         /*

          * If it starts with rpcap://, cut down the string

          */

         if (strncmp(p->opt.source, PCAP_SRC_IF_STRING, strlen(PCAP_SRC_IF_STRING)) == 0)

         {

              size_t len = strlen(p->opt.source) - strlen(PCAP_SRC_IF_STRING) + 1;

              char *new_string;

              /*

               * allocate a new string and free the old one

               */

              if (len > 0)

              {

                   new_string = (char*)malloc(len);

                   if (new_string != NULL)

                   {

                       char *tmp;

                       strcpy(new_string, p->opt.source + strlen(PCAP_SRC_IF_STRING));

                       tmp = p->opt.source;

                       p->opt.source = new_string;

                       free(tmp);

                   }

              }

         }

     }

 

#endif   /* HAVE_REMOTE */

 

     if (p->opt.rfmon) {

         /*

          * No monitor mode on Windows.  It could be done on

          * Vista with drivers that support the native 802.11

          * mechanism and monitor mode.

          */

         return (PCAP_ERROR_RFMON_NOTSUP);

     }

 

     /* Init WinSock */

     wsockinit();

 

     p->adapter = PacketOpenAdapter(p->opt.source);     //打开适配器

    

     if (p->adapter == NULL)

     {

         /* Adapter detected but we are not able to open it. Return failure. */

         snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening adapter: %s", pcap_win32strerror());

         return PCAP_ERROR;

     }

    

     /*get network type*/

     if(PacketGetNetType (p->adapter,&type) == FALSE)

     {

         snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Cannot determine the network type: %s", pcap_win32strerror());

         goto bad;

     }

    

     /*Set the linktype*/

     switch (type.LinkType)

     {

     case NdisMediumWan:

         p->linktype = DLT_EN10MB;

         break;

        

     case NdisMedium802_3:

         p->linktype = DLT_EN10MB;

         /*

          * This is (presumably) a real Ethernet capture; give it a

          * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so

          * that an application can let you choose it, in case you're

          * capturing DOCSIS traffic that a Cisco Cable Modem

          * Termination System is putting out onto an Ethernet (it

          * doesn't put an Ethernet header onto the wire, it puts raw

          * DOCSIS frames out on the wire inside the low-level

          * Ethernet framing).

          */

         p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);

         /*

          * If that fails, just leave the list empty.

          */

         if (p->dlt_list != NULL) {

              p->dlt_list[0] = DLT_EN10MB;

              p->dlt_list[1] = DLT_DOCSIS;

              p->dlt_count = 2;

         }

         break;

        

     case NdisMediumFddi:

         p->linktype = DLT_FDDI;

         break;

        

     case NdisMedium802_5:           

         p->linktype = DLT_IEEE802; 

         break;

        

     case NdisMediumArcnetRaw:

         p->linktype = DLT_ARCNET;

         break;

        

     case NdisMediumArcnet878_2:

         p->linktype = DLT_ARCNET;

         break;

        

     case NdisMediumAtm:

         p->linktype = DLT_ATM_RFC1483;

         break;

        

     case NdisMediumCHDLC:

         p->linktype = DLT_CHDLC;

         break;

 

     case NdisMediumPPPSerial:

         p->linktype = DLT_PPP_SERIAL;

         break;

 

     case NdisMediumNull:

         p->linktype = DLT_NULL;

         break;

 

     case NdisMediumBare80211:

         p->linktype = DLT_IEEE802_11;

         break;

 

     case NdisMediumRadio80211:

         p->linktype = DLT_IEEE802_11_RADIO;

         break;

 

     case NdisMediumPpi:

         p->linktype = DLT_PPI;

         break;

 

     default:

         p->linktype = DLT_EN10MB;            /*an unknown adapter is assumed to be ethernet*/

         break;

     }

 

     /* Set promiscuous mode */

     if (p->opt.promisc)

     {

 

         if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)

         {

              snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");

              goto bad;

         }

     }

     else

     {

         if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE)

         {

              snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");

              goto bad;

         }

     }

 

     /* Set the buffer size */

     p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE;

 

     /* allocate Packet structure used during the capture */

     if((p->Packet = PacketAllocatePacket())==NULL)

     {

         snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to allocate the PACKET structure");

         goto bad;

     }

 

     if(!(p->adapter->Flags & INFO_FLAG_DAG_CARD))

     {

     /*

      * Traditional Adapter

      */

         /*

          * If the buffer size wasn't explicitly set, default to

          * WIN32_DEFAULT_USER_BUFFER_SIZE.

          */

          if (p->opt.buffer_size == 0)

              p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;

 

         if(PacketSetBuff(p->adapter,p->opt.buffer_size)==FALSE)

         {

              snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "driver error: not enough memory to allocate the kernel buffer");

              goto bad;

         }

        

         p->buffer = (u_char *)malloc(p->bufsize);

         if (p->buffer == NULL)

         {

              snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));

              goto bad;

         }

        

         PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize);

        

         /* tell the driver to copy the buffer only if it contains at least 16K */

         if(PacketSetMinToCopy(p->adapter,16000)==FALSE)

         {

              snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error calling PacketSetMinToCopy: %s", pcap_win32strerror());

              goto bad;

         }

     }

     else

#ifdef HAVE_DAG_API

     {

     /*

      * Dag Card

      */

         LONG status;

         HKEY dagkey;

         DWORD    lptype;

         DWORD    lpcbdata;

         int      postype = 0;

         char keyname[512];

        

         snprintf(keyname, sizeof(keyname), "%s\\CardParams\\%s",

              "SYSTEM\\CurrentControlSet\\Services\\DAG",

              strstr(_strlwr(p->opt.source), "dag"));

         do

         {

              status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &dagkey);

              if(status != ERROR_SUCCESS)

                   break;

             

              status = RegQueryValueEx(dagkey,

                   "PosType",

                   NULL,

                   &lptype,

                   (char*)&postype,

                   &lpcbdata);

             

              if(status != ERROR_SUCCESS)

              {

                   postype = 0;

              }

             

              RegCloseKey(dagkey);

         }

         while(FALSE);

        

        

         p->snapshot = PacketSetSnapLen(p->adapter, snaplen);

        

         /* Set the length of the FCS associated to any packet. This value

          * will be subtracted to the packet length */

         p->md.dag_fcs_bits = p->adapter->DagFcsLen;

     }

#else

     goto bad;

#endif /* HAVE_DAG_API */

    

     PacketSetReadTimeout(p->adapter, p->md.timeout);

    

#ifdef HAVE_DAG_API

     if(p->adapter->Flags & INFO_FLAG_DAG_CARD)

     {

         /* install dag specific handlers for read and setfilter */

         p->read_op = pcap_read_win32_dag;

         p->setfilter_op = pcap_setfilter_win32_dag;

     }

     else

     {

#endif /* HAVE_DAG_API */

         /* install traditional npf handlers for read and setfilter */

         p->read_op = pcap_read_win32_npf;

         p->setfilter_op = pcap_setfilter_win32_npf;

#ifdef HAVE_DAG_API

     }

#endif /* HAVE_DAG_API */

     p->setdirection_op = NULL;  /* Not implemented. */

         /* XXX - can this be implemented on some versions of Windows? */

     p->inject_op = pcap_inject_win32;

     p->set_datalink_op = NULL;  /* can't change data link type */

     p->getnonblock_op = pcap_getnonblock_win32;

     p->setnonblock_op = pcap_setnonblock_win32;

     p->stats_op = pcap_stats_win32;

     p->setbuff_op = pcap_setbuff_win32;

     p->setmode_op = pcap_setmode_win32;

     p->setmintocopy_op = pcap_setmintocopy_win32;

     p->cleanup_op = pcap_cleanup_win32;

 

     return (0);

bad:

     pcap_cleanup_win32(p);

     return (PCAP_ERROR);

}

 

所有的参数设置都在这个函数中进行,该函数是wpcap里面pcap-win32.c里面的函数,从这个函数中可以看到各种设置的实现过程,下面逐渐分析:

 

1)设置混合模式

源码段如下:


 /* Set promiscuous mode */
 if (p->opt.promisc)
 {

  if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
  {
   snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to promiscuous mode");
   goto bad;
  }
 }
 else
 {
  if (PacketSetHwFilter(p->adapter,NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE)
  {
   snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "failed to set hardware filter to non-promiscuous mode");
   goto bad;
  }
 }

 

接着跟进PacketSetHwFilter函数,该函数是Packet库里面Packet32.c中定义,源码如下:

*/
BOOLEAN PacketSetHwFilter(LPADAPTER  AdapterObject,ULONG Filter)
{
    BOOLEAN    Status;
    ULONG      IoCtlBufferLength=(sizeof(PACKET_OID_DATA)+sizeof(ULONG)-1);
    PPACKET_OID_DATA  OidData;
 
 TRACE_ENTER("PacketSetHwFilter");

#ifdef HAVE_AIRPCAP_API
 if(AdapterObject->Flags == INFO_FLAG_AIRPCAP_CARD)
 {
  // Airpcap for the moment is always in promiscuous mode, and ignores any other filters
  return TRUE;
 }
#endif // HAVE_AIRPCAP_API

#ifdef HAVE_NPFIM_API
 if(AdapterObject->Flags == INFO_FLAG_NPFIM_DEVICE)
 {
  return TRUE;
 }
#endif // HAVE_NPFIM_API

#ifdef HAVE_WANPACKET_API
 if(AdapterObject->Flags == INFO_FLAG_NDISWAN_ADAPTER)
 {
  TRACE_EXIT("PacketSetHwFilter");
  return TRUE;
 }
#endif // HAVE_WANPACKET_API
   
 if (AdapterObject->Flags == INFO_FLAG_NDIS_ADAPTER)
 {
  OidData=GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,IoCtlBufferLength);
  if (OidData == NULL) {
         TRACE_PRINT("PacketSetHwFilter: GlobalAlloc Failed");
   TRACE_EXIT("PacketSetHwFilter");
         return FALSE;
  }
  OidData->Oid=OID_GEN_CURRENT_PACKET_FILTER;
  OidData->Length=sizeof(ULONG);
     *((PULONG)OidData->Data)=Filter;
  Status=PacketRequest(AdapterObject,TRUE,OidData);
  GlobalFreePtr(OidData);
 }
 else
 {
  TRACE_PRINT1("Setting HW filter not supported on this adapter type (%u)", AdapterObject->Flags);
  Status = FALSE;
 }
 
 TRACE_EXIT("PacketSetHwFilter");
    return Status;
}

 

从中可以看到设置混合模式的信息保存在OidData结构中,OidData中保存OIDs(NDIS Object Identifiers).

OidData->Oid=OID_GEN_CURRENT_PACKET_FILTER;
  OidData->Length=sizeof(ULONG);
     *((PULONG)OidData->Data)=Filter;
  Status=PacketRequest(AdapterObject,TRUE,OidData);

 

下面跟进PacketRequest函数,源码如下(packet32.c)

BOOLEAN PacketRequest(LPADAPTER  AdapterObject,BOOLEAN Set,PPACKET_OID_DATA  OidData)
{
    DWORD  BytesReturned;
    BOOLEAN  Result;

 TRACE_ENTER("PacketRequest");
+
#ifdef HAVE_NPFIM_API
 if(AdapterObject->Flags == INFO_FLAG_NPFIM_DEVICE)
 {
  if (Set)
  {
   TRACE_PRINT("PacketRequest SET not supported on NPFIM devices");
   TRACE_EXIT("PacketRequest");
   return FALSE;
  }

  Result = (BOOLEAN)g_NpfImHandlers.NpfImIssueQueryOid(AdapterObject->NpfImHandle,
   OidData->Oid,
   OidData->Data,
   &OidData->Length);

  TRACE_EXIT("PacketRequest");
  return Result;
 }
#endif

 if(AdapterObject->Flags != INFO_FLAG_NDIS_ADAPTER)
 {
  TRACE_PRINT("PacketRequest not supported on non-NPF/NPFIM adapters.");
  TRACE_EXIT("PacketRequest");
  return FALSE;
 }

 Result=(BOOLEAN)DeviceIoControl(AdapterObject->hFile,(DWORD) Set ? (DWORD)BIOCSETOID : (DWORD)BIOCQUERYOID,
                           OidData,sizeof(PACKET_OID_DATA)-1+OidData->Length,OidData,
                           sizeof(PACKET_OID_DATA)-1+OidData->Length,&BytesReturned,NULL);
   
 // output some debug info
 TRACE_PRINT4("PacketRequest, OID=%.08x Length=%.05d Set=%.04d Res=%.04d",
  OidData->Oid,
  OidData->Length,
  Set,
  Result);

 TRACE_EXIT("PacketRequest");
 return Result;
}

 

主要起作用的是

 Result=(BOOLEAN)DeviceIoControl(AdapterObject->hFile,(DWORD) Set ? (DWORD)BIOCSETOID : (DWORD)BIOCQUERYOID,
                           OidData,sizeof(PACKET_OID_DATA)-1+OidData->Length,OidData,
                           sizeof(PACKET_OID_DATA)-1+OidData->Length,&BytesReturned,NULL);

 

DeviceIoControl是应用程序和驱动通信的接口函数:

原型如下:

BOOL DeviceIoControl(
  HANDLE hDevice, 
  DWORD dwIoControlCode, 
  LPVOID lpInBuffer, 
  DWORD nInBufferSize, 
  LPVOID lpOutBuffer, 
  DWORD nOutBufferSize, 
  LPDWORD lpBytesReturned, 
  LPOVERLAPPED lpOverlapped
);
Parameters(参数)

hDevice (CreateFile返回的设备句柄)

[in] Handle to the device that is to perform the operation. To obtain a device handle, call the CreateFile function.

dwIoControlCode (应用程序调用驱动程序的控制命令,就是IOCTL_XXX IOCTLs )

[in] IOCTL for the operation. This value identifies the specific operation to perform and the type of device on which to perform the operation. There are no specific values defined for the dwIoControlCode parameter. However, you can define custom IOCTL_XXX IOCTLs with the CTL_CODE macro. You can then advertise these IOCTLs and an application can use these IOCTLs withDeviceIoControl to perform the driver-specific functions.

lpInBuffer (应用程序传递给驱动程序的数据缓冲区地址)

[in] Long pointer to a buffer that contains the data required to perform the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not require input data.

nInBufferSize (应用程序传递给驱动程序的数据缓冲区大小,字节数)

[in] Size, in bytes, of the buffer pointed to by lpInBuffer.

lpOutBuffer (驱动程序返回给应用程序的数据缓冲区地址)

[out] Long pointer to a buffer that receives the output data for the operation. Set to NULL if the dwIoControlCode parameter specifies an operation that does not produce output data.

nOutBufferSize (驱动程序返回给应用程序的数据缓冲区大小,字节数)

[out] Size, in bytes, of the buffer pointed to by lpOutBuffer.

lpBytesReturned (驱动程序实际返回给应用程序的数据字节数地址)

[out] Long pointer to a variable that receives the size, in bytes, of the data stored in lpOutBuffer. TheDeviceIoControl function may unnecessarily use this parameter. For example, if an operation does not produce data for lpOutBuffer and lpOutBuffer is NULL, the value of lpBytesReturned is meaningless.

lpOverlapped (重叠操作结构)

[in] Ignored; set to NULL.

Return Values(返回值)

Nonzero indicates success. Zero indicates failure. To obtain extended error information, call theGetLastError function. (非0成功,0失败)


请看续集7,下回分解。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值