深度剖析WinPcap-獲得與釋放網絡適配器設備列表

1.1    wpcap.dll導出的相應函數接口

wpcap.dll爲了獲得與釋放已連接的網絡適配器設備列表,提供了下列函數:
文件/wpcap/libpcap/pcap/pcap.h中
struct pcap_if;
struct pcap_addr;
int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf);
void pcap_freealldevs(pcap_if_t *alldevsp ) ;
文件wpcap/libpcap/remote-ext.h中
int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char*errbuf);

1.1.1       pcap_if結構體

函數pcap_findalldevs_ex或pcap_findalldevs分別返回一個 pcap_if_t類型的鏈表alldevs或alldevsp。每個pcap_if_t結構體都包含一個適配器的詳細信息。其中成員 name 和 description 分別表示一個適配器的名稱和一個更容易讓人理解的描述。該結構體的定義如下:
typedef struct pcap_if pcap_if_t;
struct pcap_if {
/*如果不爲NULL,則指向鏈表的下一個元素。如果爲NULL,則爲鏈表的尾部*/
struct pcap_if *next;
/*給pcap_open_live函數傳遞的一個描述設備名稱的字符串指針*/
char *name;   
/*如果不爲NULL,則指向描述設備的一個可讀字符串*/
char *description;
/*一個指向接口地址鏈表的第一個元素的指針*/
struct pcap_addr *addresses;
/*
*PCAP_IF_接口標誌。當前僅有的可能標誌爲PCAP_IF_LOOPBACK,
*如果接口是迴環的則設置該標誌
*/
bpf_u_int32 flags;
};
其中結構體pcap_addr的定義在下面描述。結構體pcap_addr表示接口地址的信息,定義如下:
typedef struct pcap_addr pcap_addr_t;
struct pcap_addr {
    struct pcap_addr *next;    /*指向下一個元素的指針*/
    struct sockaddr *addr;      /* IP地址 */
    struct sockaddr *netmask;   /* 網絡掩碼 */
    struct sockaddr *broadaddr; /* 廣播地址 */
    struct sockaddr *dstaddr;   /* P2P目的地址*/
};

1.1.2        pcap_findalldevs_ex函數

通常,編寫基於WinPcap應用程序的第一件事情,就是獲得已連接的網絡適配器設備列表。WinPcap提供了pcap_findalldevs_ex函數來實現這個功能,該函數的的原型如下:
int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth,
                        pcap_if_t **alldevs, char *errbuf);
該函數創建一個能用pcap_open函數打開的網絡適配器設備列表。該函數是老函數pcap_findalldevs的一個擴展,pcap_findalldevs()是一個過時的函數,其只允許列出在本機上的網絡設備。反之pcap_findalldevs_ex也允許列出一個遠程機器上的網絡設備,此外還能列出一個給定文件夾中可用的pcap文件。因爲pcap_findalldevs_ex()依賴於標準的pcap_findalldevs()來獲得本地機器的地址,所以它是平臺無關的。
萬一該函數必須列出遠程機器上的設備,它對那臺機器打開一個新的控制連接,重新獲得那個網絡接口並終止連接。然而,如果函數檢測到遠程計算機正處在“激活模式”下,連接不會終止並使用已存在的套結字。
“source”是一個告訴函數在哪兒查找設備的參數,並且它使用與pcap_open函數同樣的語法。與pcap_findalldevs函數不同,該設備的名稱 (由alldevs->name 指定,其它的存在已連接的鏈表中)已經被考慮用在pcap_open函數中。相反,pcap_findalldevs函數的輸出必須採用pcap_createsrcstr()格式處理後,才能把源參數傳遞給pcap_open函數使用。
參數source是一個字符型的緩衝區,根據新的WinPcap語法保存着“源的位置”。
檢查該源以尋找適配器(本機的或遠程的)(如源可以爲本機的適配器“rpcap://”或遠程的適配器“rpcap://host:port”)或pcap文件(如源可以爲“file://c:/myfolder/”)。該字符串應該預先仔細考慮,爲了闡明所需的源是否爲本地/遠程適配器或文件。這些源的含義都在新的語法規定(Source Specification Syntax )中定義。
參數auth是一個指向pcap_rmtauth結構體的指針。該指針保持着認證RPCAP連接到遠程主機所需的信息。該參數對本地主機請求沒什麼意義,此時可以設爲NULL。
參數alldevs是一個“pcap_if_t”結構體類型的指針,在該函數中被正確的分配。該函數成功返回時,該指針被設置爲指向網絡設備鏈表的第一個元素,該鏈表的每個元素都是“pcap_if_t”類型。
參數errbuf是一個指向用戶分配的緩衝區(大小爲PCAP_ERRBUF_SIZE)的指針,如果函數操作出現錯誤,該緩衝區將存儲該錯誤信息。
函數成功則返回0,如果有錯誤則返回-1。“alldevs”變量返回設備列表,當函數正確返回時,“alldevs”不能爲NULL。也就是說,當系統沒有任何接口時,該函數也返回-1。“errbuf”變量返回錯誤信息,一個錯誤可能由下列原因導致:
Ø WinPcap沒有安裝在本地/遠程主機上
Ø 用戶沒有足夠的權限來列出這些設備/文件
Ø 一個網絡故障
Ø RPCAP版本協商失敗(the RPCAP version negotiation failed)
Ø 其它錯誤(如沒足夠的內存或其它的問題)
值得注意的是,通過調用pcap_findalldevs函數可能存在網絡設備不能被pcap_open函數打開的現象。比如可能沒有足夠的權限來打開它們並進行捕獲,如果是這樣,這些設備將不出現在設備列表中。
該函數所獲取的設備列表必須採用pcap_freealldevs函數手工進行釋放。

1.1.3    pcap_findalldevs函數

函數pcap_findalldevs是一個過時的函數,其只允許列出本機上出現的網絡設備。函數原型如下:
int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf);
函數獲得已連接並能打開的所有網絡設備列表,該列表能夠被pcap_open_live函數打開。參數alldevsp指向列表的第一個元素,列表的每個元素都爲pcap_if_t類型。如果沒有已連接並能打開的網絡設備,該鏈表可能爲NULL。
函數失敗返回-1,errbuf存儲合適的錯誤信息;成功返回0。
值得注意的是,通過調用pcap_findalldevs函數可能存在網絡設備不能被pcap_open_live函數打開的現象。比如可能沒有足夠的權限來打開它們並進行捕獲,如果是這樣,這些設備將不出現在設備列表中。

1.1.4  pcap_freealldevs函數

由函數pcap_findalldevs_ex或pcap_findalldevs函數返回的網絡適配器設備鏈表,必須調用pcap_freealldevs函數釋放。該函數的原型如下:
void pcap_freealldevs(pcap_if_t *alldevsp )

st1/:*{behavior:url(#ieooui) }

1.2    獲得與釋放網絡適配器列表的實例

下列代碼能獲取適配器列表,並在屏幕上顯示出來,如果沒有找到適配器,將打印錯誤信息。並在程序結束時釋放設備列表。
#include "remote-ext.h"
#include "pcap.h"
main()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int i=0;
    char errbuf[PCAP_ERRBUF_SIZE];
//獲取本地機器設備列表
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL , &alldevs, errbuf) == -1)
//獲取設備列表失敗,程序返回
        fprintf(stderr,"Error in pcap_findalldevs_ex: %s/n", errbuf);
        exit(1);
    }
    //打印設備列表
    for(d= alldevs; d != NULL; d= d->next)
    {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)/n", d->description);
        else
            printf(" (No description available)/n");
    }
    if (i == 0)
//沒找到設備接口,確認WinPcap已安裝,程序退出
        printf("/nNo interfaces found! Make sure WinPcap is installed./n");
        return;
    }
//不再需要設備列表了,釋放它
}
首先, pcap_findalldevs_ex函數和其他libpcap函數一樣,有一個 errbuf 參數。一旦發生錯誤,這個參數將會被libpcap寫入字符串類型的錯誤信息。
第二要記住,不是所有的操作系統都支持libpcap提供的網絡程序接口,因此,如果想編寫一個可移植的應用程序,就必須考慮在什麼情況下, description 是 null。在本程序中遇到這種情況時,會打印提示語句"No description available"。
最後要記住,當完成了設備列表的使用,要調用 pcap_freealldevs() 函數將其佔用的內存資源釋放。
在某臺WinXP的電腦上,運行該程序得到的結果是:
   1. /Device/NPF_{4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter)
   2. /Device/NPF_{5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章