Home > Mobile >  C network interface invalid result
C network interface invalid result

Time:06-28

First of all , Actually i am java developer and this code maybe unclear for C developers , sorry ....

I try to get network interface informations with native C Programming.
This is my example code :

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <netdb.h>
#include <ifaddrs.h>
#include <net/if.h>

#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <linux/if_link.h>
#include <linux/types.h>
#include <sys/socket.h>

#include <list>

using namespace std ;

class Network {
private:
    struct ifaddrs *ifaddrs ;
    char host[NI_MAXHOST];

public:
    Network() {
        if (getifaddrs(&ifaddrs) == -1) {
            perror("getifaddrs");
            exit(EXIT_FAILURE);
        }
    }

    ~Network() {
        freeifaddrs(ifaddrs);
    }

    list<string> interfaces() {
        list<string> names ;
        for (struct  ifaddrs *ifa = ifaddrs ; ifa != NULL ; ifa = ifa->ifa_next)
        {
            if (ifa->ifa_addr == NULL) continue ;
            if (ifa->ifa_addr->sa_family == AF_PACKET) {
                names.push_back(ifa->ifa_name);
            }
        }
        return names ;
    }

    int mac_addr(const char *name,char *mac_addr) {
        int s;
        struct ifreq buffer;

        s = socket(PF_INET, SOCK_DGRAM, 0);
        memset(&buffer, 0x00, sizeof(buffer));
        strcpy(buffer.ifr_name, name);
        ioctl(s, SIOCGIFHWADDR, &buffer);
        close(s);

        char *data = buffer.ifr_hwaddr.sa_data;
        sprintf(mac_addr,
                "x:x:x:x:x:x",
                (unsigned char)data[0],
                (unsigned char)data[1],
                (unsigned char)data[2],
                (unsigned char)data[3],
                (unsigned char)data[4],
                (unsigned char)data[5]);
        return 0 ;
    }

    int ipaddr(const char *name, bool ipv4,bool netmask,char *ip) {
        void * tmpAddrPtr;

        for (struct  ifaddrs *ifa = ifaddrs ; ifa != NULL ; ifa = ifa->ifa_next)
        {
            if (ifa->ifa_addr == NULL) continue ;
            int family = ifa->ifa_addr->sa_family ;

            if (strcmp(ifa->ifa_name,name) == 0 && family == AF_INET && ipv4) {
                tmpAddrPtr = netmask ?
                             &((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr :
                             &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr ;
                inet_ntop(AF_INET, tmpAddrPtr, ip, INET_ADDRSTRLEN);
                return 0 ;
            } else if (strcmp(ifa->ifa_name,name) == 0 && family == AF_INET6 && !ipv4) {
                tmpAddrPtr = netmask ?
                             &((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr :
                             &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr ;

                inet_ntop(AF_INET6, tmpAddrPtr, ip, INET6_ADDRSTRLEN);
                return 0 ;
            }
        }
        return 1 ;
    }


    int link_stats(const char *name,struct rtnl_link_stats *stats) {
        for (struct  ifaddrs *ifa = ifaddrs ; ifa != NULL ; ifa = ifa->ifa_next)
        {
            if (ifa->ifa_addr == NULL) continue ;
            int family = ifa->ifa_addr->sa_family ;

            if (strcmp(ifa->ifa_name,name) == 0 && family == AF_PACKET && ifa->ifa_data != NULL) {
                stats = (struct rtnl_link_stats *) ifa->ifa_data;
                return 0 ;
            }
        }
        return 1 ;
    }
} ;


int main() {

    Network network ;
    list<string> interface_list = network.interfaces() ;
    list<string>::iterator it ;

    const char* ethernet = "wlan0" ; 
    char *ip = new char[16] ;
    struct rtnl_link_stats *stats ;

 
    network.ipaddr(ethernet,true,false,ip) ;
    network.link_stats(ethernet,stats) ;

    cout << "Ethernet Name: " << ethernet << endl ;
    cout << "Ethernet IP: " << ip << endl ;
    
    printf("\t\ttx_packets = u; rx_packets = u\n"
                          "\t\ttx_bytes   = u; rx_bytes   = u\n",
                          stats->tx_packets, stats->rx_packets,
                          stats->tx_bytes, stats->rx_bytes);
    free(ip);
    return 0;
}

First Question :
Why this code some times result Segmentation fault ?!

> make
mkdir -p build
c   -g -o build/main main.cpp
strip --strip-all build/main
--------------------------------------------------------
> ./build/main
Segmentation fault (core dumped)
> ./build/main
Segmentation fault (core dumped)
> ./build/main
Ethernet Name: wlan0
Ethernet IP: 192.168.1.123
                tx_packets =          0; rx_packets = 4294967295
                tx_bytes   =      32615; rx_bytes   =  495411392
> ./build/main
Ethernet Name: wlan0
Ethernet IP: 192.168.1.123
                tx_packets = 3077881989; rx_packets =  818185032
                tx_bytes   =  609520456; rx_bytes   =    5081928
> ./build/main
Segmentation fault (core dumped)

Second Quesion :
Why result is unstable ?!
for example tx_bytes some times return 32615 or 609520456 or ... .

CodePudding user response:

Why the segfault?

int ipaddr(const char *name, bool ipv4,bool netmask,char *ip) {
    ...
    inet_ntop(AF_INET, tmpAddrPtr, ip, INET_ADDRSTRLEN);

...

int main() {

    char *ip;

    network.ipaddr(ethernet,true,false,ip) ;

You are using an uninitialised pointer ip right there.

I would fix it like this

Change ip to be a string

string ip;

Change ipaddr to take that parameter by reference

int ipaddr(const char *name, bool ipv4,bool netmask,string& ip) {

Resize the string to the correct size immediately prior to calling inet_ntop and then use string::data to get the pointer inet_top requires.

ip.resize(INET_ADDRSTRLEN);
inet_ntop(AF_INET, tmpAddrPtr, ip.data(), INET_ADDRSTRLEN)

Similar change for the other call to inet_top

Good rule of thumb for C programs which have to interact with C API is to always hold your data in C objects (string, vectors etc) and convert to the pointers that the C API requires only at the point where you call the C API.

  • Related