Home » Linux » using C code to get same info as ifconfig

using C code to get same info as ifconfig

Posted by: admin November 30, 2017 Leave a comment

Questions:

Is there a way in Linux, using C code, to get the same information that “ifconfig eth0” would return? I’m interested in things like IP address, link status, and MAC address.

Here’s sample output from 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 
Answers:

Yes, ifconfig itself is written in C. 🙂 See: http://cvsweb.netbsd.org/bsdweb.cgi/src/sbin/ifconfig/ifconfig.c?rev=1.169&content-type=text/x-cvsweb-markup

Do man netdevice to see the details (on Linux). You use the ioctl() system call.

Questions:
Answers:

One way to get to the bottom of problems like this, particularly in cases when you don’t have source, is strace.

It gives you a list of all the system calls made by any program you pass it, along with their arguments and return values. If your program just dumps some info and quits rather than running for an extended time it can be pretty straightforward to just do a man on all the system calls you see that look like they might provide the info you’re looking for.

When I run

strace ifconfig

Some of the interesting calls are:

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

followed by a bunch of ioctls, corroborating @payne’s answer:

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

Questions:
Answers:

Here is how I get MAC and MTU in my code:

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]);
    }

Questions:
Answers:

One simple way is to use the popen function see:
http://pubs.opengroup.org/onlinepubs/009696899/functions/popen.html

Use something like:

FILE *fp;

char returnData[64];

fp = popen("/sbin/ifconfig eth0", "r");

while (fgets(returnData, 64, fp) != NULL)
{
    printf("%s", returnData);
}

pclose(fp);

Questions:
Answers:

There is simpler approach. copied from 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);
   }