Linux提供了一系列网络接口操做相关的命令集,其中,一些传统的工具,如net-tools软件包中的ifconfig(8),arp(8),route(8)等都是经过ioctl(2)系统调用实现
本篇介绍使用ioctl(2)进行网络接口参数的获取与设置linux
#include <sys/ioctl.h> int ioctl(int d, int request, ...);
第一个参数fd指定一个由open(2)/socket(2)建立的文件描述符
第二个参数request指定操做的类型,即对该文件描述符执行何种操做
第三个参数为一块内存区域,一般依赖于request指定的操做类型ios
内核版本:2.6.32.5数组
ioctl(2)使用struct ifreq与/或struct ifconf结构执行网络接口相关的操做,这两个结构的地址做为ioctl(2)的第三个参数网络
/* include/linux/if.h */ #define IFNAMSIZ 16 #define IFALIASZ 256 struct ifreq { #define IFHWADDRLEN 6 union { char ifrn_name[IFNAMSIZ]; } ifr_ifrn; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short ifru_flags; int ifru_ivalue; int ifru_mtu; struct ifmap ifru_map; char ifru_slave[IFNAMSIZ]; char ifru_newname[IFNAMSIZ]; void __user * ifru_data; struct if_settings ifru_settings; } ifr_ifru; }; #define ifr_name ifr_ifrn.ifrn_name /* interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ #define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ #define ifr_metric ifr_ifru.ifru_ivalue /* metric */ #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ #define ifr_map ifr_ifru.ifru_map /* device map */ #define ifr_slave ifr_ifru.ifru_slave /* slave device */ #define ifr_data ifr_ifru.ifru_data /* for use by interface */ #define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ #define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ #define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */ #define ifr_newname ifr_ifru.ifru_newname /* New name */ #define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/ struct ifconf { int ifc_len; union { char __user *ifcu_buf; struct ifreq __user *ifcu_req; } ifc_ifcu; }; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */
操做类型,ioctl(2)的第二个参数app
/* include/linux/sockios.h */ /* Socket configuration controls. */ #define SIOCGIFNAME 0x8910 /* get iface name */ #define SIOCSIFLINK 0x8911 /* set iface channel */ #define SIOCGIFCONF 0x8912 /* get iface list */ #define SIOCGIFFLAGS 0x8913 /* get flags */ #define SIOCSIFFLAGS 0x8914 /* set flags */ #define SIOCGIFADDR 0x8915 /* get PA address */ #define SIOCSIFADDR 0x8916 /* set PA address */ #define SIOCGIFDSTADDR 0x8917 /* get remote PA address */ #define SIOCSIFDSTADDR 0x8918 /* set remote PA address */ #define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ #define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ #define SIOCGIFNETMASK 0x891b /* get network PA mask */ #define SIOCSIFNETMASK 0x891c /* set network PA mask */ #define SIOCGIFMETRIC 0x891d /* get metric */ #define SIOCSIFMETRIC 0x891e /* set metric */ #define SIOCGIFMEM 0x891f /* get memory address (BSD) */ #define SIOCSIFMEM 0x8920 /* set memory address (BSD) */ #define SIOCGIFMTU 0x8921 /* get MTU size */ #define SIOCSIFMTU 0x8922 /* set MTU size */ #define SIOCSIFNAME 0x8923 /* set interface name */ #define SIOCSIFHWADDR 0x8924 /* set hardware address */ #define SIOCGIFENCAP 0x8925 /* get/set encapsulations */ #define SIOCSIFENCAP 0x8926 #define SIOCGIFHWADDR 0x8927 /* Get hardware address */ #define SIOCGIFSLAVE 0x8929 /* Driver slaving support */ #define SIOCSIFSLAVE 0x8930 #define SIOCADDMULTI 0x8931 /* Multicast address lists */ #define SIOCDELMULTI 0x8932 #define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */ #define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */ #define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */ #define SIOCGIFPFLAGS 0x8935 #define SIOCDIFADDR 0x8936 /* delete PA address */ #define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ #define SIOCGIFCOUNT 0x8938 /* get number of devices */ ... #define SIOCETHTOOL 0x8946 /* Ethtool interface */
结构字段与操做类型的含义在大都在注释中已注明socket
经过ioctl(2)执行网络接口参数的获取/设置的通常步骤为:函数
经过socket(2)建立IP套接字;因为ioctl(2)此时是与内核通讯,所以对套接字的通讯域与类型没有强制要求,通讯域能够为AF_INET/AF_LOCAL,类型能够为SOCK_DGRAM/SOCK_STREAM/SOCK_RAW等工具
初始化struct ifconf与/或struct ifreq结构oop
对套接字描述符调用ioctl(2),执行相应类型的SIO操做code
获取返回至truct ifconf与/或struct ifreq结构中的相关信息
本地网络接口信息:eth0网线已链接且已配置IPv4地址,eth1网线未链接且未配置IPv4地址
# ip l 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:ed:9d:28 brd ff:ff:ff:ff:ff:ff 3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000 link/ether 00:0c:29:ed:9d:32 brd ff:ff:ff:ff:ff:ff # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:ed:9d:28 brd ff:ff:ff:ff:ff:ff inet 192.168.56.139/24 brd 192.168.56.255 scope global eth0 inet6 fe80::20c:29ff:feed:9d28/64 scope link valid_lft forever preferred_lft forever 3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000 link/ether 00:0c:29:ed:9d:32 brd ff:ff:ff:ff:ff:ff
1 . 经过SIOCGIFCONF操做获取系统中全部的网络接口
/* list_network_interfaces_ioctl.c */ #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <net/if.h> #include <string.h> #define BUFSIZE 1024 int main(int argc, char *argv[]) { int sfd, if_count, i; struct ifconf ifc; struct ifreq ifr[10]; char ipaddr[INET_ADDRSTRLEN] = {'\0'}; memset(&ifc, 0, sizeof(struct ifconf)); sfd = socket(AF_INET, SOCK_DGRAM, 0); ifc.ifc_len = 10 * sizeof(struct ifreq); ifc.ifc_buf = (char *)ifr; /* SIOCGIFCONF is IP specific. see netdevice(7) */ ioctl(sfd, SIOCGIFCONF, (char *)&ifc); if_count = ifc.ifc_len / (sizeof(struct ifreq)); for (i = 0; i < if_count; i++) { printf("Interface %s : ", ifr[i].ifr_name); inet_ntop(AF_INET, &(((struct sockaddr_in *)&(ifr[i].ifr_addr))->sin_addr), ipaddr, INET_ADDRSTRLEN); printf("%s\n", ipaddr); } close(sfd); exit(EXIT_SUCCESS); }
编译并运行
# gcc list_network_interfaces_ioctl.c -g -o list_network_interfaces_ioctl # ./list_network_interfaces_ioctl Interface lo : 127.0.0.1 Interface eth0 : 192.168.56.139
SIOCGIFCONF操做须要同时使用struct ifconf与struct ifreq
初始化struct ifconf时,ifc_ifcu指定一个缓冲区的首地址,缓冲区中保存若干个连续的struct ifreq,ifc_len指定该缓冲区的长度;ioctl(2)返回后,内核将为每个配置了IPv4地址的本地网络接口分配一个struct ifreq并保存到初始化的缓冲区中,struct ifreq中保存单个网络接口的名称及IPv4地址,struct ifconf的ifc_len被更新为初始化缓冲区中实际返回的数据长度
2 . 经过SIOCGIFADDR操做获取指定网络接口的IPv4地址
/* get_interface_ip_address_ioctl.c */ #include <stdio.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <errno.h> static char *get_ipaddr(const char *); int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s [network interface name]\n", argv[0]); exit(EXIT_FAILURE); } char ifname[IFNAMSIZ] = {'\0'}; strncpy(ifname, argv[1], IFNAMSIZ-1); char *ip = get_ipaddr(ifname); printf("Interface %s : %s\n", ifname, ip); return 0; } static char *get_ipaddr(const char *dev) { int sfd, saved_errno, ret; struct ifreq ifr; char *ipaddr; ipaddr = (char *)malloc(INET_ADDRSTRLEN); memset(&ifr, 0, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, dev, IFNAMSIZ); sfd = socket(AF_INET, SOCK_DGRAM, 0); errno = saved_errno; ret = ioctl(sfd, SIOCGIFADDR, &ifr); if (ret == -1) { if (errno == 19) { fprintf(stderr, "Interface %s : No such device.\n", dev); exit(EXIT_FAILURE); } if (errno == 99) { fprintf(stderr, "Interface %s : No IPv4 address assigned.\n", dev); exit(EXIT_FAILURE); } } saved_errno = errno; inet_ntop(AF_INET, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), ipaddr, INET_ADDRSTRLEN); close(sfd); return ipaddr; }
编译并运行
# gcc get_interface_ip_address_ioctl.c -g -o get_interface_ip_address_ioctl # # ./get_interface_ip_address_ioctl eth0 Interface eth0 : 192.168.56.139 # # ./get_interface_ip_address_ioctl eth1 Interface eth1 : No IPv4 address assigned. # # ./get_interface_ip_address_ioctl eth2 Interface eth2 : No such device.
SIOCGIFADDR操做使用struct ifreq中的ifr_ifru.ifru_addr字段;ifr_ifrn.ifrn_name指定为网络接口名称并调用ioctl(SIOCGIFADDR),返回后将ifr_ifru.ifru_addr转换为IPv4套接字地址结构,IPv4地址保存在该结构中的sin_addr字段中
SIOCGIFCONF与SIOCGIFADDR属于IPv4特定的操做,对于未配置IPv4地址的网络接口,ioctl(SIOCGIFCONF)返回时不会分配struct ifreq结构,于是不会返回该接口的名称,而ioctl(SIOCGIFADDR)将以errno值99(Cannot assign requested address)而调用失败
若指定了系统中不存在的网络接口,则errno的值为19(No such device)
SIOCGIFCONF与SIOCGIFADDR没法获取网络接口的IPv6地址,ioctl的内核源码中经过读取/proc/net/if_inet6获取
3 . 经过SIOCGIFHWADDR操做获取指定网络接口的mac地址
/* get_interface_mac_address_ioctl.c */ #include <stdio.h> #include <stdlib.h> #include <net/if.h> #include <sys/ioctl.h> #include <errno.h> #include <string.h> #include <netinet/if_ether.h> #include <net/if_arp.h> static unsigned char *get_if_mac(const char *); int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s [network interface name]\n", argv[0]); exit(EXIT_FAILURE); } char ifname[IFNAMSIZ] = {'\0'}; strncpy(ifname, argv[1], IFNAMSIZ-1); unsigned char *mac = get_if_mac(ifname); printf("Interface %s : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", ifname, *mac, *(mac+1), *(mac+2), *(mac+3), *(mac+4), *(mac+5)); return 0; } static unsigned char *get_if_mac(const char *dev) { int sfd, ret, saved_errno, i; unsigned char *mac_addr; struct ifreq ifr; mac_addr = (unsigned char *)malloc(ETH_ALEN); sfd = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); saved_errno = errno; ret = ioctl(sfd, SIOCGIFHWADDR, &ifr); if (ret == -1 && errno == 19) { fprintf(stderr, "Interface %s : No such device.\n", dev); exit(EXIT_FAILURE); } errno = saved_errno; if (ifr.ifr_addr.sa_family == ARPHRD_LOOPBACK) { printf("Interface %s : A Loopback device.\n", dev); printf("MAC address is always 00:00:00:00:00:00\n"); exit(EXIT_SUCCESS); } if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) { fprintf(stderr, "Interface %s : Not an Ethernet device.\n", dev); exit(EXIT_FAILURE); } memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); return (unsigned char *)mac_addr; }
编译并运行
# gcc get_interface_mac_address_ioctl.c -g -o get_interface_mac_address_ioctl # # ./get_interface_mac_address_ioctl lo Interface lo : A Loopback device. MAC address is always 00:00:00:00:00:00 # # ./get_interface_mac_address_ioctl eth0 Interface eth0 : 00:0c:29:ed:9d:28 # # ./get_interface_mac_address_ioctl eth1 Interface eth1 : 00:0c:29:ed:9d:32 # # ./get_interface_mac_address_ioctl eth2 Interface eth2 : No such device.
SIOCGIFHWADDR操做使用struct ifreq中的ifr_ifru.ifru_hwaddr字段,在ifr_ifrn.ifrn_name中填充指定的网络接口名称后,该接口的mac地址按顺序返回到ifr_ifru.ifru_hwaddr.sa_data数组的前6个字节中
4 . 经过SIOCGIFFLAGS操做获取指定网络接口的标志
/* get_interface_flags_ioctl.c */ #include <stdio.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <netinet/if_ether.h> #include <net/if_arp.h> static short get_if_flags(int, char *); int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s [network interface name]\n", argv[0]); exit(EXIT_FAILURE); } int sfd; short flags; char ifname[IFNAMSIZ] = {'\0'}; strncpy(ifname, argv[1], IFNAMSIZ-1); sfd = socket(AF_INET, SOCK_DGRAM, 0); flags = get_if_flags(sfd, ifname); printf("Interface %s : ", ifname); if (flags & IFF_UP) printf("UP "); if (flags & IFF_RUNNING) printf("RUNNING "); if (flags & IFF_LOOPBACK) printf("LOOPBACK "); if (flags & IFF_BROADCAST) printf("BROADCAST "); if (flags & IFF_MULTICAST) printf("MULTICAST "); if (flags & IFF_PROMISC) printf("PROMISC"); #ifndef IFF_LOWER_UP #define IFF_LOWER_UP 0x10000 if (flags & IFF_LOWER_UP) printf("LOWER_UP"); #endif printf("\n"); close(sfd); exit(EXIT_SUCCESS); } static short get_if_flags(int s, char *dev) { int saved_errno, ret; short if_flags; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); saved_errno = errno; ret = ioctl(s, SIOCGIFFLAGS, &ifr); if (ret == -1 && errno == 19) { fprintf(stderr, "Interface %s : No such device.\n", dev); exit(EXIT_FAILURE); } errno = saved_errno; if_flags = ifr.ifr_flags; return if_flags; }
编译并运行
# gcc get_interface_flags_ioctl.c -g -o get_interface_flags_ioctl # # ./get_interface_flags_ioctl lo Interface lo : UP RUNNING LOOPBACK # # ./get_interface_flags_ioctl eth0 Interface eth0 : UP RUNNING BROADCAST MULTICAST # # ./get_interface_flags_ioctl eth1 Interface eth1 : UP BROADCAST MULTICAST # # ./get_interface_flags_ioctl eth2 Interface eth2 : No such device.
ifr_ifrn.ifrn_name指定为网络接口名称后,ioctl(SIOCGIFFLAGS)调用将标志返回到ifr_ifru.ifru_flags字段
IFF_RUNNING表示该接口已被激活,且能够正常传输数据
IFF_UP表示giant接口已被激活,但可能没法正常传输数据,如网线未链接的状况
IFF_LOWER_UP表示网络的物理链接已就绪,即网线链接正常;因为struct ifreq的ifr_ifru.ifru_flags类型为short,用16进制表示仅为4位,于是没法获取与设置5位16进制的IFF_LOWER_UP标志(0x10000)
5 .经过SIOCSIFADDR操做设置指定网络接口的IPv4地址
/* set_interface_ip_address_ioctl.c */ #include <stdio.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <errno.h> static void set_ipaddr(const char *, const char *); int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s [network interface name] [ip address]\n", argv[0]); exit(EXIT_FAILURE); } char ifname[IFNAMSIZ] = {'\0'}; strncpy(ifname, argv[1], IFNAMSIZ-1); char ipaddr[INET_ADDRSTRLEN] = {'\0'}; strncpy(ipaddr, argv[2], INET_ADDRSTRLEN); set_ipaddr(ifname, ipaddr); printf("Interface %s : ip address is set to %s\n", ifname, ipaddr); return 0; } static void set_ipaddr(const char *dev, const char *ip) { int sfd, saved_errno, ret; struct ifreq ifr; struct sockaddr_in sin; sfd = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; inet_pton(AF_INET, ip, &(sin.sin_addr)); memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr)); errno = saved_errno; ret = ioctl(sfd, SIOCSIFADDR, &ifr); if (ret == -1) { if (errno == 19) { fprintf(stderr, "Interface %s : No such device.\n", dev); exit(EXIT_FAILURE); } if (errno == 99) { fprintf(stderr, "Interface %s : No IPv4 address assigned.\n", dev); exit(EXIT_FAILURE); } } saved_errno = errno; close(sfd); }
编译并运行
# gcc set_interface_ip_address_ioctl.c -g -o set_interface_ip_address_ioctl # # ./set_interface_ip_address_ioctl eth1 10.0.0.1 Interface eth1 : ip address is set to 10.0.0.1 # # ./get_interface_ip_address_ioctl eth1 Interface eth1 : 10.0.0.1 # # ./set_interface_ip_address_ioctl eth1 10.0.0.2 Interface eth1 : ip address is set to 10.0.0.2 # # ./get_interface_ip_address_ioctl eth1 Interface eth1 : 10.0.0.2
与ifconfig(8)相同,屡次指定同一网络接口名称设置IP地址时,最后的设置将覆盖先前的设置而生效
6 . 经过SIOCGIFFLAGS操做设置指定网络接口的标志
使用ifconfig(8)将eth1设置为混杂模式,并关闭该接口,而后在程序中关闭混杂模式,并开启该接口
# ifconfig eth1 promisc # # ifconfig eth1 down # # ./get_interface_flags_ioctl eth1 Interface eth1 : BROADCAST MULTICAST PROMISC
/* set_interface_flags_ioctl.c */ #include <stdio.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <errno.h> static short get_if_flags(int, struct ifreq*); static void set_if_flags(int, struct ifreq*); int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s [network interface name]\n", argv[0]); exit(EXIT_FAILURE); } int sfd; short flags; struct ifreq ifr; char ifname[IFNAMSIZ] = {'\0'}; strncpy(ifname, argv[1], IFNAMSIZ-1); sfd = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ); flags = get_if_flags(sfd, &ifr); ifr.ifr_flags = flags; /* set IFF_UP if cleared */ if (!(flags & IFF_UP)) { ifr.ifr_flags |= IFF_UP; set_if_flags(sfd, &ifr); printf("Interface %s : UP set.\n", ifname); } flags = ifr.ifr_flags; /* clear IFF_PROMISC if set */ if (flags & IFF_PROMISC) { ifr.ifr_flags &= ~IFF_PROMISC; set_if_flags(sfd, &ifr); printf("Interface %s : PROMISC cleared.\n", ifname); } close(sfd); exit(EXIT_SUCCESS); } static short get_if_flags(int s, struct ifreq *ifr) { int ret, saved_errno; short if_flags; saved_errno = errno; ret = ioctl(s, SIOCGIFFLAGS, ifr); if (ret == -1 && errno == 19) { fprintf(stderr, "Interface %s : No such device.\n", ifr->ifr_name); exit(EXIT_FAILURE); } errno = saved_errno; if_flags = ifr->ifr_flags; return if_flags; } static void set_if_flags(int s, struct ifreq *ifr) { int ret, saved_errno; saved_errno = errno; ret = ioctl(s, SIOCSIFFLAGS, ifr); if (ret == -1) { fprintf(stderr, "Interface %s : %s\n", ifr->ifr_name, strerror(errno)); exit(EXIT_FAILURE); } errno = saved_errno; }
编译并运行
# gcc set_interface_flags_ioctl.c -g -o set_interface_flags_ioctl # # ./set_interface_flags_ioctl eth1 Interface eth1 : UP set. Interface eth1 : PROMISC cleared. # # ./get_interface_flags_ioctl eth1 Interface eth1 : UP BROADCAST MULTICAST
7 .经过SIOCSIFNAME操做更改网络接口的名称
/* change_ifname_ioctl.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <net/if.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> static void change_ifname(char *, char *); static void shutdown_if_up(char *); int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "%s [old ifname] [new ifname]\n", argv[0]); exit(EXIT_FAILURE); } char old_ifname[IFNAMSIZ] = {'\0'}; strncpy(old_ifname, argv[1], IFNAMSIZ); char new_ifname[IFNAMSIZ] = {'\0'}; strncpy(new_ifname, argv[2], IFNAMSIZ); change_ifname(old_ifname, new_ifname); printf("Interface name %s has been changed to %s\n", old_ifname, new_ifname); return 0; } void change_ifname(char *old_dev, char *new_dev) { int sfd, ret, saved_errno; struct ifreq ifr; shutdown_if_up(old_dev); sfd = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, old_dev, IFNAMSIZ); strncpy(ifr.ifr_newname, new_dev, IFNAMSIZ); saved_errno = errno; ret = ioctl(sfd, SIOCSIFNAME, &ifr); if (ret == -1) { fprintf(stderr, "Interface %s : %s\n", dev, strerror(errno)); exit(EXIT_FAILURE); } errno = saved_errno; } static void shutdown_if_up(char *dev) { int sfd, ret, saved_errno; short flags; struct ifreq ifr; sfd = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); saved_errno = errno; ret = ioctl(sfd, SIOCGIFFLAGS, &ifr); if (ret == -1) { fprintf(stderr, "Interface %s : %s\n", dev, strerror(errno)); exit(EXIT_FAILURE); } errno = saved_errno; flags = ifr.ifr_flags; if (flags & IFF_UP) { ifr.ifr_flags &= ~IFF_UP; saved_errno = errno; ret = ioctl(sfd, SIOCSIFFLAGS, &ifr); if (ret == -1) { fprintf(stderr, "Interface %s : %s\n",dev, strerror(errno)); exit(EXIT_FAILURE); } errno = saved_errno; } }
将struct ifreq的ifr_ifrn.ifrn_name指定为网络接口名称后,ioctl(SIOCSIFNAME)将指定的新名称写入到ifr_ifru.ifru_newname中;该操做要求网络接口为关闭状态,即(~IFF_UP)