メイン   モジュール   デー タ構造   ファイルリスト   データフィールド   グローバル   関連ページ   注意事項   English

アダプタのオープニングとパケットのキャプチャ方法
[WinPcap プログラミング入門編]


 ここまで、アダプタの獲得方法を見ながら遊んできたわけですが、デバイスをオープンしてトラフィック上をトランジット(伝送)しているものをキャプチャ するという、より実質的なジョブに移っていきましょう。このレッスンでは、ネットワーク上を伝送しているあらゆるパケットについての情報の幾つかを表示す るプログラムを作成していきます。

 キャプチャデバイスをオープンする関数は、pcap_open_live()で す。 そのパラメータの中でも、snaplen、 promiscto_ms はよりよい説明の価値があるものです。

 snaplen はパケットのどの部分をキャプチャするのかを指定します。特定のOS(xBSDやWin32)では、パケット ドライバは任意のパケットの一部だけをキャプチャするように指定することが可能です。これによりコピーするデータの量を減少させることになるので、キャプ チャの効率が改善します。このケースでは、取り扱う最大データ転送サイズ(MTU)よりも高い値(65536)を使用します。それにより、アプリケーショ ンが常にパケット全体を受け取ることが保障されます。

promisc は、アダプタがpromisc(無差別)モードに設定されるかどうかを指示します。通常状態では、アダプタはネットワークからそのアダプタ宛に送られてき たトラフィックだけを抽出します。したがって他のホスト間でやり取りされたパケットは無視されます。それに代わってアダプタが無差別モードの時は、すべて のトラフィックを受け入れます。このことはWinPcapが、シェアードメディア(ノンスイッチドイーサネットなど)において他のホストのパケットも同様 にキャプチャできるようになるということを意味しています。無差別モードはほとんどのキャプチャアプリケーションでデフォルト設定なので、続く用例でその 機能を有効にします。

to_ms は、リード(読み出し)タイムアウトをミリセカンド単位で指定します。アダプタをリードすると常に常にto_msミリセカンド後にリターンし、またネット ワークからパケットを取得できなかった場合にもリターンします。さらに、to_msはアダプタがスタティスティカルモード(統計モード)にある場合には、 そのインターバルを指定します(統計モードに関する情報については「ネットワークトラフィックの統計値収集」 を参照のこと)。to_msを0に設定することはタイムアウトがないということ、アダプタ上のリードはパケットが届いていないかをまったく返さない、とい うことを意味しています。その一方でマイナス1タイムアウトは、常にすぐ値を返します。

#include "pcap.h"

/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];

/* Retrieve the device list */ if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}

/* Print the list */ for(d=alldevs; d; 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)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}

printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);

if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* Free the device list */ pcap_freealldevs(alldevs);
return -1;
}

/* Jump to the selected adapter */ for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);

/* Open the adapter */ if ( (adhandle= pcap_open_live(d->name, // name of the device 65536, // portion of the packet to capture. // 65536 grants that the whole packet will be captured on all the MACs. 1, // promiscuous mode 1000, // read timeout errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
/* Free the device list */ pcap_freealldevs(alldevs);
return -1;
}

printf("\nlistening on %s...\n", d->description);

/* At this point, we don't need any more the device list. Free it */ pcap_freealldevs(alldevs);

/* start the capture */ pcap_loop(adhandle, 0, packet_handler, NULL);

return 0;
}


/* Callback function invoked by libpcap for every incoming packet */ void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm *ltime;
char timestr[16];

/* convert the timestamp to readable format */ ltime=localtime(&header->ts.tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);

printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);

}

 一旦アダプタが開かれると、pcap_dispatch()pcap_loop() によってキャプチャが開始されます。この二つの関数はよく似ていますが、違いは、pcap_dispatch()は 指定時間が経過すると値を返す一方、pcap_loop()は cntパケットをキャプチャするまで値を返しません。pcap_loop() はこのサンプルの目的には十分な関数ですが、もっと複雑なプログラムでは通常、pcap_dispatch()が 使用されます。

 これら二つの関数はどちらともパケットを受け取る関数を指すコールバックパラメータを保持しています。この場合はpacket_handlerで す。この関数は、ネットワークから新たなパケットと、タイムスタンプとパケットの長さのような幾つかの情報を含んだヘッダと最終的には全てのプロトコル ヘッダを含んだパケットの実際のデータなどのジェネリックステータス(pcap_loop()pcap_dispatch() 関数のユーザーパラメータに対応する)を, 受け取るごとに、libpcapによって呼び出されます。通常はそこにMAC(メディアアクセスコントロール)やCRC(巡回冗長検査)が存在しないこと に注目してください。なぜなら、それらはフレーム検証の後にネットワークアダプタによって削除されているからです。また、ほとんどのアダプタは間違った CRCでパケットを廃棄してしまうことにも注目してください。したがってWinPcapは通常それらをキャプチャすることはできないのです。

 ここに提示されたよう例は、タイムスタンプと pcap_pkthdr ヘッダの全パケットの長さを抽出し、それらを画面に表示します。


documentation. Copyright (c)2002-2003 Politecnico di Torino.
2005 translated by Telebusiness,Inc.
 All rights reserved.