代码之家  ›  专栏  ›  技术社区  ›  Dark Sorrow

getnameinfo()编译时错误-在Linux中提取MAC地址

  •  1
  • Dark Sorrow  · 技术社区  · 7 年前

    所有机器都在内部网络上。 我已经提取了我的套接字的IP,我正在尝试提取硬件地址。

    我的策略:

    1. 使用提取套接字的IP getsockname() 系统调用。
    2. 使用 getifaddrs() 列出所有可用网络接口的系统调用。在我使用的for循环中 getnameinfo() 系统调用以查找当前迭代接口名称的IP,然后将此IP与套接字IP(从步骤1中提取)进行比较,以查找所连接套接字的接口名称。
    3. ioctl(fd, SIOCGIFHWADDR, &ifr) 系统调用以使用在第2阶段中找到的接口名称获取硬件地址。

    getnameinfo() 系统调用。

    如果我不将第一个参数强制转换为(struct sockaddr\u in*),则会出现以下错误: ai_family not supported

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

    如果我将第一个参数强制转换为(struct sockaddr\u in*),则会出现以下错误: 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)’

    NULL,0,NI_NUMERICHOST);
    

    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:%.2x\n" , 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;
    }
    
    3 回复  |  直到 7 年前
        1
  •  1
  •   Mats    7 年前

    我看到一件奇怪的事,关于你打电话给 getnameinfo ifa_addr 等于 sockaddr_in 类型,但我可以想象你可以得到其他类型,例如。 sockaddr_in6 ifa_addr->sa_family

    getnameinfo

    MAC address with getifaddrs 进行相关讨论。

        2
  •  0
  •   Antti Haapala -- Слава Україні    7 年前

    这个 getifaddrs

    这个 ifa_addr sa_family 应参考子字段以确定地址结构的格式。)此字段可能包含空指针。

    因此

    • 检查字段是否不是空指针(如果是,则它不是您要查找的IP)
    • 长度参数必须与中地址的长度匹配 萨乌家族 AF_INET .

    那个插座


    如果这是嵌入式Linux,并且接口的名称始终相同,只需从 /sys/class/net/eth0/address

        3
  •  0
  •   Dark Sorrow    7 年前

    @Antti Haapala,@Mats; 问题是,正如您所提到的,接口中存在的其他类型/系列地址以及导致getnameinfo()系统调用出现问题的其他类型/系列地址。

    现在我过滤掉了其他地址,只允许AF_INET。

    if(ifa->ifa_addr->sa_family != AF_INET)
          continue;