【问题标题】:using C code to get same info as ifconfig使用 C 代码获取与 ifconfig 相同的信息
【发布时间】:2011-06-24 11:43:39
【问题描述】:

在 Linux 中有没有一种方法可以使用 C 代码来获得与“ifconfig eth0”返回的信息相同的信息?我对 IP 地址、链接状态和 MAC 地址等内容感兴趣。

这是 ifconfig 的示例输出:

eth0      Link encap:Ethernet  HWaddr 00:0F:20:CF:8B:42
          inet addr:217.149.127.10  Bcast:217.149.127.63  Mask:255.255.255.192
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2472694671 errors:1 dropped:0 overruns:0 frame:0
          TX packets:44641779 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1761467179 (1679.8 Mb)  TX bytes:2870928587 (2737.9 Mb)
          Interrupt:28 

【问题讨论】:

标签: c linux networking


【解决方案1】:

解决此类问题的一种方法是strace

它会为您提供您传递给它的任何程序进行的所有系统调用的列表,以及它们的参数和返回值。如果您的程序只是转储一些信息并退出而不是长时间运行,那么只需对您看到的所有系统调用执行人工操作就可以非常简单,看起来它们可能会提供您正在寻找的信息。

当我跑步时

strace ifconfig

一些有趣的调用是:

open("/proc/net/dev", O_RDONLY)         = 6

随后是一堆 ioctl,证实了@payne 的回答:

ioctl(5, SIOCGIFFLAGS, {ifr_name="eth0",    ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="eth0", ifr_hwaddr=84:2b:2b:b7:9e:6d}) = 0
ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0

【讨论】:

  • +1 表示您如何找到答案,以及如何将该技术应用于其他问题
  • 聪明,当然它确实忽略了这样一个事实,即对于 Linux ifconfig 命令,source 是现成的。
  • 这必须是我见过的用于模拟命令和过滤器功能的最佳工具之一。有时你很匆忙,需要知道什么样的系统调用序列可以让你得到你需要做的事情,而无需调用 popen() 来执行命令。我很幸运地找到了关于 Linux 编程的最佳技巧之一。非常感谢!
【解决方案2】:

是的,ifconfig 本身是用 C 编写的。:) 请参阅:http://cvsweb.netbsd.org/bsdweb.cgi/src/sbin/ifconfig/ifconfig.c?rev=1.169&content-type=text/x-cvsweb-markup

man netdevice 以查看详细信息(在 Linux 上)。您使用ioctl() 系统调用。

【讨论】:

    【解决方案3】:

    有更简单的方法。复制自http://man7.org/linux/man-pages/man3/getifaddrs.3.html

       #include <arpa/inet.h>
       #include <sys/socket.h>
       #include <netdb.h>
       #include <ifaddrs.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <unistd.h>
       #include <linux/if_link.h>
    
       int main(int argc, char *argv[])
       {
           struct ifaddrs *ifaddr, *ifa;
           int family, s, n;
           char host[NI_MAXHOST];
    
           if (getifaddrs(&ifaddr) == -1) {
               perror("getifaddrs");
               exit(EXIT_FAILURE);
           }
    
           /* Walk through linked list, maintaining head pointer so we
              can free list later */
    
           for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
               if (ifa->ifa_addr == NULL)
                   continue;
    
               family = ifa->ifa_addr->sa_family;
    
               /* Display interface name and family (including symbolic
                  form of the latter for the common families) */
    
               printf("%-8s %s (%d)\n",
                      ifa->ifa_name,
                      (family == AF_PACKET) ? "AF_PACKET" :
                      (family == AF_INET) ? "AF_INET" :
                      (family == AF_INET6) ? "AF_INET6" : "???",
                      family);
    
               /* For an AF_INET* interface address, display the address */
    
               if (family == AF_INET || family == AF_INET6) {
                   s = getnameinfo(ifa->ifa_addr,
                           (family == AF_INET) ? sizeof(struct sockaddr_in) :
                                                 sizeof(struct sockaddr_in6),
                           host, NI_MAXHOST,
                           NULL, 0, NI_NUMERICHOST);
                   if (s != 0) {
                       printf("getnameinfo() failed: %s\n", gai_strerror(s));
                       exit(EXIT_FAILURE);
                   }
    
                   printf("\t\taddress: <%s>\n", host);
    
               } else if (family == AF_PACKET && ifa->ifa_data != NULL) {
                   struct rtnl_link_stats *stats = (struct rtnl_link_stats *)ifa->ifa_data;
    
                   printf("\t\ttx_packets = %10u; rx_packets = %10u\n"
                          "\t\ttx_bytes   = %10u; rx_bytes   = %10u\n",
                          stats->tx_packets, stats->rx_packets,
                          stats->tx_bytes, stats->rx_bytes);
               }
           }
    
           freeifaddrs(ifaddr);
           exit(EXIT_SUCCESS);
       }
    

    【讨论】:

      【解决方案4】:

      一种简单的方法是使用 popen 函数,请参阅: http://pubs.opengroup.org/onlinepubs/009696899/functions/popen.html

      使用类似的东西:

      FILE *fp;
      
      char returnData[64];
      
      fp = popen("/sbin/ifconfig eth0", "r");
      
      while (fgets(returnData, 64, fp) != NULL)
      {
          printf("%s", returnData);
      }
      
      pclose(fp);
      

      【讨论】:

      • 人们不会喜欢它,但它是一个很好的便携式答案,并且使用 ioctls 滚动你自己不适合胆小的人!
      • 有趣的答案。如果您还将它传送到awk 以解析值,我会赞成。由于您已经使用 popen 分叉并调用了 shell,我建议使用 awk 作为解析数据的经典 Unix 选择,而不是 C 中的 strtokstrstr 等。
      【解决方案5】:

      这是我在代码中获取 MAC 和 MTU 的方法:

      void getMACAddress(std::string _iface,unsigned char MAC[6]) {
              int fd = socket(AF_INET, SOCK_DGRAM, 0);
              struct ifreq ifr;
              ifr.ifr_addr.sa_family = AF_INET;
              strncpy(ifr.ifr_name , _iface.c_str() , IFNAMSIZ-1);
              ioctl(fd, SIOCGIFHWADDR, &ifr);
              for(unsigned int i=0;i<6;i++)
                  MAC[i] = ifr.ifr_hwaddr.sa_data[i];
              ioctl(fd, SIOCGIFMTU, &ifr);
              close(fd);
              printf("MTU: %d\n",ifr.ifr_mtu);
              printf("MAC:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",MAC[0],MAC[1],MAC[2],MAC[3],MAC[4],MAC[5]);
          }
      

      【讨论】:

      • 我应该向unsigned char MAC[6] 传递什么??
      • @ppumkin: MAC[6] 是一个输出参数,他使用它而不是返回值。因此,在此处输入一个指向您自己的无符号字符数组的指针。像这样:unsigned char outMAC[6]; getMACAddress("eth0", outMac);
      • 但是在只有绑定地址的情况下如何获取接口名称呢?
      【解决方案6】:
      void parse_ioctl(const char *ifname)
      {
          printf("%s\n", "scarf rosari...");
          int sock;
          struct ifreq ifr;
          struct sockaddr_in *ipaddr;
          char address[INET_ADDRSTRLEN];
          size_t ifnamelen;
      
          /* copy ifname to ifr object */
          ifnamelen = strlen(ifname);
          if (ifnamelen >= sizeof(ifr.ifr_name)) {
              printf("error :%s\n", ifr.ifr_name);
              return ;
          }
          memcpy(ifr.ifr_name, ifname, ifnamelen);
          ifr.ifr_name[ifnamelen] = '\0';
      
          /* open socket */
          sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
          if (sock < 0) {
              printf("error :%s\n", "unable to open socket..");
              return;
          }
      
          /* process mac */
          if (ioctl(sock, SIOCGIFHWADDR, &ifr) != -1) {
              printf("Mac address: %02x:%02x:%02x:%02x:%02x:%02x\n",
                      (unsigned char)ifr.ifr_hwaddr.sa_data[0],
                      (unsigned char)ifr.ifr_hwaddr.sa_data[1],
                      (unsigned char)ifr.ifr_hwaddr.sa_data[2],
                      (unsigned char)ifr.ifr_hwaddr.sa_data[3],
                      (unsigned char)ifr.ifr_hwaddr.sa_data[4],
                      (unsigned char)ifr.ifr_hwaddr.sa_data[5]);
          }
      
          /* process mtu */
          if (ioctl(sock, SIOCGIFMTU, &ifr) != -1) {
              printf("MTU: %d\n", ifr.ifr_mtu);
          }
      
          /* die if cannot get address */
          if (ioctl(sock, SIOCGIFADDR, &ifr) == -1) {
              close(sock);
              return;
          }
      
          /* process ip */
          ipaddr = (struct sockaddr_in *)&ifr.ifr_addr;
          if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
              printf("Ip address: %s\n", address);
          }
      
          /* try to get broadcast */
          if (ioctl(sock, SIOCGIFBRDADDR, &ifr) != -1) {
              ipaddr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
              if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
                  printf("Broadcast: %s\n", address);
              }
          }
      
          /* try to get mask */
          if (ioctl(sock, SIOCGIFNETMASK, &ifr) != -1) {
              ipaddr = (struct sockaddr_in *)&ifr.ifr_netmask;
              if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
                  printf("Netmask: %s\n", address);
              }
          }
      
          close(sock);
      }
      

      用法:

      parse_ioctl("eth0");
      

      【讨论】:

        猜你喜欢
        • 2019-12-09
        • 2012-09-01
        • 2021-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-29
        • 2012-09-21
        相关资源
        最近更新 更多