無差別ネットワークデバイスからの読み取り
-
02-07-2019 - |
質問
無線トラフィックのリアルタイム分析ツールを作成したいと考えています。
C でプロミスキャス (またはスニッフィング) デバイスから読み取る方法を知っている人はいますか?
これを行うには root アクセス権が必要であることはわかっています。これを行うためにどのような関数が必要か知っている人はいるだろうかと思いました。ここでは通常のソケットは意味がないようです。
解決
Linux では、PF_PACKET ソケットを使用して、プロミスキャス モードで実行されているイーサネット インターフェイスなどの RAW デバイスからデータを読み取ります。
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
これにより、受信したすべてのパケットのコピーがソケットに送信されます。ただし、実際にはすべてのパケットが必要なわけではない可能性が高くなります。カーネルは、BPF を使用して最初のレベルのフィルタリングを実行できます。 バークレーパケットフィルター. 。BPF は本質的にはスタックベースの仮想マシンです。次のような小さな命令セットを処理します。
ldh = load halfword (from packet)
jeq = jump if equal
ret = return with exit code
BPF の終了コードは、パケットをソケットにコピーするかどうかをカーネルに伝えます。setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, ) を使用して、比較的小さな BPF プログラムを直接記述することができます。(警告:カーネルは struct bpf_program ではなく struct sock_fprog を受け取ります。これらを混同しないでください。混同しないと、プログラムが一部のプラットフォームで動作しません)。
かなり複雑なものについては、実際には libpcap を使用する必要があります。BPF はできること、特にパケットごとに実行できる命令の数に制限があります。 libpcap カーネルが最初のレベルのフィルタリングを実行し、より機能的なユーザー空間コードが実際に見たくないパケットをドロップすることで、複雑なフィルターを 2 つの部分に分割します。
libpcap は、アプリケーション コードからカーネル インターフェイスを抽象化します。Linux と BSD は同様の API を使用しますが、Solaris では DLPI が必要で、Windows では別の API が使用されます。
他のヒント
以前、生のイーサネット フレームでリッスンする必要があり、最終的にこのためのラッパーを作成することになりました。デバイス名を使用して関数を呼び出すことで、例: eth0
代わりに、無差別モードのソケットを受け取りました。行う必要があるのは、生のソケットを作成し、それを無差別モードにすることです。これが私がやった方法です。
int raw_init (const char *device)
{
struct ifreq ifr;
int raw_socket;
memset (&ifr, 0, sizeof (struct ifreq));
/* Open A Raw Socket */
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?\n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, device);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device.\n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode\n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index.\n");
exit (1);
}
return raw_socket;
}
ソケットを用意したら、select を使用して、パケットが到着したときにパケットを処理できます。
pcap ライブラリを使用することもできます (「 http://www.tcpdump.org/pcap.htm) tcpdump と Wireshark でも使用されます。
なぜ次のようなものを使用しないのですか ワイヤーシャーク?
これはオープンソースなので、単に使用したくない場合は、少なくともそこからいくつかのことを学ぶことができます。
Linux 上の WireShark には、PLCP (物理層コンバージェンス プロトコル) ヘッダー情報をキャプチャする機能があります。