How can I programmatically find the IP address/netmask/gateway configured for a specific network device in Linux?

后端 未结 3 656
傲寒
傲寒 2020-12-23 13:11

I would like to write a piece of code which checks, for each network device (e.g. eth0, lo, master devices) some statistics and configuration data about that device.
I c

相关标签:
3条回答
  • 2020-12-23 13:27

    Running netstat through strace (on a random Linux box), reveals the following sequence of calls taking place:

    socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
    access("/proc/net/if_inet6", R_OK)      = 0
    socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 5
    [snip]
    open("/proc/net/dev", O_RDONLY)         = 6
    fstat64(6, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f91000
    read(6, "Inter-|   Receive               "..., 1024) = 575
    read(6, "", 1024)                       = 0
    close(6)                                = 0
    munmap(0xb7f91000, 4096)                = 0
    ioctl(4, SIOCGIFCONF, {64, {{"lo", {AF_INET, inet_addr("127.0.0.1")}}, {"eth0", {AF_INET, inet_addr("192.168.0.
    8")}}}}) = 0
    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=00:11:09:ca:d1:55}) = 0
    ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0
    ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0
    ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0x4000, irq=10, dma=0, port=0
    }}) = 0
    ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0x4000, irq=10, dma=0, port=0
    }}) = 0
    ioctl(5, SIOCGIFTXQLEN, {ifr_name="eth0", ifr_qlen=1000}) = 0
    ioctl(4, SIOCGIFADDR, {ifr_name="eth0", ifr_addr={AF_INET, inet_addr("192.168.0.8")}}) = 0
    ioctl(4, SIOCGIFDSTADDR, {ifr_name="eth0", ifr_dstaddr={AF_INET, inet_addr("192.168.0.8")}}) = 0
    ioctl(4, SIOCGIFBRDADDR, {ifr_name="eth0", ifr_broadaddr={AF_INET, inet_addr("192.168.0.255")}}) = 0
    ioctl(4, SIOCGIFNETMASK, {ifr_name="eth0", ifr_netmask={AF_INET, inet_addr("255.255.255.0")}}) = 0
    

    So, the "secret" seems to be to create a socket, then do a bunch of ioctl() calls to access the current information.

    0 讨论(0)
  • 2020-12-23 13:29

    There sure is using a struct of ifreq and ioctl() calls you can grab all interface information:

    Man page is here Ifreq manpage

    /* local interface info */
        typedef struct{
            char *iface;
            struct ether_addr hwa;
            struct in_addr ipa;
            struct in_addr bcast;
            struct in_addr nmask;
            u_short mtu;
        } ifcfg_t; 
        /*
         * Grabs local network interface information and stores in a ifcfg_t 
         * defined in network.h, returns 0 on success -1 on failure
        */
        int get_local_info(int rsock, ifcfg_t *ifcfg)
        {
            struct ifreq ifr;
    
            memset(&ifr, 0, sizeof(ifr));
            strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
            if((ioctl(rsock, SIOCGIFHWADDR, &ifr)) == -1){
                perror("ioctl():");
                return -1;
            }
            memcpy(&(ifcfg->hwa), &ifr.ifr_hwaddr.sa_data, 6);
    
            memset(&ifr, 0, sizeof(ifr));
            strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
            if((ioctl(rsock, SIOCGIFADDR, &ifr)) == -1){
                perror("ioctl():");
                return -1;
            }
            memcpy(&ifcfg->ipa, &(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr, 4);
    
            memset(&ifr, 0, sizeof(ifr));
            strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
            if((ioctl(rsock, SIOCGIFBRDADDR, &ifr)) == -1){
                perror("ioctl():");
                return -1;
            }
            memcpy(&ifcfg->bcast, &(*(struct sockaddr_in *)&ifr.ifr_broadaddr).sin_addr, 4);
    
            memset(&ifr, 0, sizeof(ifr));
            strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
            if((ioctl(rsock, SIOCGIFNETMASK, &ifr)) == -1){
                perror("ioctl():");
                return -1;
            }
            memcpy(&ifcfg->nmask.s_addr, &(*(struct sockaddr_in *)&ifr.ifr_netmask).sin_addr, 4);
    
            memset(&ifr, 0, sizeof(ifr));
            strncpy(ifr.ifr_name, ifcfg->iface, IF_NAMESIZE);
            if((ioctl(rsock, SIOCGIFMTU, &ifr)) == -1){
                perror("ioctl():");
                return -1;
            }
            ifcfg->mtu = ifr.ifr_mtu;
    
            return 0;
        }
    

    Quick edit, this function requires that the interface has been assigned before it is called, like so:

    strcpy(if_cfg->iface, iface)
    

    Ensuring you have allocated the memory first, then call like so

    if((get_local_info(sock, if_cfg)) != 0){
        printf("Unable to get network device info\n");
        return -1;
    }
    
    0 讨论(0)
  • 2020-12-23 13:35

    Take a look at /usr/include/ifaddrs.h. There is a GNU specific API for this.

    int getifaddrs (struct ifaddrs **ifap);
    
    0 讨论(0)
提交回复
热议问题