Skip to content
Advertisement

getnameinfo() compile time error – Extracting MAC address in Linux

I have to send to the server the IP address and MAC address of the network interface from which my client socket is connected and communicating with the server. All machines are on intra-net. I have extracted the IP of my socket and I am attempting to extract the H/W address.

My strategy :

  1. Extract IP of the socket using getsockname() system call.
  2. Use getifaddrs() system call to list all available network interfaces. Inside a for-loop I am using getnameinfo() system call to find IP for currently iterating interface name and then compare this IP with socket IP (extracted from step 1) to find interface name of the connected socket.
  3. Use ioctl(fd, SIOCGIFHWADDR, &ifr) system call to get H/W address using interface name found out in stage 2.

I am facing problem getnameinfo() system call.

If I don’t type cast the first parameter to (struct sockaddr_in*) I get the following error : ai_family not supported

getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST,
                           NULL, 0, NI_NUMERICHOST);

If I type cast the first parameter to (struct sockaddr_in*) I get the following error : error: cannot convert ‘sockaddr_in*’ to ‘const sockaddr*’ for argument ‘1’ to ‘int getnameinfo(const sockaddr*, socklen_t, char*, socklen_t, char*, socklen_t, int)’

getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST,
                           NULL, 0, NI_NUMERICHOST);

Kindly advice. I am even open to some alternative strategy to programmatically and dynamically get Socket IP and MAC address.

bool Ethernet::getIp(void)
{
    struct      sockaddr_in addr;
    char        bufferIp[INET_ADDRSTRLEN];
    socklen_t   addrLen = sizeof(addr);
    if(getsockname(this->clientSocket, (struct sockaddr*) &addr, &addrLen) == -1)
    {
        string errStr = strerror(errno);
        FileOperations fo;
        string str;
        str = "Unable to extract IP address of socket";
        str += " Error : " + errStr;
        fo.printError(str);
        return RETURN_FAILURE;
    }

    if(inet_ntop(AF_INET, &addr.sin_addr, bufferIp, INET_ADDRSTRLEN) == NULL)
    {
        string errStr = strerror(errno);
        FileOperations fo;
        string str;
        str = "Unable to convert extracted IP address from binary to char* in Ethernet::getInterfaceDetails.";
        str += " Error : " + errStr;
        fo.printError(str);
        return RETURN_FAILURE;
    }
    this->ip = string(bufferIp);
    return RETURN_SUCCESS;
}

bool Ethernet::getMac(void)
{
    int fd;
    struct ifreq ifr;
//    char *iface = "eth0";
    unsigned char *mac;
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name , this->interfaceName.c_str(), IFNAMSIZ-1);
    ioctl(fd, SIOCGIFHWADDR, &ifr);
    close(fd);
    mac = (unsigned char *)ifr.ifr_hwaddr.sa_data;

    //display mac address
    printf("Mac : %.2x:%.2x:%.2x:%.2x:%.2x:%.2xn" , mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    return RETURN_SUCCESS;

}

bool Ethernet::getInterfaceDetails(void)
{
    struct ifaddrs *ifaddr, *ifa;
    int s;
    char host[NI_MAXHOST];
    string tempAddr;
    char   buffer[INET_ADDRSTRLEN];
    if (getifaddrs(&ifaddr) == -1) 
    {
        string errStr = strerror(errno);
        FileOperations fo;
        string str;
        str = "System call 'getifaddrs' failed in Ethernet::getInterfaceDetails.";
        str += " Error : " + errStr;
        fo.printError(str);
        return RETURN_FAILURE;
    }

    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
    {
        if (ifa->ifa_addr == NULL)
            continue;

        this->interfaceName = string(ifa->ifa_name);
        if(this->interfaceName == string("lo"))
            continue;

         s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST,
                           NULL, 0, NI_NUMERICHOST);

        if(s != 0)
        {
            string errStr = gai_strerror(s);
            cout << "Error : " << errStr << endl;
            FileOperations fo;
            string str;
            str = "Unable to convert extracted IP address address from binary to char* in Ethernet::getInterfaceDetails.";
            str += " Error : " + errStr;
            fo.printError(str);
            return RETURN_FAILURE;
        }
        tempAddr = string(host);      
        if(tempAddr == this->ip)
        {
            freeifaddrs(ifaddr);
            return RETURN_SUCCESS;
        }
    }
    return RETURN_FAILURE;
}

Advertisement

Answer

@Antti Haapala, @Mats; Thanks for the help. The problem was as you mentioned that other types/families of addresses where present in the interfaces and where causing problems to getnameinfo() system call.

Now I am filtering out other addresses and only allowing AF_INET.

I have added the following validation :

if(ifa->ifa_addr->sa_family != AF_INET)
      continue;
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement