usando el código C para obtener la misma información que ifconfig

7 minutos de lectura

¿Hay alguna manera en Linux, usando código C, para obtener la misma información que devolvería “ifconfig eth0”? Estoy interesado en cosas como la dirección IP, el estado del enlace y la dirección MAC.

Aquí hay una salida de muestra de 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 

  • ‘ifconfig’ no se ha mantenido en Linux durante muchos años. Utilice ‘ip’ en su lugar. serverfault.com/questions/633087/…

    – mikemaccana

    28 de agosto de 2015 a las 14:55


Una forma de llegar al fondo de problemas como este, particularmente en los casos en los que no tiene fuente, es rastro.

Le brinda una lista de todas las llamadas al sistema realizadas por cualquier programa que le pase, junto con sus argumentos y valores devueltos. Si su programa simplemente arroja información y se cierra en lugar de ejecutarse durante un tiempo prolongado, puede ser bastante sencillo simplemente hacer un hombre en todas las llamadas al sistema que ve que parecen proporcionar la información que está buscando.

cuando corro

strace ifconfig

Algunas de las convocatorias interesantes son:

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

seguido de un montón de ioctls, corroborando la respuesta de @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 para una respuesta que muestre cómo encontró la respuesta y cómo aplicar la técnica a otros problemas

    – R.. GitHub DEJA DE AYUDAR A ICE

    9 de febrero de 2011 a las 23:48

  • Inteligente, por supuesto que ignora el hecho de que para el linux ifconfig mando, fuente está fácilmente disponible.

    – mctylr

    18 de julio de 2014 a las 16:56

  • Esta tiene que ser una de las mejores herramientas que he visto para tratar de emular la funcionalidad de los comandos y filtros. Algunas veces tiene prisa y necesita saber qué secuencia de llamadas al sistema le darán lo que necesita hacer sin llamar a popen() para desembolsar el comando. Uno de los mejores consejos que he tenido la suerte de encontrar con respecto a la programación de Linux. ¡Muchas gracias!

    – CCS

    25 de noviembre de 2015 a las 21:47

Sí, ifconfig en sí está escrito en C. 🙂 Ver: http://cvsweb.netbsd.org/bsdweb.cgi/src/sbin/ifconfig/ifconfig.c?rev=1.169&content-type=text/x-cvsweb-markup

Hacer man netdevice para ver los detalles (en Linux). usas el ioctl() llamada del sistema.

Hay un enfoque más simple. copiado de 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);
   }

avatar de usuario
luis r

Una forma simple es usar la función popen ver:
http://pubs.opengroup.org/onlinepubs/009696899/functions/popen.html

Usa algo como:

FILE *fp;

char returnData[64];

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

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

pclose(fp);

Así es como obtengo MAC y MTU en mi código:

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

  • ¿Qué le paso a la unsigned char MAC[6] ??

    –Piotr Kula

    08/06/2015 a las 21:22

  • @ppumkin: MAC[6] es un parámetro de salida, lo usa en lugar del valor de retorno. Entonces ingrese allí un puntero a su propia matriz de caracteres sin firmar. Me gusta esto: unsigned char outMAC[6]; getMACAddress("eth0", outMac);

    – Youda008

    26 de diciembre de 2015 a las 19:10

  • Pero, ¿cómo obtener el nombre de la interfaz cuando todo lo que tiene es la dirección de enlace?

    – Carlos Wood

    10 de julio de 2019 a las 15:38

avatar de usuario
mahdi mohammadi

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

uso:

parse_ioctl("eth0");

  • ¿Qué le paso a la unsigned char MAC[6] ??

    –Piotr Kula

    08/06/2015 a las 21:22

  • @ppumkin: MAC[6] es un parámetro de salida, lo usa en lugar del valor de retorno. Entonces ingrese allí un puntero a su propia matriz de caracteres sin firmar. Me gusta esto: unsigned char outMAC[6]; getMACAddress("eth0", outMac);

    – Youda008

    26 de diciembre de 2015 a las 19:10

  • Pero, ¿cómo obtener el nombre de la interfaz cuando todo lo que tiene es la dirección de enlace?

    – Carlos Wood

    10 de julio de 2019 a las 15:38

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad