memo.log

技術情報の雑なメモ

setsocopt探訪のメモ(3)

さて、前回記事では、Cでの setsocopt 関数の optval にはRubyの同メソッドからオプションのデータを渡した際には文字列データを渡していることまでを確認した。では、Cの仕様としては指定の構造体を渡すところで、なぜ文字列でも問題ないのか、本当に問題ないのか、といったあたりを探っていこうと思う。

まずは、文字列データを渡しても本当に良いのかということを確認するため、Cで構造体を渡すときと、文字列データを渡すときとで動作の違いを確認しようと思う。setsocopt はシステムコールなので、Cの関数で実行されたら最終的にはシステムコールとして実行されるはずだ。

そこで、両者を実行し、 strace コマンドで実行されるシステムコールの内容を比べてみることとした。

まずは普通に packet_mreq 構造体で実行するパターンで用意し、 strace sudo ./soc のように strace 付きでプログラムを実行する。

  sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  struct packet_mreq mreq;
  mreq.mr_ifindex = 2; // eth0
  mreq.mr_type = PACKET_MR_PROMISC; // 1
  mreq.mr_alen = 0;
  mreq.mr_address[0] ='\0';
  setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, mreq, sizeof(mreq));

すると、以下のシステムコールが確認できた。

setsockopt(3, SOL_PACKET, PACKET_ADD_MEMBERSHIP, {mr_ifindex=if_nametoindex("eth0"), mr_type=PACKET_MR_PROMISC, mr_alen=0, mr_address=}, 16) = 0

次に代わりに以下のような文字列データを用意する。内容、サイズとも packet_mreq 構造体で指定したものの、上の要素から順番に並べたものだ。前回記事でRubyのソース中で printf で確認した内容と同じものと言っても良い。

char mreq2[16] = {3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, mreq2, sizeof(mreq2));

strace 付きで実行すると、以下の内容が確認できた。 packet_mreq 構造体で指定した内容と全く同じであった!

setsockopt(3, SOL_PACKET, PACKET_ADD_MEMBERSHIP, {mr_ifindex=if_nametoindex("eth0"), mr_type=PACKET_MR_PROMISC, mr_alen=0, mr_address=}, 16) = 0

これにより、 setsockopt では optval に構造体で指定したときでも、文字列データで指定したときでも同じ結果が得られると確認できた。 しかし、それは任意のオプションのときにも言えることなのだろうか?( PACKET_ADD_MEMBERSHIP の時だけでは無いだろうか?) なぜ、文字列データでも問題ないのだろうか?

長くなってきたので、続きは次回に。