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

パケットの送出
[WinPcap プログラミング入門編]


 “WinPcap” という名前が示すとおり、このライブラリの主な目的はパケットをキャプチャすることですが、直接ネットワーキングに関する他の有能な機能も提供していま す。それらの中に、ユーザーはパケット送出のための完全な関数のセットを見つけることができます。このレッスンがそれを示しています。

 オリジナルのlibpcapはパケットの送出に関して何の方法も提供していなかったことに注目してください。ここに示されているこれら全ての関数 はWinPcapオリジナルの拡張機能で、Unix環境下では動作しません。

pcap_sendpacketで一個のパケットを送出する

 パケットを送出する一番簡単な方法が、次の断片コードの中に示されています。アダプタのオープン後、手製のパケットを送出するために pcap_sendpacket() が呼び出されます。pcap_sendpacket() は送るデータを含んだバッファ、その長さとそれを送るアダプタを引数として取ります。バッファが、どんな操作なしでもネットにそのまま送出されることに注 目してください。これはアプリケーションが、きちんとした意味のあるものを送出するためには正しいプロトコルヘッダを作り出さなければならないことを意味 しています。

#include <stdlib.h>
#include <stdio.h>

#include <pcap.h>

void usage();

void main(int argc, char **argv) {
pcap_t *fp;
char error[PCAP_ERRBUF_SIZE];
u_char packet[100];
int i;

/* Check the validity of the command line */
if (argc != 2)
{
printf("usage: %s inerface", argv[0]);
return;
}

/* Open the output adapter */
if((fp = pcap_open_live(argv[1], 100, 1, 1000, error) ) == NULL)
{
fprintf(stderr,"\nError opening adapter: %s\n", error);
return;
}

/* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */
packet[0]=1;
packet[1]=1;
packet[2]=1;
packet[3]=1;
packet[4]=1;
packet[5]=1;

/* set mac source to 2:2:2:2:2:2 */
packet[6]=2;
packet[7]=2;
packet[8]=2;
packet[9]=2;
packet[10]=2;
packet[11]=2;

/* Fill the rest of the packet */
for(i=12;i<100;i++){
packet[i]=i%256;
}

/* Send down the packet */
pcap_sendpacket(fp,
packet,
100);

return;
}

キューを送出する

 pcap_sendpacket() がシンプルで直接的なパケット送出方法を提供する一方で、キュー送出は高度な、強力で最適化されたパケットグループの送出メカニズムを提供します。キュー 送出はネットワークへ送られる様々なパケットを入れておく箱になっています。それにはサイズがあり、そのサイズとは蓄えることの出来る最大のバイト量を示 しています。

 キュー送出は pcap_sendqueue_alloc() 関数によって作られ、新たなキューが保持するサイズを特定します。

 一旦キューが作られると、pcap_sendqueue_queue() はそれにパケットを蓄えることに使用されます。この関数はタイムスタンプ、長さとパケットデータのバッファと共にpcap_pkthdr を受け取ります。これらのパラメータはpcap_next_ex()pcap_handler() によって受け取られ るものと同じなので、したがってファイルからキャプチャされたかファイルから読み込まれたパケットをキューに入れることはそれらを pcap_sendqueue_queue()  に パスすることに関連しています。

 キューを送るために、WinPcapは pcap_sendqueue_transmit() 関数を用意しています。三番目のパラメータに注目してください。もしゼロでなければ、送出は同期されます。すなわち、関連のあるパケットのタイムスタンプ が遵守されます。このことはCPUの並外れた量を要求します。なぜなら、この同期化は「力任せ」ループを使用してカーネルドライバ内で行われますが、通常 は非常に高い精度(大抵数マイクロ秒かそれ以下)を与えるからです。

 pcap_sendqueue_transmit() でキューを送出することは、一連の pcap_sendpacket() で実行できるものよりもより効果的です。なぜなら、キューの送出はコンテキストスイッチの数を急激に減らしながら、カーネルレベルでバッファされるからで す。

 キューがもう必要でなくなった時には、関連付けられた全てのバッファを解放する pcap_sendqueue_destroy() によってそれらのキューは削除されます。

 次のコードはどのようにキュー送出を使用するかを示しています。まず pcap_open_offline() でキャプチャファイルを開き、それでパケットをファイルから適切に割り振られたキューへと移動します。この時点でキューへと伝送して、ユーザーから要求が あれば同期させます。

 ダンプrファイルのリンク層が pcap_datalink() を使用してパケットを送出するインターフェイスのうちの一つと比較されて、それらが異なる時に警告文が表示されることに注目してください。リンク層上で、 別のものからキャプチャされたパケットを送出することは、非常に無駄なことです。

/*
* Copyright (c) 1999 - 2002
* Politecnico di Torino. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the Politecnico
* di Torino, and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <stdlib.h>
#include <stdio.h>

#include <pcap.h>

void usage();

void main(int argc, char **argv) {
pcap_t *indesc,*outdesc;
char error[PCAP_ERRBUF_SIZE];
FILE *capfile;
int caplen,
sync;
u_int res;
pcap_send_queue *squeue;
struct pcap_pkthdr *pktheader;
u_char *pktdata;

/* Check the validity of the command line */
if (argc <= 2 || argc >= 5)
{
usage();
return;
}

/* Retrieve the length of the capture file */
capfile=fopen(argv[1],"rb");
if(!capfile){
printf("Capture file not found!\n");
return;
}

fseek(capfile , 0, SEEK_END);
caplen= ftell(capfile)- sizeof(struct pcap_file_header);
fclose(capfile);

/* Chek if the timestamps must be respected */
if(argc == 4 && argv[3][0] == 's')
sync = TRUE;
else
sync = FALSE;

/* Open the capture */
if((indesc = pcap_open_offline(argv[1], error)) == NULL){
fprintf(stderr,"\nError opening the input file: %s\n", error);
return;
}

/* Open the output adapter */
if((outdesc = pcap_open_live(argv[2], 100, 1, 1000, error) ) == NULL)
{
fprintf(stderr,"\nError opening adapter: %s\n", error);
return;
}

/* Check the MAC type */
if(pcap_datalink(indesc) != pcap_datalink(outdesc)){
printf("Warning: the datalink of the capture differs from the one of the selected interface.\n");
printf("Press a key to continue, or CTRL+C to stop.\n");
getchar();
}

/* Allocate a send queue */
squeue = pcap_sendqueue_alloc(caplen);

/* Fill the queue with the packets from the file */
while((res = pcap_next_ex( indesc, &pktheader, &pktdata)) == 1){
if(pcap_sendqueue_queue(squeue, pktheader, pktdata) == -1){
printf("Warning: packet buffer too small, not all the packets will be sent.\n");
break;
}
}

if(res == -1){
printf("Corrupted input file.\n");
pcap_sendqueue_destroy(squeue);
return;
}

/* Transmit the queue */

if((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len)
{
printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", error, res);
}

/* free the send queue */
pcap_sendqueue_destroy(squeue);

return;
}


void usage()
{

printf("\nSendcap, sends a libpcap/tcpdump capture file to the net. Copyright (C) 2002 Loris Degioanni.\n");
printf("\nUsage:\n");
printf("\t sendcap file_name adapter [s]\n");
printf("\nParameters:\n");
printf("\nfile_name: the name of the dump file that will be sent to the network\n");
printf("\nadapter: the device to use. Use \"WinDump -D\" for a list of valid devices\n");
printf("\ns: if present, forces the packets to be sent synchronously, i.e. respecting the timestamps in the dump file. This option will work only under Windows NTx.\n\n");

exit(0);
}

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