在linux下使用ioctl操作网络接口时,首先需要两个结构体结构ifconf和ifreq ifconf用来保存所有网络接口的信息,其结构体为:
ifreq用来保存某个接口的信息,用来获取Ip地址,MAC,子网掩码等网络接口信息,其结构体为:
具体操作方法是: 1.通过ioctl获得本地所有接口的信息并保存在ifconf结构体中; 2.在从ifconf中获得具体某个ifreq的接口信息 其中: ifc_len:表示用来存放所有接口信息的缓冲区长度 ifc_buf:表示存放接口信息的缓冲区 因此我们需要在程序开始时对ifconf的ifc_led和ifc_buf进行初始化 实例: #include <string.h> #include <net/if.h> #include <unistd.h> #include <sys/ioctl.h> #include <netinet/in.h> int { int int struct unsigned struct //初始化ifconf ifconf.ifc_len = 512; ifconf.ifc_buf = buf; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0) { perror("socket"); exit(1); } ioctl(sockfd, SIOCGIFCONF, &ifconf); //接下来一个一个的获取IP地址 ifreq = (struct for(i=(ifconf.ifc_len/sizeof(struct { printf("name = [%s]n", ifreq->ifr_name); printf("local addr = [%s]n", inet_ntoa(((struct ifreq++; } return } 此参考程序是通过ioctl获得本地接口的信息,我们也可以通过操作socket的函数写一些小的应用程序,下面的例子是实现ifconfig的源代码(自测试,可通过) #include <stdio.h> //printf() #include <unistd.h> //ioctl() #include <sys/ioctl.h> //ioctl #include <sys/socket.h> //socket() #include <net/if.h> //struct ifconf{} & struct ifreq{} #include <string.h> //strcpy() #include <arpa/inet.h> //inet_ntoa() #include <stdlib.h> //malloc() & free() int print_if_addr(int fd, char *interface_name); //打印接口的ip地址 int print_if_mac(int fd, char *interface_name); //打印接口的mac地址 int print_if_broadaddr(int fd, char *interface_name); //打印接口的广播地址 int print_if_mask(int fd, char *interface_name); //打印接口的掩码 int print_if_mtu(int fd, char *interface_name); //打印接口的mtu int print_all_interface(); //打印所有接口的基本信息 int print_if_addr6(char *interface_name); //打印接口的ipv6地址 int print_interface_info(char *interface_name); //打印接口的以上所有信息 int set_if_up(char *interface_name); //启动接口 int set_if_down(char *interface_name); //关闭接口 int set_if_ip(char *interface_name, char *ip_str); //设置接口的ip地址 void usage(); //打印该程序的使用手册 int main(int argc, char **argv) { int sockfd; switch(argc) { case 1: print_all_interface(); break; case 2: print_interface_info(argv[1]); break; case 3: if(strcmp(argv[2], "up") == 0) set_if_up(argv[1]); else if(strcmp(argv[2], "down") == 0) set_if_down(argv[1]); else set_if_ip(argv[1], argv[2]); break; default: usage(); break; } return 0; } void usage() { printf("usage: ./myifconfig [interface [down|up|ip]]\n"); } int print_if_addr(int fd, char *if_name) { struct sockaddr_in *ip; struct ifreq ifr; strcpy(ifr.ifr_name, if_name); if(ioctl(fd, SIOCGIFADDR, &ifr) < 0) { perror("ioctl SIOCGIFADDR error"); return -1; } ip = (struct sockaddr_in *)&ifr.ifr_addr; //获得ipv4地址 printf(" IP: %s\n", inet_ntoa(ip->sin_addr)); //将ipv4地址转换为主机字节序的字符串并输出 return 0; } int print_if_broadaddr(int fd, char *if_name) { struct sockaddr_in *ip; struct ifreq ifr; strcpy(ifr.ifr_name, if_name); if(ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) { perror("ioctl SIOCGIFBRDADDR error"); return -1; } ip = (struct sockaddr_in *)&ifr.ifr_broadaddr; //获得广播地址 printf(" Broadcast: %s\n", inet_ntoa(ip->sin_addr)); return 0; } int print_if_mask(int fd, char *if_name) { struct sockaddr_in *ip; struct ifreq ifr; strcpy(ifr.ifr_name, if_name); if(ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) { perror("ioctl SIOCGIFNETMASK error"); return -1; } ip = (struct sockaddr_in *)&ifr.ifr_ifru.ifru_netmask; //获得子网掩码。注意!我们仍放在struct aockaddr_in结构中返回 printf(" Mask: %s\n", inet_ntoa(ip->sin_addr)); return 0; } int print_if_mac(int fd, char *if_name) { unsigned char *p; //注意! 这里要用unsigned char,而不是char!因为char要对[1xxx xxxx]这样的数进行补码运算的。 //但我们等下要打印的mac地址是不需要符号的数值 struct ifreq ifr; strcpy(ifr.ifr_name, if_name); if(ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl SIOCGIFHWADDR error"); return -1; } p = (char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0]; //获得接口的MAC地址,用字符串指针返回 printf(" MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5)); //printf(" MAC:%02x:%02x:%02x:%02x:%02x:%02x/n", *p++, *p++, *p++, *p++, *p++, *p++); //这么写会导致输出为倒序。这并不是p指针有什么问题,不信你可以用 // for(;;) // printf(p++); //来试验就是正确的,我猜倒序的原因是编译器的优化问题吧 return 0; } int print_if_mtu(int fd, char *if_name) { unsigned int mtu; struct ifreq ifr; strcpy(ifr.ifr_name, if_name); if(ioctl(fd, SIOCGIFMTU, &ifr) < 0) { perror("ioctl SIOCGIFMTU error"); return -1; } mtu = ifr.ifr_ifru.ifru_mtu; //获得子网掩码。注意!我们仍放在struct aockaddr_in结构中返回 printf(" MTU: %d\n", mtu); return 0; } int print_if_addr6(char *if_name) { unsigned int mtu; struct ifreq ifr; int sockfd; if((sockfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 创建用来检查网络接口的套接字 /* strcpy(ifr.ifr_name, if_name); if(ioctl(fd, SIOCGIFMTU, &ifr) < 0) { perror("ioctl SIOCGIFMTU error"); return -1; } mtu = ifr.ifr_ifru.ifru_mtu; //获得子网掩码。注意!我们仍放在struct aockaddr_in结构中返回 printf(" ipv6: %d/n", mtu); */ //未写完,不知道怎么获得ipv6地址。。。 return 0; } int print_all_interface() { struct ifconf ifc; struct ifreq *ifr_p; int sockfd, len, old_len = 0, i; char *buf; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 创建用来检查网络接口的套接字 len = 10 * sizeof(struct ifreq); for( ; ; ) { if((buf = malloc(len)) == NULL) { perror("malloc error"); return -1; } ifc.ifc_len = len; ifc.ifc_buf = buf; if(ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { perror("ioctl SIOCGIFCONF error"); return -1; } if(ifc.ifc_len == old_len) break; old_len = ifc.ifc_len; len += 10 * sizeof(struct ifreq); free(buf); } printf("we have %d Interfaces\n", ifc.ifc_len / sizeof(struct ifreq)); for(i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++) { ifr_p = &ifc.ifc_req[i]; printf(" Interface [%s]:\n", ifr_p->ifr_name); print_if_addr(sockfd, ifr_p->ifr_name); print_if_broadaddr(sockfd, ifr_p->ifr_name); print_if_mask(sockfd, ifr_p->ifr_name); print_if_mac(sockfd, ifr_p->ifr_name); print_if_mtu(sockfd, ifr_p->ifr_name); } close(sockfd); return 0; } int print_interface_info(char *if_name) { int sockfd; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 创建用来检查网络接口的套接字 printf("%s:\n", if_name); print_if_addr(sockfd, if_name); print_if_broadaddr(sockfd, if_name); print_if_mask(sockfd, if_name); print_if_mac(sockfd, if_name); print_if_mtu(sockfd, if_name); close(sockfd); return 0; } int set_if_up(char *if_name) //启动接口 { struct ifreq ifr; int sockfd; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 创建用来检查网络接口的套接字 strcpy(ifr.ifr_name, if_name); if(ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { perror("ioctl SIOCGIFFLAGS error"); return -1; } ifr.ifr_flags |= IFF_UP; if(ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { perror("ioctl SIOCSIFFLAGS error"); return -1; } return 0; } int set_if_down(char *if_name) //关闭接口 { struct ifreq ifr; int sockfd; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 创建用来检查网络接口的套接字 strcpy(ifr.ifr_name, if_name); if(ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { perror("ioctl SIOCGIFFLAGS error"); return -1; } ifr.ifr_flags &= ~IFF_UP; //将IIF_UP取反后与原来的标志进行 与运算。 if(ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { perror("ioctl SIOCSIFFLAGS error"); return -1; } return 0; } int set_if_ip(char *if_name, char *ip_str) //设置接口的ip地址 { struct ifreq ifr; struct sockaddr_in ip_addr; int sockfd; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 创建用来检查网络接口的套接字 ip_addr.sin_family = AF_INET; if(inet_pton(AF_INET, ip_str, &ip_addr.sin_addr) < 1) { perror("error ipv4 addr:"); return -1; } strcpy(ifr.ifr_name, if_name); memcpy(&ifr.ifr_addr, &ip_addr, sizeof(struct sockaddr_in)); if(ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { perror("ioctl SIOCSIFADDR error"); return -1; } return 0; } |
|
来自: 身子莫 > 《linux内核及操作系统》