科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件一个简易网络嗅探器的实现

一个简易网络嗅探器的实现

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文介绍一个用C语言和网络数据包分析开发工具实现的简易网络Sniffer

作者:何忠龙 顾丽娜 来源:ahcit 2007年10月28日

关键字: Linux

  • 评论
  • 分享微博
  • 分享邮件
下面这段代码是用来在不同版本下得到网络适配器名:

  Win9x 和WinNT中的网卡名称是分别用ASCII和UNICODE实现的,所以首先要得到本地操作系统的版本号:

dwVersion=GetVersion();
dwWindowsMajorVersion= (DWORD)(LOBYTE(LOWORD(dwVersion)));

  这里首先用到的Packet.dll函数是PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize,通常它是与驱动程序通信并被调用的第一个函数,它将返回的用户本地系统中安装的网络适配器的名字放在缓冲区pStr中;BufferSize是缓冲区的长度:

if (!(dwVersion >= 0x80000000 && dwWindowsMajorVersion >= 4))
{
 //是Windows NT
 // 找不到设备列表
 if(PacketGetAdapterNames(AdapterName,&AdapterLength)==FALSE){
  printf("Unable to retrieve the list of the adapters!\n");
  return -1;
 }
 // 找到设备列表
 temp=AdapterName;
 temp1=AdapterName;
 while ((*temp!='\0')||(*(temp-1)!='\0'))
 {
  if (*temp=='\0')
  {
   memcpy(AdapterList[i],temp1,(temp-temp1)*2);
   temp1=temp+1;
   i++;
  }
  temp++;
 }
 // 显示适配器列表
 AdapterNum=i;
 for (i=0;i<AdapterNum;i++)
  wprintf(L"\n%d- %s\n",i+1,AdapterList[i]);
  printf("\n");
 }
 else //否则就是windows 9x,获取适配器名的方法同WinNT下
 {
  if(PacketGetAdapterNames(AdapterNamea,&AdapterLength)==FALSE){
   printf("Unable to retrieve the list of the adapters!\n");
   return -1;
 }
 tempa=AdapterNamea;
 temp1a=AdapterNamea;
 while ((*tempa!='\0')||(*(tempa-1)!='\0'))
 {
  if (*tempa=='\0')
  {
   memcpy(AdapterList[i],temp1a,tempa-temp1a);
   temp1a=tempa+1;
   i++;
  }
  tempa++;
 }
 AdapterNum=i;
 for (i=0;i<AdapterNum;i++)
  printf("\n%d- %s\n",i+1,AdapterList[i]);
  printf("\n");
}

  下面这段代码就是让用户选择监听的网络适配器号:

// 选择设备
do
{
 printf("Select the number of the adapter to open : ");
 scanf("%d",&Open);
 if (Open>AdapterNum)
  printf("\nThe number must be smaller than %d",AdapterNum);
} while (Open>AdapterNum);

  然后,将所选择的设备打开,这里可以设置为“混杂”模式打开,也可以是“直接”模式打开。代码如下:

// 打开设备
lpAdapter = PacketOpenAdapter(AdapterList[Open-1]);
// 当设备无法打开时,出示错误信息:
if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
{
 dwErrorCode=GetLastError();
 printf("Unable to open the adapter, Error Code : %lx\n",dwErrorCode);
 return -1;
}

  将网卡设置为“混杂”模式,代码如下:

  这里用到函数PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter),它在到来的包上设置了一个硬件过滤器,如操作成功,返回TRUE。AdapterObject是过滤器所在的网卡设备指针;过滤器的常量Filter定义在头文件ntddndis.h 中,包括有:

  ·NDIS-PACKET-TYPE-PROMISCUOUS:设置混杂模式,每个到来的包都会被网卡接受;

  ·NDIS-PACKET-TYPE-DIRECTED:只有直接到主机网卡的包才会被接受;

  ·NDIS-PACKET-TYPE-BROADCAST:只接受广播包;

  ·NDIS-PACKET-TYPE-MULTICAST:只接受到主机所在的组的多播包;

  ·NDIS-PACKET-TYPE-ALL-MULTICAS:接受每个多播的包。

// set the network adapter in promiscuous mode
// 如果混杂模式设置失败,提示错误:
if(PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS)==FALSE){
printf("Warning: unable to set promiscuous mode!\n");
}

  然后在driver中置512K的缓冲:

  这里用到函数PacketSetBuff(LPADAPTER AdapterObject,int dim),它被用于设置AdapterObject指向的网卡的驱动程序的缓冲区,成功则返回TRUE。Dim是新的缓冲区的大小,当它被设定时,旧缓冲区中的数据将被丢弃,其中存储的包也会失去。

  需要注意的地方:驱动器缓冲区的大小设置是否恰当,将影响截包进程的性能,设置应能保证运行快且不会丢包。这里设置的是512000Byte。

// set a 512K buffer in the driver
// 当无法设置缓冲区时,提示错误:
if(PacketSetBuff(lpAdapter,512000)==FALSE){
 printf("Unable to set the kernel buffer!\n");
 return -1;
}

  PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout)函数的功能是,设置与AdapterObject指定网卡绑定的读操作超时的值,timeout以毫秒为单位,0表示没有超时,当没有包到时,read就不返回。

// set a 1 second read timeout
// 设置1秒的读取操作超时
if(PacketSetReadTimeout(lpAdapter,1000)==FALSE){
 printf("Warning: unable to set the read tiemout!\n");
}
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章