ioctl相当于一个杂物箱,它一直作为那些不适合归入其他精细定义类别的特性的系统接口。
本章笔记先放着,到时候有需要再看
ioctl函数
#include <unistd.h> int ioctl(int fd,int request,.../* void *arg */);
其中第三个参数总是一个指针,但指针的类型依赖于request参数。
我们可以把网络相关的请求(request)划分为6类:
1.套接字操作
2.文件操作
3.接口操作
4.ARP高速缓存操作
5.路由表操作
6.流系统
下图列出了网络相关ioctl请求的request参数以及arg地址必须指向的数据类型:
套接字操作
SIOCATMARK 如果本套接字的读指针当前位于带外标记,那就通过由第三个参数指向的整数返回一个非0值,否则返回一个0值
SIOCGPGRP 通过由第三个参数指向的整数返回本套接字的进程ID或进程组ID
SIOCSGRP 把本进程进程ID或进程组ID设置成由第三个参数指向的整数
文件操作
FIONBIO 根据ioctl的第三个参数指向一个0值或非0值,可清除或设置本套接字的非阻塞式I/O标志
FIOASYNC 根据ioctl的第三个参数指向一个0值或非0值,可清除或设置本套接字的信号驱动异步I/O标志,它决定是否收取针对本套接字的异步I/O信号(SIGIO)
FIONREAD 通过由ioctl的第三个参数指向的整数返回当前本套接字接收缓冲区中的字节数
FIOSETOWN 对于套接字和SIOCSPGRP等效
FIOGETOWN 对于套接字和SIOCGPGRP等效
接口配置
需处理网络接口的许多程序的初始步骤之一就是从内核获取配置在系统中的所有接口。本任务由SIOCGIFCONF请求完成,它使用ifconf结构,ifconf又使用ifreq结构。这两个结构定义如下:
struct ifconf { int ifc_len; /* size of buffer */ union { char *ifcu_buf; /* input from user->kernel*/ struct ifreq *ifcu_req; /* return from kernel->user*/ } ifc_ifcu; }; #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ //ifreq用来保存某个接口的信息 //if.h struct ifreq { char ifr_name[IFNAMSIZ]; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; short ifru_flags; int ifru_metric; caddr_t ifru_data; } ifr_ifru; }; #define ifr_addr ifr_ifru.ifru_addr #define ifr_dstaddr ifr_ifru.ifru_dstaddr #define ifr_broadaddr ifr_ifru.ifru_broadaddr
在调用ioctl前我们先分配一个缓冲区和一个ifconf结构,然后初始化后者。下面展示这个ifconf结构的初始化结果,其中缓冲区的大小为1024字节
假设内核返回2个ifreq结构,在ioctl返回时通过同一个ifconf结构所返回的值如下图。缓冲区被填入两个ifreq结构,而且ifconf结构的ifc_len成员也被更新
get_ifi_info函数(暂时不看)
我们使用ioctl开发一个名为get_ifi_info的函数,它返回一个结构链表,其中每个结构对应一个当前处于“up”状态的接口。
头文件
1 /* Our own header for the programs that need interface configuration info. 2 Include this file, instead of "unp.h". */ 3 4 #ifndef __unp_ifi_h 5 #define __unp_ifi_h 6 7 #include "unp.h" 8 #include <net/if.h> 9 10 #define IFI_NAME 16 /* same as IFNAMSIZ in <net/if.h> */ 11 #define IFI_HADDR 8 /* allow for 64-bit EUI-64 in future */ 12 13 struct ifi_info { 14 char ifi_name[IFI_NAME]; /* interface name, null-terminated */ 15 short ifi_index; /* interface index */ 16 short ifi_mtu; /* interface MTU */ 17 u_char ifi_haddr[IFI_HADDR]; /* hardware address */ 18 u_short ifi_hlen; /* # bytes in hardware address: 0, 6, 8 */ 19 short ifi_flags; /* IFF_xxx constants from <net/if.h> */ 20 short ifi_myflags; /* our own IFI_xxx flags */ 21 struct sockaddr *ifi_addr; /* primary address */ 22 struct sockaddr *ifi_brdaddr;/* broadcast address */ 23 struct sockaddr *ifi_dstaddr;/* destination address */ 24 struct ifi_info *ifi_next; /* next of these structures */ 25 }; 26 27 #define IFI_ALIAS 1 /* ifi_addr is an alias */ 28 29 /* function prototypes */ 30 struct ifi_info *get_ifi_info(int, int); 31 struct ifi_info *Get_ifi_info(int, int); 32 void free_ifi_info(struct ifi_info *); 33 34 #endif /* __unp_ifi_h */
main函数
1 #include "unpifi.h" 2 3 int 4 main(int argc, char **argv) 5 { 6 struct ifi_info *ifi, *ifihead; 7 struct sockaddr *sa; 8 u_char *ptr; 9 int i, family, doaliases; 10 11 if (argc != 3) 12 err_quit("usage: prifinfo <inet4|inet6> <doaliases>"); 13 14 if (strcmp(argv[1], "inet4") == 0) 15 family = AF_INET; 16 #ifdef IPv6 17 else if (strcmp(argv[1], "inet6") == 0) 18 family = AF_INET6; 19 #endif 20 else 21 err_quit("invalid <address-family>"); 22 doaliases = atoi(argv[2]); 23 24 for (ifihead = ifi = Get_ifi_info(family, doaliases); 25 ifi != NULL; ifi = ifi->ifi_next) { 26 printf("%s: ", ifi->ifi_name); 27 if (ifi->ifi_index != 0) 28 printf("(%d) ", ifi->ifi_index); 29 printf("<"); 30 /* *INDENT-OFF* */ 31 if (ifi->ifi_flags & IFF_UP) printf("UP "); 32 if (ifi->ifi_flags & IFF_BROADCAST) printf("BCAST "); 33 if (ifi->ifi_flags & IFF_MULTICAST) printf("MCAST "); 34 if (ifi->ifi_flags & IFF_LOOPBACK) printf("LOOP "); 35 if (ifi->ifi_flags & IFF_POINTOPOINT) printf("P2P "); 36 printf("> "); 37 /* *INDENT-ON* */ 38 39 if ( (i = ifi->ifi_hlen) > 0) { 40 ptr = ifi->ifi_haddr; 41 do { 42 printf("%s%x", (i == ifi->ifi_hlen) ? " " : ":", *ptr++); 43 } while (--i > 0); 44 printf(" "); 45 } 46 if (ifi->ifi_mtu != 0) 47 printf(" MTU: %d ", ifi->ifi_mtu); 48 49 if ( (sa = ifi->ifi_addr) != NULL) 50 printf(" IP addr: %s ", 51 Sock_ntop_host(sa, sizeof(*sa))); 52 if ( (sa = ifi->ifi_brdaddr) != NULL) 53 printf(" broadcast addr: %s ", 54 Sock_ntop_host(sa, sizeof(*sa))); 55 if ( (sa = ifi->ifi_dstaddr) != NULL) 56 printf(" destination addr: %s ", 57 Sock_ntop_host(sa, sizeof(*sa))); 58 } 59 free_ifi_info(ifihead); 60 exit(0); 61 }
get_ifi_info.c
1 /* include get_ifi_info1 */ 2 #include "unpifi.h" 3 4 struct ifi_info * 5 get_ifi_info(int family, int doaliases) 6 { 7 struct ifi_info *ifi, *ifihead, **ifipnext; 8 int sockfd, len, lastlen, flags, myflags, idx = 0, hlen = 0; 9 char *ptr, *buf, lastname[IFNAMSIZ], *cptr, *haddr, *sdlname; 10 struct ifconf ifc; 11 struct ifreq *ifr, ifrcopy; 12 struct sockaddr_in *sinptr; 13 struct sockaddr_in6 *sin6ptr; 14 15 sockfd = Socket(AF_INET, SOCK_DGRAM, 0); 16 17 lastlen = 0; 18 len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ 19 for ( ; ; ) { 20 buf = Malloc(len); 21 ifc.ifc_len = len; 22 ifc.ifc_buf = buf; 23 if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { 24 if (errno != EINVAL || lastlen != 0) 25 err_sys("ioctl error"); 26 } else { 27 if (ifc.ifc_len == lastlen) 28 break; /* success, len has not changed */ 29 lastlen = ifc.ifc_len; 30 } 31 len += 10 * sizeof(struct ifreq); /* increment */ 32 free(buf); 33 } 34 ifihead = NULL; 35 ifipnext = &ifihead; 36 lastname[0] = 0; 37 sdlname = NULL; 38 /* end get_ifi_info1 */ 39 40 /* include get_ifi_info2 */ 41 for (ptr = buf; ptr < buf + ifc.ifc_len; ) { 42 ifr = (struct ifreq *) ptr; 43 44 #ifdef HAVE_SOCKADDR_SA_LEN 45 len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); 46 #else 47 switch (ifr->ifr_addr.sa_family) { 48 #ifdef IPV6 49 case AF_INET6: 50 len = sizeof(struct sockaddr_in6); 51 break; 52 #endif 53 case AF_INET: 54 default: 55 len = sizeof(struct sockaddr); 56 break; 57 } 58 #endif /* HAVE_SOCKADDR_SA_LEN */ 59 ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */ 60 61 #ifdef HAVE_SOCKADDR_DL_STRUCT 62 /* assumes that AF_LINK precedes AF_INET or AF_INET6 */ 63 if (ifr->ifr_addr.sa_family == AF_LINK) { 64 struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; 65 sdlname = ifr->ifr_name; 66 idx = sdl->sdl_index; 67 haddr = sdl->sdl_data + sdl->sdl_nlen; 68 hlen = sdl->sdl_alen; 69 } 70 #endif 71 72 if (ifr->ifr_addr.sa_family != family) 73 continue; /* ignore if not desired address family */ 74 75 myflags = 0; 76 if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) 77 *cptr = 0; /* replace colon with null */ 78 if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { 79 if (doaliases == 0) 80 continue; /* already processed this interface */ 81 myflags = IFI_ALIAS; 82 } 83 memcpy(lastname, ifr->ifr_name, IFNAMSIZ); 84 85 ifrcopy = *ifr; 86 Ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy); 87 flags = ifrcopy.ifr_flags; 88 if ((flags & IFF_UP) == 0) 89 continue; /* ignore if interface not up */ 90 /* end get_ifi_info2 */ 91 92 /* include get_ifi_info3 */ 93 ifi = Calloc(1, sizeof(struct ifi_info)); 94 *ifipnext = ifi; /* prev points to this new one */ 95 ifipnext = &ifi->ifi_next; /* pointer to next one goes here */ 96 97 ifi->ifi_flags = flags; /* IFF_xxx values */ 98 ifi->ifi_myflags = myflags; /* IFI_xxx values */ 99 #if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU) 100 Ioctl(sockfd, SIOCGIFMTU, &ifrcopy); 101 ifi->ifi_mtu = ifrcopy.ifr_mtu; 102 #else 103 ifi->ifi_mtu = 0; 104 #endif 105 memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME); 106 ifi->ifi_name[IFI_NAME-1] = '