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;
}
这很可能是有在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之前清除结构。
哇,谢谢,它已经奏效!如何使用相同的界面名称来工作...我不知道。但是,谢谢! – Nikkolasg 2015-03-19 10:58:15
您是否试过简单阅读'/ sys/class/net/eth0/address'文件? – myaut 2015-03-19 10:34:15
我希望代码尽可能便携。不依赖于特定的文件夹。 – Nikkolasg 2015-03-19 10:35:51
'/ sys'是'sysfs'文件系统的挂载点,可以直接从内核导出数据。它应该可以在任何Linux 2.6系统上使用(除非是非常奇特的情况,例如http:// *。com/questions/26913935/linux-without-sysfs-debugfs-filesystem) – myaut 2015-03-19 10:44:27