一个关于网卡的问题!!!!!(50分)

  • 主题发起人 主题发起人 fatfish74
  • 开始时间 开始时间
F

fatfish74

Unregistered / Unconfirmed
GUEST, unregistred user!
请问如何通过DELPHI编程改变一个网卡的接收模式?
是不是一定要通过DeviceIoControl()函数?
如果一定要通过通过DeviceIoControl()函数来改变的话,那么其中
的dwIoControlCode参数应该怎么设置呢?
拜托了!!!!!
谢谢!!!
 
网卡得接收模式,是存在网卡主芯片里面得寄存器里,Windows下得程序能改得没有见过,
到是厂家得程序见过,都在DOS下,也许是Windows下不知道该芯片得I/O吧
 
同意陈礼泉。
 
在NT下用UNPACK,
在9X下没法。
 
就我目前所知道的,是可以通过编程来更改网卡的接收模式的。
所有的sniffer都是要更改网卡的接收模式来达到抓包的目的。
 
我转发一篇文章:
无需驱动程序的Sniffer-IPMon
在Windows平台上实现的Sniffer一般都需要自己写驱动程序,例如在Win9x
下面是通过写一个驱动程序用Hook_Device_Service( )来挂接ndis.vxd提供

的服务,在WinNT/2K下面则一般是需要写一个中间驱动程序(请参考白云黄

鹤站的相关文章以及http://www.pcausa.com的论述)。

Arkady Frankel(arkadyf@hotmail.com) 在CodeGuru上给出了一个无需自

己编写驱动程序的Sniffer-IPMon。该程序利用了WinSock 2的特性,只能

运行在Win2K平台上。WinSock 2允许程序使用WSAIoctl( )给一个SOCK_RAW类

型的socket设置SIO_RCVALL属性,这样该socket就可以收到所有经过本机的

数据。 下面简单分析一下其实现方法。


首先打开一个socket,参数必须是 AF_INET、SOCK_RAW和IPPROTO_IP,否则

不能设置SIO_RCVALL属性:


m_s = socket( AF_INET , SOCK_RAW , IPPROTO_IP ) ;

if( INVALID_SOCKET == m_s )

{

dwErr = WSAGetLastError() ;

sprintf( szErr , "Error socket() = %ld " , dwErr ) ;

AfxMessageBox( szErr ) ;

return ;

}


然后可以设置一下该socket的超时参数等选项:


int rcvtimeo = 5000 ;

if( setsockopt( m_s , SOL_SOCKET , SO_RCVTIMEO ,

(const char *)&rcvtimeo , sizeof(rcvtimeo) ) == SOCKET_ERROR)

{

dwErr = WSAGetLastError() ;

sprintf( szErr , "Error WSAIoctl = %ld " , dwErr ) ;

AfxMessageBox( szErr ) ;

closesocket( m_s ) ;

return ;

}


再将该socket与本机的某个网络接口绑定(注意绑定的IP地址不能是INADDR_ANY):


sa.sin_family = AF_INET;

sa.sin_port = htons(7000);

sa.sin_addr.s_addr= m_iphostsource;

if (bind(m_s,(PSOCKADDR)&sa, sizeof(sa)) == SOCKET_ERROR)

{

dwErr = WSAGetLastError() ;

sprintf( szErr , "Error bind() = %ld " , dwErr ) ;

AfxMessageBox( szErr ) ;

closesocket( m_s ) ;

return ;

}


接下来就可以设置SIO_RCVALL属性。此后就可以利用这个socket来读取经

过本机的数据包了。IPMon创建了一个新线程专门来读取该socket,以防止

处理用户输入的主线程被阻塞。


if( SOCKET_ERROR != WSAIoctl( m_s, SIO_RCVALL , &dwBufferInLen,

sizeof(dwBufferInLen),&dwBufferLen, sizeof(dwBufferLen),

&dwBytesReturned , NULL , NULL ) )

AfxBeginThread( threadFunc , (LPVOID)this );

else

{

dwErr = WSAGetLastError() ;

sprintf( szErr , "Error WSAIoctl = %ld " , dwErr ) ;

AfxMessageBox( szErr ) ;

closesocket( m_s ) ;

return ;

}


新线程中读取socket的代码也非常简单,只需要反复调用recv( )即可:


memset( buf , 0 , sizeof(buf) ) ;

iRet = recv( pDlg->m_s , buf , sizeof( buf ) , 0 ) ;

if( iRet == SOCKET_ERROR )

{

dwErr = WSAGetLastError() ;

sprintf( szErr , "Error recv() = %ld " , dwErr ) ;

continue ;

}

else

if( *buf )

{

bufwork = buf ;

pIpHeader = (IPHEADER *)bufwork ;

WORD iLen = ntohs(pIpHeader->total_len) ;

......

}


此时pIpHeader就指向buf中的RAW IP数据包,如何处理就看自己的需要了。


总之这个实现是非常方便的,不用自己编写复杂的抓包代码,所有重要

的工作都由WinSock自己封装了。WSAIoctl( )还有其它一些比较有用的

参数,如SIO_RCVALL_MCAST参数使socket可以接收所有的多播数据,

SIO_RCVALL_IGMPMCAST参数则可以接收IGMP多播数据。实际测试的时候

发现IPMon经常无法看到本机发出去的数据包(偶尔能收到),不知是什

么原因。



参考资料:

1、http://www.codeguru.com/network/ipmon.html

2、MSDN


 
Hi
我有现成的VXD及接口函数可以随意更改网卡的接收模式,WIN95,WIN98下都没有问题,
不知能否满足你的应用要求!
 
后退
顶部