ネットワークデバイスの情報を取得する


ネットワークプログラムを書いている時、本を読んでいる時、ご飯を食べている時などに、
ネットワークデバイスの情報を取得したい場合があります。
時々そういう場面に遭遇することがあるので方法を簡単にまとめたいと思います。

取得にはデバイスのパラメーターを操作できるシステムコールioctlを使用します。

インターフェスのインデックス番号を取得する

#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
  printf("%s\n",argv[1]);

  struct ifreq ir;
  int soc = socket(AF_INET, SOCK_STREAM, 0);
  snprintf(ir.ifr_name, IFNAMSIZ, "%s", argv[1]);
  ioctl(soc, SIOCGIFINDEX, &ir);
  printf("%d\n", ir.ifr_ifindex);

  return 0;
}



コマンド引数でインターフェース名を渡すと情報を表示してくれます。

./ioctl {インターフェース名}

IPアドレスを取得する

#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
  printf("%s\n",argv[1]);
  struct ifreq ir;
  int soc = socket(AF_INET, SOCK_STREAM, 0);
  snprintf(ir.ifr_name, IFNAMSIZ, "%s", argv[1]);

  ioctl(soc, SIOCGIFADDR, &ir);

  printf("%s\n",  inet_ntoa(((struct sockaddr_in *)&ir.ifr_addr )->sin_addr) );

  return 0;
}

ハードウェアアドレスを取得する

#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
  printf("%s\n",argv[1]);
  struct ifreq ir;
  int soc = socket(AF_INET, SOCK_STREAM, 0);
  snprintf(ir.ifr_name, IFNAMSIZ, "%s", argv[1]);

  ioctl(soc, SIOCGIFHWADDR, &ir);
  for(int i=0; i<6; i++) {
    printf("%02x ", (uint8_t)ir.ifr_hwaddr.sa_data[i]);
  }
  printf("\n");
  return 0;
}

インターフェースに設定されたフラグを取得する

#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
  printf("%s\n",argv[1]);
  int flags[] = {
     IFF_UP
    ,IFF_BROADCAST
    ,IFF_DEBUG
    ,IFF_LOOPBACK
    ,IFF_POINTOPOINT
    ,IFF_RUNNING
    ,IFF_NOARP
    ,IFF_PROMISC
    ,IFF_NOTRAILERS
    ,IFF_ALLMULTI
    ,IFF_MASTER
    ,IFF_SLAVE
    ,IFF_MULTICAST
    ,IFF_PORTSEL
    ,IFF_AUTOMEDIA
    ,IFF_DYNAMIC
  };
  char *flag_str[] = {
     "IFF_UP"
    ,"IFF_BROADCAST"
    ,"IFF_DEBUG"
    ,"IFF_LOOPBACK"
    ,"IFF_POINTOPOINT"
    ,"IFF_RUNNING"
    ,"IFF_NOARP"
    ,"IFF_PROMISC"
    ,"IFF_NOTRAILERS"
    ,"IFF_ALLMULTI"
    ,"IFF_MASTER"
    ,"IFF_SLAVE"
    ,"IFF_MULTICAST"
    ,"IFF_PORTSEL"
    ,"IFF_AUTOMEDIA"
    ,"IFF_DYNAMIC"
  };
  struct ifreq ir;
  int soc = socket(AF_INET, SOCK_STREAM, 0);
  snprintf(ir.ifr_name, IFNAMSIZ, "%s", argv[1]);

  ioctl(soc, SIOCGIFFLAGS, &ir);

  for (int i=0; i<sizeof(flags)/sizeof(flags[0]); i++) {
    if (ir.ifr_flags & flags[i]) {
      printf("%s\n",flag_str[i]);
    }
  }

  return 0;
}


このようにioctlを使用することでデバイスの情報を取得することができます。
取得するだけでなく値を設定することもできます。

例えばネットワークインターフェースをプロミスキャス・モードとして動作させるためにフラグを設定できます。

マニュアルページを見る限り他にも設定できる値があるようです。

僕自身もプロミスキャス・モードとして動作できるように頑張りたいと思います。