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

  • Post author:
  • Post category:其他


项目开发中有时候需要在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



————————————

—————————————————————————————-

最后的效果就是:



最后非常感谢 Thomas 在

Filter driver:get ip address

的热心帮助。