How to get NIC information from program C?

I want to get the following data for all network adapters connected to my computer:

1) Interface name (e.g. eth0)

2) Interface number (for example, Windows ), if such a thing exists in Linux

3) NIC capacity and bandwidth mode (e.g. 1 Gbps full duplex)

+7
source share
4 answers

You can use getifaddrs() / freeifaddrs() to get a linked list of all interfaces, then ioctl(fd, SIOCGIFINDEX, struct ifreq *) to get the interface index for each. Since the interfaces are sequential and always listed (regardless of whether they are active or not), I choose to list them using a loop using ioctl(fd, SIOCGIFNAME, struct ifreq *) . In all cases, fd is an AF_INET socket.

To get duplex and interface speed, you need to use ioctl(fd, SIOCETHTOOL, struct ifreq *) with ifr_data pointing to struct ethtool_cmd with cmd = ETHTOOL_GSET .

ioctls should return -1 if they fail, and a non-negative value (zero, I think) if success.

Here is an example program:

 #include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/ip.h> #include <net/if.h> #include <linux/ethtool.h> #include <linux/sockios.h> #include <string.h> #include <errno.h> #include <stdio.h> struct interface { int index; int flags; /* IFF_UP etc. */ long speed; /* Mbps; -1 is unknown */ int duplex; /* DUPLEX_FULL, DUPLEX_HALF, or unknown */ char name[IF_NAMESIZE + 1]; }; static int get_interface_common(const int fd, struct ifreq *const ifr, struct interface *const info) { struct ethtool_cmd cmd; int result; /* Interface flags. */ if (ioctl(fd, SIOCGIFFLAGS, ifr) == -1) info->flags = 0; else info->flags = ifr->ifr_flags; ifr->ifr_data = (void *)&cmd; cmd.cmd = ETHTOOL_GSET; /* "Get settings" */ if (ioctl(fd, SIOCETHTOOL, ifr) == -1) { /* Unknown */ info->speed = -1L; info->duplex = DUPLEX_UNKNOWN; } else { info->speed = ethtool_cmd_speed(&cmd); info->duplex = cmd.duplex; } do { result = close(fd); } while (result == -1 && errno == EINTR); if (result == -1) return errno; return 0; } int get_interface_by_index(const int index, struct interface *const info) { int socketfd, result; struct ifreq ifr; if (index < 1 || !info) return errno = EINVAL; socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (socketfd == -1) return errno; ifr.ifr_ifindex = index; if (ioctl(socketfd, SIOCGIFNAME, &ifr) == -1) { do { result = close(socketfd); } while (result == -1 && errno == EINTR); return errno = ENOENT; } info->index = index; strncpy(info->name, ifr.ifr_name, IF_NAMESIZE); info->name[IF_NAMESIZE] = '\0'; return get_interface_common(socketfd, &ifr, info); } int get_interface_by_name(const char *const name, struct interface *const info) { int socketfd, result; struct ifreq ifr; if (!name || !*name || !info) return errno = EINVAL; socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (socketfd == -1) return errno; strncpy(ifr.ifr_name, name, IF_NAMESIZE); if (ioctl(socketfd, SIOCGIFINDEX, &ifr) == -1) { do { result = close(socketfd); } while (result == -1 && errno == EINTR); return errno = ENOENT; } info->index = ifr.ifr_ifindex; strncpy(info->name, name, IF_NAMESIZE); info->name[IF_NAMESIZE] = '\0'; return get_interface_common(socketfd, &ifr, info); } int main(int argc, char *argv[]) { struct interface iface; int arg; int status = 0; if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { fprintf(stderr, "\n"); fprintf(stderr, "Usage: %s { -h | --help }\n", argv[0]); fprintf(stderr, " %s\n", argv[0]); fprintf(stderr, " %s INTERFACE ...\n", argv[0]); fprintf(stderr, "\n"); return 1; } if (argc > 1) { for (arg = 1; arg < argc; arg++) { if (get_interface_by_name(argv[arg], &iface) != 0) { fprintf(stderr, "%s: No such interface.\n", argv[arg]); status = 1; continue; } printf("%s: Interface %d", iface.name, iface.index); if (iface.flags & IFF_UP) printf(", up"); if (iface.duplex == DUPLEX_FULL) printf(", full duplex"); else if (iface.duplex == DUPLEX_HALF) printf(", half duplex"); if (iface.speed > 0) printf(", %ld Mbps", iface.speed); printf("\n"); } } else { for (arg = 1; ; arg++) { if (get_interface_by_index(arg, &iface) != 0) break; printf("%s: Interface %d", iface.name, iface.index); if (iface.flags & IFF_UP) printf(", up"); if (iface.duplex == DUPLEX_FULL) printf(", full duplex"); else if (iface.duplex == DUPLEX_HALF) printf(", half duplex"); if (iface.speed > 0) printf(", %ld Mbps", iface.speed); printf("\n"); } } return status; } 

If you save the above as iflist.c , you can compile it with

 gcc -W -Wall -O3 iflist.c -o iflist 

To see usage, run iflist -h . To list all the interfaces, run it without parameters:

 ./iflist 

The above method will use the described multiplier. To display only specific interfaces, start it by specifying the interfaces:

 ./iflist eth0 lo 

Duplex and speed are listed only for Ethernet interfaces, of course.


Edited to add:

If the above program does not provide bandwidth and mode for the interface, here is a simplified version that reports the exact cause (errors). This interface name is called command line options; it does not list interfaces.

 #include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/ip.h> #include <net/if.h> #include <linux/ethtool.h> #include <linux/sockios.h> #include <string.h> #include <errno.h> #include <stdio.h> int ethernet_interface(const char *const name, int *const index, int *const speed, int *const duplex) { struct ifreq ifr; struct ethtool_cmd cmd; int fd, result; if (!name || !*name) { fprintf(stderr, "Error: NULL interface name.\n"); fflush(stderr); return errno = EINVAL; } if (index) *index = -1; if (speed) *speed = -1; if (duplex) *duplex = -1; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { const int err = errno; fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err)); fflush(stderr); return errno = err; } strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); ifr.ifr_data = (void *)&cmd; cmd.cmd = ETHTOOL_GSET; if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) { const int err = errno; do { result = close(fd); } while (result == -1 && errno == EINTR); fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err)); return errno = err; } if (speed) *speed = ethtool_cmd_speed(&cmd); if (duplex) switch (cmd.duplex) { case DUPLEX_HALF: *duplex = 0; break; case DUPLEX_FULL: *duplex = 1; break; default: fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex); fflush(stderr); *duplex = -1; } if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0) *index = ifr.ifr_ifindex; do { result = close(fd); } while (result == -1 && errno == EINTR); if (result == -1) { const int err = errno; fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err)); return errno = err; } return 0; } int main(int argc, char *argv[]) { int arg, speed, index, duplex; if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { fprintf(stderr, "\n"); fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]); fprintf(stderr, " %s INTERFACE ...\n", argv[0]); fprintf(stderr, "\n"); return 0; } for (arg = 1; arg < argc; arg++) { if (ethernet_interface(argv[arg], &index, &speed, &duplex)) return 1; if (index == -1) printf("%s: (no interface index)", argv[arg]); else printf("%s: interface %d", argv[arg], index); if (speed == -1) printf(", unknown bandwidth"); else printf(", %d Mbps bandwidth", speed); if (duplex == 0) printf(", half duplex.\n"); else if (duplex == 1) printf(", full duplex.\n"); else printf(", unknown mode.\n"); } return 0; } 

Questions?

+13
source

(1) getifaddrs ()

(2) if_indextoname () , if_nameindex () , if_nametoindex ()

(3) I am not sure about this, but you can get it through ioctl () and one from SIOCGIF* or from /proc .

+4
source

the following link explains the getifaddrs function getifaddrs with a working example

getifaddrs ()

+2
source
 ethtool eth1 

this command will list all information about eth1, including speed, duplex, port ...

you can use popen () to get the output and display it.

POPEN (3) Linux Programmer's Guide
POPEN (3)

NAME popen, pclose - stream to or from a process

SYNTAXIS #include

  FILE *popen(const char *command, const char *type); 
+1
source

All Articles