IOCTL调用在某些体系结构上工作

问题描述:

我正在使用C语言编写程序,它需要查找IP &接口的MAC地址。我正在使用IOCTL调用。直到最近,我仍然使用自定义数据结构来存储这些地址,并且一切都很完美。 后来我搬到了使用标准结构喜欢IOCTL调用在某些体系结构上工作

struct in_addr

struct ether_addr

在我的操作系统(Archlinux)上,它仍然正常工作,所以这很好。但通常我会将我的程序运行到VirtualBox中的虚拟化环境(Slitaz linux)中。我这样做是为了使用GNS3运行虚拟化网络。由于这些修改,无法使Slitaz中的IOCTL调用正常工作。当我打电话

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

我只是得到

没有这样的设备

如果不是两个架构正常工作,我会寻找更深入,但在这里我完全失去了,它在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); 
    } 

SOLUTION

得益于雁我改变了我的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; 
} 
+0

您是否试过简单阅读'/ sys/class/net/eth0/address'文件? – myaut 2015-03-19 10:34:15

+0

我希望代码尽可能便携。不依赖于特定的文件夹。 – Nikkolasg 2015-03-19 10:35:51

+0

'/ sys'是'sysfs'文件系统的挂载点,可以直接从内核导出数据。它应该可以在任何Linux 2.6系统上使用(除非是非常奇特的情况,例如http:// *。com/questions/26913935/linux-without-sysfs-debugfs-filesystem) – myaut 2015-03-19 10:44:27

这很可能是有在ifreq结构所附加的垃圾,你不清除出在这里:

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

您在堆栈中声明struct ifreq,但不要初始化它,以便该结构中的字节可能是随机垃圾。然后,您将if_len字节完全复制到它中,但紧接着的字节又如何呢?假设if_len小于IFNAMSIZ,在解释接口名称时,内核如何知道if_len会停止?

我会在strncpy之前清除结构。

+0

哇,谢谢,它已经奏效!如何使用相同的界面名称来工作...我不知道。但是,谢谢! – Nikkolasg 2015-03-19 10:58:15