獲取已安裝設備的高級信息


      繼續WinPcap編程的學習,上一節說到《獲取本地適配器信息》,本節的實例程序功能跟上一節的程序功能類似,只是打印了適配器更詳細的信息,來看一下源碼(在windows下codeblocks下編譯運行,即使用MingW編譯器通過)

//#define WPCAP

//#include <winsock2.h>
#define WINVER 0x0501

#define HAVE_REMOTE
#include <pcap.h>
//#include <winsock2.h>
#include <ws2tcpip.h>

//#define _WIN32_WINNT 0x0501

//typedef int socklen_t;

// 函數原型
void ifprint(pcap_if_t *d);
char *iptos(u_long in);
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen);


int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
char errbuf[PCAP_ERRBUF_SIZE+1];
char source[PCAP_ERRBUF_SIZE+1];

printf("Enter the device you want to list:\n"
"rpcap:// ==> lists interfaces in the local machine\n"
"rpcap://hostname:port ==> lists interfaces in a remote machine\n"
" (rpcapd daemon must be up and running\n"
" and it must accept 'null' authentication)\n"
"file://foldername ==> lists all pcap files in the give folder\n\n"
"Enter your choice: ");

fgets(source, PCAP_ERRBUF_SIZE, stdin);
source[PCAP_ERRBUF_SIZE] = '\0';

/* 獲得接口列表 */
if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
exit(1);
}

/* 掃描列表並打印每一項 */
for(d=alldevs;d;d=d->next)
{
ifprint(d);
}

pcap_freealldevs(alldevs);

return 1;
}



/* 打印所有可用信息 */
void ifprint(pcap_if_t *d)
{
pcap_addr_t *a;
char ip6str[128];

/* 設備名(Name) */
printf("%s\n",d->name);

/* 設備描述(Description) */
if (d->description)
printf("\tDescription: %s\n",d->description);

/* Loopback Address*/
printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");

/* IP addresses */
for(a=d->addresses;a;a=a->next) {
printf("\tAddress Family: #%d\n",a->addr->sa_family);

switch(a->addr->sa_family)
{
case AF_INET:
printf("\tAddress Family Name: AF_INET\n");
if (a->addr)
printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
if (a->netmask)
printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
if (a->broadaddr)
printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
if (a->dstaddr)
printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
break;

case AF_INET6:
printf("\tAddress Family Name: AF_INET6\n");
if (a->addr)
printf("\tAddress: %s\n", ip6tos(a->addr, ip6str, sizeof(ip6str)));
break;

default:
printf("\tAddress Family Name: Unknown\n");
break;
}
}
printf("\n");
}



/* 將數字類型的IP地址轉換成字符串類型的 */
#define IPTOSBUFFERS 12
char *iptos(u_long in)
{
static char output[IPTOSBUFFERS][3*4+3+1];
static short which;
u_char *p;

p = (u_char *)&in;
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output[which];
}

char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen)
{
socklen_t sockaddrlen;

#ifdef WIN32
sockaddrlen = sizeof(struct sockaddr_in6);
#else
sockaddrlen = sizeof(struct sockaddr_storage);
#endif


if(getnameinfo(sockaddr,
sockaddrlen,
address,
addrlen,
NULL,
0,
NI_NUMERICHOST) != 0) address = NULL;

return address;
}

      在編譯本程序的時候碰到了很多問題,這里想總結一下解決的辦法。之前在網上查找過很多博客,但是發現程序都是在VC下進行編譯的,而我的codeblocks用的是MingW編譯器進行編譯的,之間會有很多區別,VC編譯器如何解決我這里就不做介紹了,因為編寫C程序還是比較習慣在codeblocks下,個人偏好。配置其實跟VC下的配置差不多,仍然是在Link Libraries下加入Packet.lib和wpcap.lib,這兩個庫文件是WinPcap提供的;另外,還要添加libws2_32.a這個庫,這個庫可以在MingW安裝目錄下的lib文件夾里面找到,VC下面是要添加ws2_32.lib這個庫,大家千萬不要搞混了,因為有看到很多博客上寫的是配置codeblocks添加ws2_32.lib,當然如果是用VC的編譯器就沒問題,但如果用MingW編譯器一般不會報錯,但是會出現很多Warning,大家注意一下便是。截圖給大家看一下,以下是本機codeblocks Link Libraries添加的情況:

      另外,在Search directories的Compiler目錄下加入WinPcap的include目錄,也可以把MingW安裝目錄下的include目錄添加進去,添不添加關系不大,但是WinPcap的include目錄一定是要包含進去的。同樣,截圖給大家看一下本機配置情況:

      再看一看源程序,跟上一個程序很類似。只是本程序提供了更高級的信息。我們知道由pcap_findalldevs_ex()返回的每一個pcap_if結構體,都包含一個pcap_addr結構體,這個結構體如下元素組成:

      一個地址列表、一個掩碼列表、一個廣播地址列表、一個目的地址列表

      另外,函數pcap_findalldevs_ex()還能返回遠程適配器信息和一個位於所給的本地文件夾的pcap文件列表,跟函數第一個參數有關。

      我們看到源碼中聲明了3個函數,ifprint、iptos和ip6tos。ifprint函數其實就是一個打印函數,打印設備名、設備描述、回環地址、IP地址信息;iptos函數和ip6tos函數功能類似,就是把IP地址轉換成為char*類型,只是協議族不同,一個是ipv4,另一個是ipv6,而且iptos函數參數中IP地址是unsigned long類型,ip6tos函數參數中IP地址是sockaddr結構體指針類型。

      程序功能很簡單,但是有一點想說一下。我們看到源碼中多了一行:

#define WINVER 0x0501

     這行是搞什么東東呢?源碼中也沒用到這個WINVER是吧。我剛開始因為沒有添加這一行折騰了很久,一直報getnameinfo這個函數未定義,但是查看getnameinfo函數的聲明處又偏偏看到了:

      找了很久沒有找到答案,於是自己仔細分析了一下,因為這是一個條件編譯,如果說沒有找到聲明,肯定是if判斷不成功。於是乎我看了一下_WIN32_WINNT是在哪里聲明的:

      原來_WIN32_WINNT的前身是WINVER!!根據它的注釋的意思,是要自己define WINVER或者包含windef.h這個頭文件,但是查看windef.h這個頭文件看到WINVER的值為0x0400,包含了這個頭文件條件編譯仍然是不能通過的,要大於或等於0x0501。那得了,我們之間#define WINVER 0x0501不就好了,事實上也是的,添加進去后編譯就可以通過了,Congratulations!下面是程序運行后的截圖:

      輸入rpcap://后回車,返回結果如下圖所示:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM