Publi

Hallar información de un dispositivo de red en C

Volviendo a un artículo anterior donde hallábamos la dirección IP de un dispositivo, he decidido extender un poco la funcionalidad para poder hallar más información acerca de un dispositivo de red.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>

#define get_addr(var) (*(struct in_addr *) &var.ifr_addr.sa_data[2])

int getdevinfo(char * ifname) {
  int sock;
  struct ifreq ifr;

  sock=socket(AF_INET, SOCK_DGRAM, 0);
  if (sock<0)
    return -1;          /* No puedo crear el socket */

  ifr.ifr_addr.sa_family = AF_INET;
  strcpy(ifr.ifr_name, ifname);

  if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
    return -2;          /* No encuentro el dispositivo */

  printf("IP de %s: %s\n", ifname, inet_ntoa( get_addr(ifr)));

  if (ioctl(sock, SIOCGIFBRDADDR, &ifr)<0)
    return -3;          /* Fallo al obtener broadcast */
  if (get_addr(ifr).s_addr!=0)  /* Si la direccion es 0.0.0.0 */
    printf ("Broadcast de %s: %s\n", ifname, inet_ntoa(get_addr(ifr)));

  if (ioctl(sock, SIOCGIFNETMASK, &ifr)<0)
    return -4;          /* Fallo al obtener máscara */
  printf("Máscara de %s: %s\n", ifname, inet_ntoa(get_addr(ifr)));
  if (ioctl(sock, SIOCGIFHWADDR, &ifr)<0)
    return -5;          /* Fallo al obtener direccion hw */
  if (ifr.ifr_hwaddr.sa_family<=32) /* Los que tienen dirección hardware, puede que no sea siempre así */
    printf("Dirección HW de %s: %.2X.%.2X.%.2X.%.2X.%.2X.%.2X\n", ifname, (unsigned char)ifr.ifr_addr.sa_data[0],
       (unsigned char)ifr.ifr_addr.sa_data[1], (unsigned char)ifr.ifr_addr.sa_data[2], (unsigned char)ifr.ifr_addr.sa_data[3],
       (unsigned char)ifr.ifr_addr.sa_data[4], (unsigned char)ifr.ifr_addr.sa_data[5]);


  close(sock);
  return 0;
}

int main(int argc, char *argv[])
{
  getdevinfo("eth0");
}

Hemos hecho una macro llamada get_addr que nos va a ahorrar mucho trabajo, aunque podremos optimizar un poco más, y sobre todo, dar la posibilidad de reutilizar la información obtenida, y no sólo mostrarla en pantalla. La dirección hardware del dispositivo la dejaremos como cadena, pero las demás direcciones como struct sockaddr o struct sockaddr_in nos serán más útiles, sobre todo si nuestra aplicación hace uso de ellas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>

struct ifinfo
{
  struct sockaddr addr;
  struct sockaddr mask;
  struct sockaddr brdc;
  char hwaddr[18];
};

#define get_addr(var) (*(struct in_addr *) &var.sa_data[2])

int getdevinfo(char * ifname, struct ifinfo *info) {
  int sock;
  struct ifreq ifr;
  unsigned char *hwaddr;

  sock=socket(AF_INET, SOCK_DGRAM, 0);
  if (sock<0)
    return -1;          /* No puedo crear el socket */

  ifr.ifr_addr.sa_family = AF_INET;
  strcpy(ifr.ifr_name, ifname);

  if (ioctl(sock, SIOCGIFADDR, &ifr) < 0)
    return -2;          /* No encuentro el dispositivo */
  info->addr=ifr.ifr_addr;

  if (ioctl(sock, SIOCGIFBRDADDR, &ifr)<0)
    return -3;          /* Fallo al obtener broadcast */
  info->brdc=ifr.ifr_addr;

  if (ioctl(sock, SIOCGIFNETMASK, &ifr)<0)
    return -4;          /* Fallo al obtener máscara */
  info->mask=ifr.ifr_addr;

  if (ioctl(sock, SIOCGIFHWADDR, &ifr)<0)
    return -5;          /* Fallo al obtener direccion hw */
  if (ifr.ifr_hwaddr.sa_family<=32) /* Los que tienen dirección hardware, puede que no sea siempre así */
    {
      hwaddr = (unsigned char*)ifr.ifr_addr.sa_data;
      sprintf (info->hwaddr, "%.2X.%.2X.%.2X.%.2X.%.2X.%.2X", hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
    }
  else
    info->hwaddr[0]='\0';  

  close(sock);
  return 0;
}

void printdevinfo(const struct ifinfo *info)
{
  printf ("IP: %s\n", inet_ntoa(get_addr(info->addr)));
  printf ("Máscara: %s\n", inet_ntoa(get_addr(info->mask)));
  printf ("Broadcast: %s\n", inet_ntoa(get_addr(info->brdc)));
  printf ("HW: %s\n", info->hwaddr);
}

int main(int argc, char *argv[])
{
  struct ifinfo ifnfo;


  getdevinfo("eth0", &ifnfo);

  printdevinfo(&ifnfo);
}

Un apunte más, estoy limitando los dispositivos que tienen dirección hardware a los que en el miembro sa_family devuelven un valor menor o igual que 32, aunque puede que en algunos sistemas, o en un futuro, pasado o presente no sea así; para ver los dispositivos que tienen dirección hardware conviene mirar el archivo /usr/include/linux/if_arp.h

También podría interesarte....

There are 4 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. WWE Jackets /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    I really like the way that you have expressed yourself. There is a lot to be admired from this post. You might want to click on

  3. tommchris /
    Usando Google Chrome Google Chrome 122.0.0.0 en Windows Windows NT

    Ten en cuenta que este código debe compilarse en un sistema Unix/Linux y puede requerir privilegios de superusuario para ejecutarse correctamente, ya que utiliza llamadas al sistema para acceder kinitopet a información de red.

  4. Ladia55 /
    Usando Mozilla Firefox Mozilla Firefox 123.0 en Mac OS X Mac OS X 10

    In the world of dreadhead parkour, even searching for information about a network device can turn into an exciting adventure.

Leave a Reply