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 :
- Extract IP of the socket using
getsockname()
system call. - Use
getifaddrs()
system call to list all available network interfaces. Inside a for-loop I am usinggetnameinfo()
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. - 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;