インタフェイス情報取得 - ifconfigもどき

ソケットに対するioctlを用いてネットワークインタフェイスに関する情報を取得する。
参考資料:UNIXネットワークプログラミング16章

ifconfigのソースでも同様のことをやっている。

表示をなるべくifconfigに近づけた。
但し、こちらはダウンさせたインタフェイスは表示されないが、
ifconfigではダウンしているインタフェイスも表示される。

// printinfo.c
//
// print interface information
// just like ifconfig command...
// based on UNIX network programming chapter 16.

#include <stdio.h>
#include <net/if.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/sockios.h>
#include <linux/in.h>

void get_ifi_info(void);
void print_ifreq(int sock, struct ifreq* ifr);
int print_flags(int sock, struct ifreq* ifr);
void print_mtu(int sock, struct ifreq* ifr);
void print_inet(int sock, struct ifreq* ifr);
void print_arp(int sock, struct ifreq* ifr);
void print_netmask(int sock,   struct ifreq* ifr);
void print_broadcast(int sock,   struct ifreq* ifr);
void print_addr(int sock, struct ifreq* ifr, int request, char *tag);
void err_quit(const char *fmt, ...);
void yydump(char *p, int length);

#define DEBUG_PRINT printf("%s:%d\n", __FUNCTION__, __LINE__);

//-----------------------------------------
int main(int argc, char **argv)
{
  get_ifi_info();

  exit(0);
}


//-----------------------------------------
void get_ifi_info(void)
{
  int sockfd, len, ret;
  char *buf, *ptr;
  struct ifconf ifc;
  struct ifreq *ifr;

  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
  len = 100 * sizeof(struct ifreq); // assume enough size
  buf = malloc(len);
  ifc.ifc_len = len;
  ifc.ifc_buf = buf;
  ret = ioctl(sockfd, SIOCGIFCONF, &ifc);
  if(ret < 0){
    err_quit("iotcl error: ret:%d errno:%s", ret, strerror(errno));
  }

  for(ptr = buf;ptr < buf + ifc.ifc_len; ptr += sizeof(struct ifreq)){
    ifr = (struct ifreq*)ptr;
    print_ifreq(sockfd, ifr);
  }
  close(sockfd);
}


//-----------------------------------------
void print_ifreq(int sock, struct ifreq* ifr)
{
  struct ifreq ifrcopy;
  struct sockaddr *sa;
  int ret, flags;

  // print interface name
  printf("%s : ",ifr->ifr_name);

  flags = print_flags(sock, ifr);
  print_mtu(sock, ifr);
  sa = &ifr->ifr_addr;
  switch(sa->sa_family){
  case AF_INET:
    printf("\t");
    print_inet(sock, ifr);
    print_netmask(sock, ifr);
    if(flags & IFF_BROADCAST)
      print_broadcast(sock, ifr);
    printf("\n");
    printf("\t");
    print_arp(sock, ifr);
    printf("\n");
    break;
  default:
    printf("Unknown type: %d\n", sa->sa_family);
    break;
  }
  printf("\n");
}


//-----------------------------------------
int print_flags(int sock, struct ifreq* ifr)
{
  struct ifreq ifrcopy;
  int ret;
  int flags = 0;

  memcpy(&ifrcopy, ifr, sizeof(struct ifreq));
  ret = ioctl(sock, SIOCGIFFLAGS, &ifrcopy);
  if(ret < 0){
    err_quit("iotcl error: ret:%d errno:%s", ret, strerror(errno));
  }
  flags = ifrcopy.ifr_flags;

  printf("flags=%d < ", flags);
  if(flags & IFF_UP) printf("UP ");
  if(flags & IFF_BROADCAST) printf("BROADCAST ");
  if(flags & IFF_DEBUG) printf("DEBUG ");
  if(flags & IFF_LOOPBACK) printf("LOOPBACK ");
  if(flags & IFF_POINTOPOINT) printf("P2P");
  if(flags & IFF_NOTRAILERS) printf("NOTRAILERS ");
  if(flags & IFF_RUNNING) printf("RUNNING ");
  if(flags & IFF_NOARP) printf("NOARP ");
  if(flags & IFF_PROMISC) printf("PROMISC ");
  if(flags & IFF_ALLMULTI) printf("ALLMULTI ");
  if(flags & IFF_MASTER) printf("MASTER ");
  if(flags & IFF_SLAVE) printf("SLAVE ");
  if(flags & IFF_MULTICAST) printf("MULTICAST ");
  if(flags & IFF_PORTSEL) printf("PORTSEL ");
  if(flags & IFF_AUTOMEDIA) printf("AUTOMEDIA ");
  if(flags & IFF_DYNAMIC) printf("DYNAMIC ");

  printf("> ");

  return flags;
}


//-----------------------------------------
void print_mtu(int sock, struct ifreq* ifr)
{
  struct ifreq ifrcopy;
  int ret;
  int mtu = 0;

  memcpy(&ifrcopy, ifr, sizeof(struct ifreq));
  ret = ioctl(sock, SIOCGIFMTU, &ifrcopy);
  if(ret < 0){
    err_quit("iotcl error: ret:%d errno:%s", ret, strerror(errno));
  }
  mtu = ifrcopy.ifr_mtu;

  printf("mtu %d\n", mtu);
}


//-----------------------------------------
void print_arp(int sock, struct ifreq* ifr)
{
  struct ifreq ifrcopy;
  struct sockaddr *sa;
  int ret;
  int mtu = 0;
  unsigned char *p;

  memcpy(&ifrcopy, ifr, sizeof(struct ifreq));
  ret = ioctl(sock, SIOCGIFHWADDR, &ifrcopy);
  if(ret < 0){
    err_quit("iotcl error: ret:%d errno:%s", ret, strerror(errno));
  }

  sa = &ifrcopy.ifr_hwaddr;

  p = sa->sa_data;
  printf("ether %x:%x:%x:%x:%x:%x",
	 *(p+0),
	 *(p+1),
	 *(p+2),
	 *(p+3),
	 *(p+4),
	 *(p+5));
}


//-----------------------------------------
void print_inet(int sock, struct ifreq* ifr)
{
  print_addr(sock, ifr, SIOCGIFADDR, "inet");
}


//-----------------------------------------
void print_netmask(int sock, struct ifreq* ifr)
{
  print_addr(sock, ifr, SIOCGIFNETMASK, "netmask");
}


//-----------------------------------------
void print_broadcast(int sock, struct ifreq* ifr)
{
  print_addr(sock, ifr, SIOCGIFBRDADDR, "broadcast");
}


//-----------------------------------------
void print_addr(int sock, struct ifreq* ifr, int request, char *tag)
{
  struct ifreq ifrcopy;
  struct sockaddr_in *sa;
  int ret;

  memcpy(&ifrcopy, ifr, sizeof(struct ifreq));
  ret = ioctl(sock, request, &ifrcopy);
  if(ret < 0){
    err_quit("iotcl error: ret:%d errno:%s", ret, strerror(errno));
  }
  sa = (struct sockaddr_in*)&ifrcopy.ifr_addr;
  printf("%s %s ", tag, inet_ntoa(sa->sin_addr));
}

//-----------------------------------------
void err_quit(const char *fmt, ...)
{
#define MAXLINE 4096

  int errno_save, n;
  char buf[MAXLINE+1];
  va_list ap;

  va_start(ap, fmt);

  vsnprintf(buf, MAXLINE, fmt, ap);
  n = strlen(buf);
  strcat(buf, "\n");
  fflush(stdout);
  fputs(buf, stderr);
  fflush(stderr);

  va_end(ap);
  exit(1);
}


//-----------------------------------------
void yydump(char *p, int length)
{
int address = (int)p;
char data[17];
int i;
char buf[128];
char tmp[32];

 data[16] = 0; /* for string terminator */

 printf("Start Addr:[%p] Length:[%d]\n", p, length);

 for(;length>0;){
   sprintf(buf, "%08X :", address);

   for(i=0;i<16;i++){
     data[i] = *p++;	
     length--;

     /* data is out of range */
     if(length < 0){
       sprintf(tmp, "  ");
       strcat(buf, tmp);
       data[i] = ' ';
     }
     else{
       sprintf(tmp, "%02X", (unsigned char)data[i]);
       strcat(buf, tmp);
       /* eliminate undisplayable character */
       if((data[i] < 0x20) || (0x7E < data[i])){
	 data[i] = '.';
       }
     }
   }
   sprintf(tmp, " :  %s\n", data);
   strcat(buf, tmp);
   address += 16;

   printf("%s",buf);
 }
 printf("\n");
}