在Filter驱动内核中获取IP地址

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

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

 

NETIOAPI_API GetUnicastIpAddressTable(
  __in   ADDRESS_FAMILY  Family,
  __out  PMIB_UNICASTIPADDRESS_TABLE *Table
);
 

 

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

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

 

typedef struct _MIB_UNICASTIPADDRESS_TABLE {
  ULONG                    NumEntries;
  MIB_UNICASTIPADDRESS_ROW Table[ANY_SIZE];
} MIB_UNICASTIPADDRESS_TABLE, *PMIB_UNICASTIPADDRESS_TABLE;

 

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

 

typedef struct _MIB_UNICASTIPADDRESS_ROW {
  SOCKADDR_INET    Address;
  NET_LUID         InterfaceLuid;
  NET_IFINDEX      InterfaceIndex;
  NL_PREFIX_ORIGIN PrefixOrigin;
  NL_SUFFIX_ORIGIN SuffixOrigin;
  ULONG            ValidLifetime;
  ULONG            PreferredLifetime;
  UINT8            OnLinkPrefixLength;
  BOOLEAN          SkipAsSource;
  NL_DAD_STATE     DadState;
  SCOPE_ID         ScopeId;
  LARGE_INTEGER    CreationTimeStamp;
} MIB_UNICASTIPADDRESS_ROW, *PMIB_UNICASTIPADDRESS_ROW;

 

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

 

typedef union _SOCKADDR_INET {
  SOCKADDR_IN    Ipv4;
  SOCKADDR_IN6   Ipv6;
  ADDRESS_FAMILY si_family;
} SOCKADDR_INET, *PSOCKADDR_INET;

 

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

 

struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};

 

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

 

typedef struct in_addr { 
 union {    
   struct {     
     u_char s_b1,s_b2,s_b3,s_b4;   
    } S_un_b;    
  struct {     
    u_short s_w1,s_w2;    
  } S_un_w;  
 u_long S_addr;  
} S_un;
} IN_ADDR,  *PIN_ADDR,  FAR *LPIN_ADDR;

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

个数据读取了。

 

    ADDRESS_FAMILY Family;
	PMIB_UNICASTIPADDRESS_TABLE  Table = NULL;
	NETIOAPI_API  NetIoApi;//没法使用NO_ERROR
	SOCKADDR_INET  sockaddr_inet;
	SOCKADDR_IN    Ipv4;
        Family = AF_INET;
	GetUnicastIpAddressTable(Family, (PMIB_UNICASTIPADDRESS_TABLE *)&(Table));
	//本来需要加上判断比如 NetIoApi = GetUnicastIpAddressTable(...)因为NO_ERROR没法识别~
         sockaddr_inet = Table->Table[iCount].Address;
	Ipv4 = sockaddr_inet.Ipv4;
        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));
		  }

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

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

#include <ndis.h>
#include <filteruser.h>
#include "flt_dbg.h"
#include "filter.h"
#include <Netioapi.h>

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

$(DDK_LIB_PATH)\netio.lib

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

最后的效果就是:


在Filter驱动内核中获取IP地址_第1张图片


在Filter驱动内核中获取IP地址_第2张图片

 

最后非常感谢 Thomas 在 Filter driver:get ip address 的热心帮助。

你可能感兴趣的:(数据结构,.net)