バックナンバーはこちら。
https://www.simulationroom999.com/blog/In-vehicle-network-backnumber/
はじめに
ネットワークシミュレーションに向けてnpcap受信処理の話
登場人物
博識フクロウのフクさん
イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1
エンジニア歴8年の太郎くん
イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1
npcap受信コードの元ネタ
今回はnpcapの受信コードを追加するのだけど・・・。
前回と同じくサンプルのpktdump_exから持ってくる?
pktdump_exの話
pcap APIを見てて見つけたんだけど、
pcap_loopってAPIもあるんだなって。
pcap_loop API仕様
ほう?!
試しにこれ使ってみようかと。
pcap_loopを使用したサンプルコード
ちなみにpcap_loopを使用しているサンプルコードとかはあった?
あったよ。
udpdumpってのがサンプルプロジェクトとしてあったから
これの使い方をまねようかと。
なんでこれを使おうと思ったの?
まぁpktdump_exでもよかったんだけど、
パケットフィルタをしてるサンプルもあったんで、
もしかしたら今後フィルタとかしたくなるかもー。
って思って。
なるほど!
確かにそれはあるかも!
udpdumpのコード
int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
u_int netmask;
char packet_filter[] = "ip and udp";
struct bpf_program fcode;
/* Load Npcap and its functions. */
if (!LoadNpcapDlls())
{
fprintf(stderr, "Couldn't load Npcap\n");
exit(1);
}
/* Retrieve the device list */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &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 Npcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf_s("%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(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.
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
1000, // read timeout
NULL, // remote authentication
errbuf // error buffer
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by Npcap\n", d->name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Check the link layer. We support only Ethernet for simplicity. */
if(pcap_datalink(adhandle) != DLT_EN10MB)
{
fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
if(d->addresses != NULL)
/* Retrieve the mask of the first address of the interface */
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
/* If the interface is without addresses we suppose to be in a C class network */
netmask=0xffffff;
//compile the filter
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
//set the filter
if (pcap_setfilter(adhandle, &fcode)<0)
{
fprintf(stderr,"\nError setting the filter.\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;
}
udpdump説明
簡単にサンプルを説明すると、
udpパケット限定のパケットキャプチャをするのが目的のコードだね。
新出のAPIが何個かあるね?
pcap_loopを含めると以下4つだね。
- pcap_datalink:デバイスのリンクタイプ取得
- pcap_compile:フィルタ文字列をコンパイルしてbpf_program構造体を取得
- pcap_setfilter:bpf_program構造体を元にパケットフィルタ有効化
- pcap_loop:キャプチャ処理
意外とあるねー。
ここらへんも少し掘り下げて理解していこうと思う。
まとめ
まとめだよ。
- pcap_next_ex以外にキャプチャ用のAPIが存在。
- pcap_loop関数。
- pcap_loopを使用したサンプルはudpdump。
- udpのみをフィルタしてキャプチャするサンプルプログラム。
- 今回は使用しないが、今後フィルタすることもあるえるため、こちらの実装方法を採用。
コメント