简体   繁体   中英

how to get Ethernet adapter name from IP in c in centos

have two ethernet adapters, so i have two different ip addresses. Now I ant to find the name of the adapter with the respective ip. Like, I have intel card with ip 192.168.10.1. How to retrieve this adapter name in centos(linux) using C or C++ without any third party installation?

I need to find the manufacturer name( not eth0,etc..). This manufacturer list is in "/usr/share/hwdata/pci.ids", but i'm unable to map that name with the ip address. I could get the list of adapter name using 'lscpu | grep "Ethernet"'. But again the question arises to mapping the names with ip address.

There is getifaddrs function in standard libc. I modified an example from manual page.

You can't get names from the kernel, but it provides PCI IDs in /sys file systems. You can use libpci to resolve these numbers into filenames. Current code doesn't support USB devices and subdevice numbers.

#define _GNU_SOURCE     /* To get defns of NI_MAXSERV and NI_MAXHOST */
#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>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>

#include <pci/pci.h>

/* PCI IDs are contained in /sys filesystem. */
unsigned long read_sysfs_uint(const char* ifa_name, const char* info) {
    char path[PATH_MAX];
    char buf[12];
    int fd;

    snprintf(path, PATH_MAX, "/sys/class/net/%s/device/%s", ifa_name, info);

    fd = open(path, O_RDONLY);
    if(fd == -1)
        return 0;

    if(read(fd, buf, 12) == -1) {
        close(fd);
        return 0;
    }

    close(fd);
    return strtoul(buf, NULL, 16);
}

/* Try to get PCI IDs and get PCI device name for it.
   XXX: doesn't check for subsystem's numbers */
void print_pci_ids(const char* ifa_name) {
    int vendor = (int) read_sysfs_uint(ifa_name, "vendor");
    int device = (int) read_sysfs_uint(ifa_name, "device");
    int subsystem_vendor = (int) read_sysfs_uint(ifa_name, "subsystem_vendor");
    int subsystem_device = (int) read_sysfs_uint(ifa_name, "subsystem_device");

    struct pci_access *pacc = pci_alloc();
    char namebuf[256];

    printf("PCI IDs: %x %x %x %x\n", vendor, device, subsystem_device, subsystem_vendor);

    pci_init(pacc);

    if(pci_lookup_name(pacc, namebuf, 256, 
                    PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
                    vendor, device)) {
        printf("PCI Name: %s\n", namebuf);
    }

    pci_cleanup(pacc);
}

int main(int argc, char *argv[])
{
    struct ifaddrs *ifaddr, *ifa;
    struct in_addr* ifa_inaddr;
    struct in_addr addr;
    int family, s, n;

    if(argc != 2) {
        fprintf(stderr, "Usage: getifaddr <IP>\n");
        return EXIT_FAILURE;
    }

    if (inet_aton(argv[1], &addr) == 0) {
        perror("inet_aton");
        return EXIT_FAILURE;
    }

    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs");
        return 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;

        /* We seek only for IPv4 addresses */
        if(ifa->ifa_addr->sa_family != AF_INET)
            continue;

        ifa_inaddr = &(((struct sockaddr_in*) ifa->ifa_addr)->sin_addr);
        if(memcmp(ifa_inaddr, &addr, sizeof(struct in_addr)) == 0) {
            printf("Interface: %s\n", ifa->ifa_name);
            print_pci_ids(ifa->ifa_name);
        }
    }

    freeifaddrs(ifaddr);
    return EXIT_SUCCESS;
}

Compile it with libpci (you'll need to install corresponding devel package):

$ gcc getifname.c -lpci -o ./getifname

Here are examples of its usage:

$ ./getifname 
Usage: getifaddr <IP>
$ ./getifname  dlks
inet_aton: Success
$ ./getifname 127.0.0.1
Interface: lo
PCI IDs: 0 0 0 0
PCI Name: Device 0000:0000
$ ./getifname 192.168.13.144
Interface: wlan0
PCI IDs: 8086 88e 4060 8086
PCI Name: Intel Corporation Centrino Advanced-N 6235

Im assuming by adapter name you mean eth0/eth1/etc. and not Manufacturer/Model. If so, one possible solution (a little convoluted but it works) would be to perform an ifconfig sys call and pipe it to a text file. From there you can perform a search of the text file to look for the IP address and then from there since the output is constant you can just use the starting location of the IP as the basis of getting to the adapter name.

That is actually somewhat tricky since linux does not have a common, generic driver stack API like windows - basically it boils down to 3 options :

  1. read the special files which are exported by the kernel : https://stackoverflow.com/a/5611176/351861
  2. call lspci and parse its output : http://prefetch.net/articles/linuxpci.html
  3. copy the functionality of lspci and actually write your own app, as you can see you will need several kernel data structures like pcimap_entry and whatnot, but it should be straighforward since you can literally syphon the knowledge of ye olde kernel grandmasters : https://github.com/gittup/pciutils/blob/gittup/ls-kernel.c

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM