【Ethernet】車載ネットワーク その61【lwIP+npcap⑦】

【Ethernet】車載ネットワーク その61【lwIP+npcap⑦】 車載ネットワーク

バックナンバーはこちら。
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 — Npcap API
Npcap API manual page 'pcap_loop,' from libpcap.
フクさん
フクさん

ほう?!

太郎くん
太郎くん

試しにこれ使ってみようかと。

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のみをフィルタしてキャプチャするサンプルプログラム。
    • 今回は使用しないが、今後フィルタすることもあるえるため、こちらの実装方法を採用。

コメント

タイトルとURLをコピーしました