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)