今回はCで保持している全ての
ARPエントリーを取得して表示させてみました。
CでARPテーブルを表示させようと思った当初、
arpコマンドで出てくる情報を
そのままCで実装したいと思いまいした。
そこで最初に私が思ったのは、
ioctlでSIOCGIFARP指定して、
arpreq構造体にARPテーブルの情報を格納すれば、
ARPテーブルを表示出来るのではないかと思いました。
しかし、この考えがドツボにはまりました。
海外のサイト含め、色々と調べてみましが、
SIOCGARPを使って全ての
エントリーを取得するのは無理でした。
SIOCGIFARPを使うときは、
相手のIPアドレスを指定する必要があります。
カーネルはそのIPアドレスに一致する
エントリーをみて、arpreq構造体に
MACアドレスやフラグを格納します。
つまりIPアドレスを事前に
知っている必要があります。
なので今回は違うアプロ―チで、
事前にIPアドレスの指定をしないで
全てのARPエントリーを表示していきます。
そこでARPテーブルは、
/proc/net/arpを参照すれば入手できます。
procディレクトリの詳細な説明は
他のサイトに任せるとして、
ざっくりというならprocディレクトリには、
カーネルに保存されたハードウェアや
ネットワークに関する様々な情報が
格納されています。
例えば /proc/cpuinfo と叩く、
ハードウェア情報が見れます。
ということでまず、実際に中身を見てみます。
例えば vim /proc/net/arp と叩いてみて下さい。
そうすると以下ようなカーネルに
保存されいるARPテーブルが見れます。

ということで、ファイルオープンで
/proc/net/arpを指定してあとは、
そのファイルから情報を読み取っていけば、
全てのARPエントリーが手に入ります。
ちなみに一行目はいらないので、
fgets関数で読み飛ばします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include<stdio.h> #define ARP_CACHE "/proc/net/arp" /*arpテーブルが格納されたファイル*/ #define ARP_STRING_LEN 100 #define ARP_BUFFER_LEN (ARP_STRING_LEN+1) #define ARP_LINE_FORMAT "%100s 0x%100s 0x%100s %100s %100s %100s" /*fscanfするときのフォーマットを定義*/ int main(void) { char buf[ARP_BUFFER_LEN]; FILE *arp_cache = fopen(ARP_CACHE, "r"); /*ARPテーブル情報がない*/ if(arp_cache==NULL){ perror("ARP Cache : Failed to open\n!"); return -1; } /*一行目にはARPエントリーがないので読み飛ばす*/ if(fgets(buf, sizeof(buf) ,arp_cache)==NULL) { return -1; } /*読み取ったデータの格納先*/ char ip[ARP_BUFFER_LEN]; char hw_type[ARP_BUFFER_LEN]; char flags[ARP_BUFFER_LEN]; char mac[ARP_BUFFER_LEN]; char mask[ARP_BUFFER_LEN]; char device[ARP_BUFFER_LEN]; /*標準出力するときの通し番号*/ int count = 0; /*定義したフォーマットに従って情報を最後まで読み込む*/ while(fscanf(arp_cache, ARP_LINE_FORMAT, ip, hw_type, flags, mac, mask, device)==6) { printf("%03d : IP:[%s], HW_type:[%s], Flags:[%s], MAC:[%s], MASK:[%s], Device:[%s]\n", ++count, ip, hw_type, flags, mac, mask, device); } fclose(arp_cache); return 0; } |
参考までに、xxdコマンドを使えば、
ファイルを16進数や2進数で
出力することが出来ます。

先ほどの /proc/net/arp を16進数でダンプした画像です。
青丸が最初の改行コードなので、
fgets関数ではここまで来ます。
最後まで読んでいただきありがとうございました。
IPv6アドレスを同じようにファイルから取得する方法:
https://wireless-network.net/ipv6-get-c/