在linux下使用ioctl操作網(wǎng)絡(luò)接口時(shí),首先需要兩個(gè)結(jié)構(gòu)體結(jié)構(gòu)ifconf和ifreq ifconf用來(lái)保存所有網(wǎng)絡(luò)接口的信息,其結(jié)構(gòu)體為:
ifreq用來(lái)保存某個(gè)接口的信息,用來(lái)獲取Ip地址,MAC,子網(wǎng)掩碼等網(wǎng)絡(luò)接口信息,其結(jié)構(gòu)體為:
具體操作方法是: 1.通過(guò)ioctl獲得本地所有接口的信息并保存在ifconf結(jié)構(gòu)體中; 2.在從ifconf中獲得具體某個(gè)ifreq的接口信息 其中: ifc_len:表示用來(lái)存放所有接口信息的緩沖區(qū)長(zhǎng)度 ifc_buf:表示存放接口信息的緩沖區(qū) 因此我們需要在程序開始時(shí)對(duì)ifconf的ifc_led和ifc_buf進(jìn)行初始化 實(shí)例: #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); //接下來(lái)一個(gè)一個(gè)的獲取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 } 此參考程序是通過(guò)ioctl獲得本地接口的信息,我們也可以通過(guò)操作socket的函數(shù)寫一些小的應(yīng)用程序,下面的例子是實(shí)現(xiàn)ifconfig的源代碼(自測(cè)試,可通過(guò)) #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); //啟動(dòng)接口 int set_if_down(char *interface_name); //關(guān)閉接口 int set_if_ip(char *interface_name, char *ip_str); //設(shè)置接口的ip地址 void usage(); //打印該程序的使用手冊(cè) 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地址轉(zhuǎn)換為主機(jī)字節(jié)序的字符串并輸出 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; //獲得子網(wǎng)掩碼。注意!我們?nèi)苑旁趕truct aockaddr_in結(jié)構(gòu)中返回 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!因?yàn)閏har要對(duì)[1xxx xxxx]這樣的數(shù)進(jìn)行補(bǔ)碼運(yùn)算的。 //但我們等下要打印的mac地址是不需要符號(hào)的數(shù)值 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地址,用字符串指針?lè)祷?/div> 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++); //這么寫會(huì)導(dǎo)致輸出為倒序。這并不是p指針有什么問(wèn)題,不信你可以用 // for(;;) // printf(p++); //來(lái)試驗(yàn)就是正確的,我猜倒序的原因是編譯器的優(yōu)化問(wèn)題吧 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; //獲得子網(wǎng)掩碼。注意!我們?nèi)苑旁趕truct aockaddr_in結(jié)構(gòu)中返回 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; } // 創(chuàng)建用來(lái)檢查網(wǎng)絡(luò)接口的套接字 /* strcpy(ifr.ifr_name, if_name); if(ioctl(fd, SIOCGIFMTU, &ifr) < 0) { perror("ioctl SIOCGIFMTU error"); return -1; } mtu = ifr.ifr_ifru.ifru_mtu; //獲得子網(wǎng)掩碼。注意!我們?nèi)苑旁趕truct aockaddr_in結(jié)構(gòu)中返回 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; } // 創(chuàng)建用來(lái)檢查網(wǎng)絡(luò)接口的套接字 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; } // 創(chuàng)建用來(lái)檢查網(wǎng)絡(luò)接口的套接字 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) //啟動(dòng)接口 { struct ifreq ifr; int sockfd; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 創(chuàng)建用來(lái)檢查網(wǎng)絡(luò)接口的套接字 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) //關(guān)閉接口 { struct ifreq ifr; int sockfd; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("Socket error"); return -1; } // 創(chuàng)建用來(lái)檢查網(wǎng)絡(luò)接口的套接字 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取反后與原來(lái)的標(biāo)志進(jìn)行 與運(yùn)算。 if(ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { perror("ioctl SIOCSIFFLAGS error"); return -1; } return 0; } int set_if_ip(char *if_name, char *ip_str) //設(shè)置接口的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; } // 創(chuàng)建用來(lái)檢查網(wǎng)絡(luò)接口的套接字 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; } |
|
來(lái)自: 身子莫 > 《linux內(nèi)核及操作系統(tǒng)》