IOCTL 调用适用于某些架构

IOCTL call works on some architecture

我正在用 C 编写程序,它需要查找接口的 IP 和 MAC 地址。我正在使用 IOCTL 调用。直到最近我还在使用自定义数据结构来存储这些地址,一切都运行良好。 然后我开始使用像

这样的标准结构

struct in_addr

struct ether_addr

在我的 OS (Archlinux) 上,它仍然可以正常工作,这很好。但通常我 运行 我的程序进入虚拟化环境 (Slitaz linux) 在 VirtualBox.I 中这样做,所以我可以 运行 使用 GNS3 的虚拟化网络。由于这些修改,不可能让 IOCTL 调用在 Slitaz 中正常工作。当我打电话给

printf("%s\n",strerror(errno));

我刚刚得到

No Such Device

如果它在两种架构上都不能正常工作,我会进行更深入的搜索,但在这里我完全迷路了,它在 Arch 上工作正常但在 Slitaz 上却不行。在这些更改之前它在 Slitaz 中工作,我仍然可以使用旧版本(git 中有 2 个分支,一个用于旧版本,一个用于当前版本)。

感谢您的帮助。

日光


以下是代码的相关部分(我显示 MAC oinyl 因为 IP 问题是相同的):

/*
 * Return a ifreq structure for this interface
 * */
    struct ifreq
get_ifreq ( const char * interface )
{

    struct ifreq ifr;
    size_t if_len;


    if_len = strlen(interface);
    if (if_len >= sizeof(ifr.ifr_name)){
        fprintf(stderr,"Interface name too long to open descriptor.\nAbort.");
        exit(EXIT_FAILURE);
    }

    strncpy(ifr.ifr_name,interface,if_len);

    return ifr;
}

int 
get_mac_address(const char * interface, struct ether_addr * ether) {
    int fd ;
    struct ifreq ifr = get_ifreq(interface);
    if((fd = get_socketudp()) == -1) {
        fprintf(stderr,"Unable to get mac address.\n");
        return -1;
    };

    if(ioctl(fd,SIOCGIFHWADDR,&ifr) == -1) {
        fprintf(stderr,"%s\n",strerror(fd));
        fprintf(stderr,"Error while operating IOCTL (MAC resolving).\n");
        close(fd);
        return -1;
    } 
    close(fd);
    memcpy(ether,&ifr.ifr_hwaddr.sa_data,ETH_ALEN);
    return 0;

}

并且在 main.c 中,我调用此函数的地方:

char * interface = NULL;

/*----------------------------------------------------------------------
*  Our OWN mac address & ip address
*-----------------------------------------------------------------------*/
struct ether_addr mac;
struct in_addr ip;

    int
main ( int argc, char *argv[] )
{
    char * operation = NULL;
    char * hostA = NULL;
    char * hostB = NULL;
    int c = 0;

    if (argc < 2) {
        usage();
        exit(EXIT_FAILURE);
    }

    while((c = getopt(argc,argv,"m:i:a:b:f:l:")) != -1){
        switch(c){
            case 'm':
                operation = optarg;
                if (strncmp(operation,"mitm",4) != 0 &&
                        strncmp(operation,"flood",5) != 0) {
                    fprintf(stderr,"Operation %s is unknown.Abort\n",operation);
                    abort();
                }
                break;
            case 'i':
                interface = optarg;
                break;

            case '?':
                fprintf(stderr,"Option %c requires an argument",optopt);
                abort();
        }
    }


    /* Check options consistency */
    if(operation == NULL) { 
        fprintf(stderr,"No Operations given. Abort.\n");
        exit(EXIT_FAILURE);
    } else if (interface == NULL) {
        fprintf(stderr,"No interface given. Abort.\n");
        exit(EXIT_FAILURE);
    } 



    /* Store our own mac address */
    if (get_mac_address(interface,mac) == -1) {
        fprintf(stderr,"Abort.\n");
        exit(EXIT_FAILURE);
    }

解决方案

感谢回答者,我将 get_ifreq 方法更改为:

    struct ifreq
get_ifreq ( const char * interface )
{

    struct ifreq ifr;
    size_t if_len;

    memset(ifr.ifr_name,0x00,IFNAMSIZ);
    if_len = strlen(interface);
    if (if_len >= IFNAMSIZ){
        fprintf(stderr,"Interface name too long to open descriptor.\nAbort.");
        exit(EXIT_FAILURE);
    }

    strncpy(ifr.ifr_name,interface,if_len);

    return ifr;
}

似乎 ifreq 结构中存在您未在此处清除的额外垃圾:

struct ifreq ifr;
if_len = strlen(interface);
strncpy(ifr.ifr_name,interface,if_len);

您在堆栈上声明了 ifreq 结构但未对其进行初始化,因此该结构中的字节可能是随机垃圾。然后,您将 if_len 个字节精确地复制到其中,但是紧随其后的字节呢?假设 if_len 小于 IFNAMSIZ,内核如何知道在解释接口名称时停在 if_len?

我会在 strncpy 之前清除结构。