项目开发中有时候需要在Filter驱动中获取有效地Unicast地址,比如用来发送数据等。本来以为内核中需要OID那种强求来完成,结果发现OID_GEN_NETWORK_LAYER_ADDRESSES是不支持查询的。后来求助高人才发现:原来在Ndis6.x,IPHelper
API不仅可以在应用层使用,也可以在内核层使用,这里我们使用的函数是 :
- NETIOAPI_API GetUnicastIpAddressTable(
- __in ADDRESS_FAMILY Family,
- __out PMIB_UNICASTIPADDRESS_TABLE *Table
- );
这里Family可以设置AF_INET, AF_INET6, and AF_UNSPEC。比如AF_INET是只包含ipv4的地址,具体参考文档。
查询的结果保存在 数据结构中:
- typedef struct _MIB_UNICASTIPADDRESS_TABLE {
- ULONG NumEntries;
- MIB_UNICASTIPADDRESS_ROW Table[ANY_SIZE];
- } MIB_UNICASTIPADDRESS_TABLE, *PMIB_UNICASTIPADDRESS_TABLE;
NumEntries表示地址项的数目,具体信息保存在 :
- 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;
- SOCKADDR_INET sockaddr_inet;
- SOCKADDR_IN Ipv4;
- Family = AF_INET;
- GetUnicastIpAddressTable(Family, (PMIB_UNICASTIPADDRESS_TABLE *)&(Table));
-
- 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
#include
#include "flt_dbg.h"
#include "filter.h"
#include
其次要通过编译还要在source文件中TARGETLIBS添加如下:
$(DDK_LIB_PATH)\netio.lib
------------------------------------ ----------------------------------------------------------------------------------------
最后的效果就是: