Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6596798
  • 博文数量: 227
  • 博客积分: 10047
  • 博客等级: 上将
  • 技术积分: 6678
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-11 10:33
个人简介

网上的蜘蛛

文章分类

全部博文(227)

文章存档

2010年(19)

2009年(29)

2008年(179)

分类: C/C++

2010-04-19 10:14:15

项目开发中有时候需要在Filter驱动中获取有效地Unicast地址,比如用来发送数据等。本来以为内核中需要OID那种强求来完成,结果发现OID_GEN_NETWORK_LAYER_ADDRESSES是不支持查询的。后来求助高人才发现:原来在Ndis6.x,IPHelper

API不仅可以在应用层使用,也可以在内核层使用,这里我们使用的函数是 

 

C代码 
  1. NETIOAPI_API GetUnicastIpAddressTable(  
  2.   __in   ADDRESS_FAMILY  Family,  
  3.   __out  PMIB_UNICASTIPADDRESS_TABLE *Table  
  4. );  
 

 

这里Family可以设置AF_INET, AF_INET6, and AF_UNSPEC。比如AF_INET是只包含ipv4的地址,具体参考文档。

查询的结果保存在 数据结构中:

 

C代码 
  1. typedef struct _MIB_UNICASTIPADDRESS_TABLE {  
  2.   ULONG                    NumEntries;  
  3.   MIB_UNICASTIPADDRESS_ROW Table[ANY_SIZE];  
  4. } MIB_UNICASTIPADDRESS_TABLE, *PMIB_UNICASTIPADDRESS_TABLE;  

 

 NumEntries表示地址项的数目,具体信息保存在 

 

C代码 
  1. typedef struct _MIB_UNICASTIPADDRESS_ROW {  
  2.   SOCKADDR_INET    Address;  
  3.   NET_LUID         InterfaceLuid;  
  4.   NET_IFINDEX      InterfaceIndex;  
  5.   NL_PREFIX_ORIGIN PrefixOrigin;  
  6.   NL_SUFFIX_ORIGIN SuffixOrigin;  
  7.   ULONG            ValidLifetime;  
  8.   ULONG            PreferredLifetime;  
  9.   UINT8            OnLinkPrefixLength;  
  10.   BOOLEAN          SkipAsSource;  
  11.   NL_DAD_STATE     DadState;  
  12.   SCOPE_ID         ScopeId;  
  13.   LARGE_INTEGER    CreationTimeStamp;  
  14. } MIB_UNICASTIPADDRESS_ROW, *PMIB_UNICASTIPADDRESS_ROW;  

 

 我们要的地址保存在Address中:

 

C代码 
  1. typedef union _SOCKADDR_INET {  
  2.   SOCKADDR_IN    Ipv4;  
  3.   SOCKADDR_IN6   Ipv6;  
  4.   ADDRESS_FAMILY si_family;  
  5. } SOCKADDR_INET, *PSOCKADDR_INET;  

 

 接下来我们看看SOCKDDR_IN的结构:

 

Cpp代码 
  1. struct sockaddr_in {  
  2.         short   sin_family;  
  3.         u_short sin_port;  
  4.         struct  in_addr sin_addr;  
  5.         char    sin_zero[8];  
  6. };  

 

 最后的地址保存在结构in_addr中,它是一个包含多个联合Union的结构:

 

C代码 
  1. typedef struct in_addr {   
  2.  union {      
  3.    struct {       
  4.      u_char s_b1,s_b2,s_b3,s_b4;     
  5.     } S_un_b;      
  6.   struct {       
  7.     u_short s_w1,s_w2;      
  8.   } S_un_w;    
  9.  u_long S_addr;    
  10. } S_un;  
  11. } IN_ADDR,  *PIN_ADDR,  FAR *LPIN_ADDR;  

 这个就是你要的地址了。如果你使用的应用层程序,那么可以导入Winsock2.h,然后使用inet_ntoa()函数把 sin_addr 转换为字符信息。但是在内核,估计你只能自己逐

个数据读取了。

 

Java代码 
  1.    ADDRESS_FAMILY Family;  
  2. PMIB_UNICASTIPADDRESS_TABLE  Table = NULL;  
  3. NETIOAPI_API  NetIoApi;//没法使用NO_ERROR  
  4. SOCKADDR_INET  sockaddr_inet;  
  5. SOCKADDR_IN    Ipv4;  
  6.        Family = AF_INET;  
  7. GetUnicastIpAddressTable(Family, (PMIB_UNICASTIPADDRESS_TABLE *)&(Table));  
  8. //本来需要加上判断比如 NetIoApi = GetUnicastIpAddressTable(...)因为NO_ERROR没法识别~  
  9.         sockaddr_inet = Table->Table[iCount].Address;  
  10. Ipv4 = sockaddr_inet.Ipv4;  
  11.        DEBUGP(DL_TEST,("The %dth address is %d.%d.%d.%d",iCount,Ipv4.sin_addr.S_un.S_un_b.s_b1,Ipv4.sin_addr.S_un.S_un_b.s_b2,Ipv4.sin_addr.S_un.S_un_b.s_b3,Ipv4.sin_addr.S_un.S_un_b.s_b4));  
  12.       }  

----------------------------------------------------------------------------------------------------------------------------

要使用GetUnicastIpAddressTable这个函数,要导入头文件:Netioapi.h文件,而且注意导入的顺序,必须是ndis.h之后。例如:

#include
#include
#include "flt_dbg.h" 
#include "filter.h"
#include

其次要通过编译还要在source文件中TARGETLIBS添加如下:

$(DDK_LIB_PATH)\netio.lib

------------------------------------ ----------------------------------------------------------------------------------------

最后的效果就是:


最后非常感谢 Thomas 在  的热心帮助。
阅读(4343) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

yexin2182010-04-19 10:16:34

IPv6的还没有测试...不过应该没有什么问题