UNP学习笔记(第十七章 ioctl操作)

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 */
View Code

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(">\n");
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("\n");
45         }
46         if (ifi->ifi_mtu != 0)
47             printf("  MTU: %d\n", ifi->ifi_mtu);
48 
49         if ( (sa = ifi->ifi_addr) != NULL)
50             printf("  IP addr: %s\n",
51                         Sock_ntop_host(sa, sizeof(*sa)));
52         if ( (sa = ifi->ifi_brdaddr) != NULL)
53             printf("  broadcast addr: %s\n",
54                         Sock_ntop_host(sa, sizeof(*sa)));
55         if ( (sa = ifi->ifi_dstaddr) != NULL)
56             printf("  destination addr: %s\n",
57                         Sock_ntop_host(sa, sizeof(*sa)));
58     }
59     free_ifi_info(ifihead);
60     exit(0);
61 }
View Code

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] = '\0';
107         /* If the sockaddr_dl is from a different interface, ignore it */
108         if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0)
109             idx = hlen = 0;
110         ifi->ifi_index = idx;
111         ifi->ifi_hlen = hlen;
112         if (ifi->ifi_hlen > IFI_HADDR)
113             ifi->ifi_hlen = IFI_HADDR;
114         if (hlen)
115             memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen);
116 /* end get_ifi_info3 */
117 /* include get_ifi_info4 */
118         switch (ifr->ifr_addr.sa_family) {
119         case AF_INET:
120             sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
121             ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in));
122             memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
123 
124 #ifdef    SIOCGIFBRDADDR
125             if (flags & IFF_BROADCAST) {
126                 Ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
127                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
128                 ifi->ifi_brdaddr = Calloc(1, sizeof(struct sockaddr_in));
129                 memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
130             }
131 #endif
132 
133 #ifdef    SIOCGIFDSTADDR
134             if (flags & IFF_POINTOPOINT) {
135                 Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
136                 sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
137                 ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in));
138                 memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
139             }
140 #endif
141             break;
142 
143         case AF_INET6:
144             sin6ptr = (struct sockaddr_in6 *) &ifr->ifr_addr;
145             ifi->ifi_addr = Calloc(1, sizeof(struct sockaddr_in6));
146             memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6));
147 
148 #ifdef    SIOCGIFDSTADDR
149             if (flags & IFF_POINTOPOINT) {
150                 Ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
151                 sin6ptr = (struct sockaddr_in6 *) &ifrcopy.ifr_dstaddr;
152                 ifi->ifi_dstaddr = Calloc(1, sizeof(struct sockaddr_in6));
153                 memcpy(ifi->ifi_dstaddr, sin6ptr, sizeof(struct sockaddr_in6));
154             }
155 #endif
156             break;
157 
158         default:
159             break;
160         }
161     }
162     free(buf);
163     return(ifihead);    /* pointer to first structure in linked list */
164 }
165 /* end get_ifi_info4 */
166 
167 /* include free_ifi_info */
168 void
169 free_ifi_info(struct ifi_info *ifihead)
170 {
171     struct ifi_info    *ifi, *ifinext;
172 
173     for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
174         if (ifi->ifi_addr != NULL)
175             free(ifi->ifi_addr);
176         if (ifi->ifi_brdaddr != NULL)
177             free(ifi->ifi_brdaddr);
178         if (ifi->ifi_dstaddr != NULL)
179             free(ifi->ifi_dstaddr);
180         ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
181         free(ifi);                    /* the ifi_info{} itself */
182     }
183 }
184 /* end free_ifi_info */
185 
186 struct ifi_info *
187 Get_ifi_info(int family, int doaliases)
188 {
189     struct ifi_info    *ifi;
190 
191     if ( (ifi = get_ifi_info(family, doaliases)) == NULL)
192         err_quit("get_ifi_info error");
193     return(ifi);
194 }
View Code

运行情况

 

 

 

接口操作

SIOCGIFCONF请求为每个已配置的接口返回其明知以及一个套接字地址结构。我们接着可以发出多个接口类的其他请求以设置或获取每个接口的其他特性

这些请求的get版本(SIOCGxxx)通常由netstat程序发出,set版本(SIOCSxxx)通常由ifconfig程序发出

这些请求接受或返回一个ifreq结构中的信息,而这个结构的地址作为ioctl调用的第三个参数。

SIGCGIFADDR   在ifr_addr成员中返回单播地址

SIOCSIFADDR    用ifr_addr成员设置接口地址

SIOCGIFFLAGS   在ifr_flags成员中返回接口标志,如:是否处于在工状态(IFF_UP)

SIOCSIFFLAGS    用ifr_flags成员设置接口标志

SIOCGIFDSTADDR  在if_dstaddr成员中返回点到点地址

SIGCSIFDSTADDR  用if_dstaddr成员设置点到点地址

SIOCGIFBRDADDR  在ifr_broadaddr成员中返回广播地址

SIOCSIFBRDADDR   用ifr_broadaddr成员设置广播地址

SIOCGIFNETMASK    在ifr_addr成员中返回子网掩码

SIOCSIFNETMASK    用ifr_addr成员设置子网掩码

SIOCGIFMETRIC   在ifr_metric成员返回接口测度

SIGCSIFMETRIC   用ifr_metric成员设置接口测度

 

 

ARP高速缓存操作

这些请求使用如下所示的arpreq结构

struct arpreq{
  struct sockaddr arp_pa; //协议地址
  struct sockaddr arp_ha; //硬件地址
  int arp_flags;//标志位
}

#define ATR_INUSE  0x01   /* entry in use */
#define ATF_COM    0x02   /* completed entry (hardware addr valid) */
#define ATF_PERM   0x04 /* permanent entry */
#define ATF_PUBL   0x08 /* published entry (repond for other host) */

操纵ARP高速缓存的ioctl请求有以下3个

SIOCSARP    把一个新的表项加到ARP高速缓存,或者修改其中一个已经存在的表项

SIOCDARP    从ARP高速缓存中删除一个表项。调用者指定要删除的arp_pa

SIOCGARP    从ARP高速缓存中获取一个表项。调用者指定arp_pa,相应的硬件地址随标志一起返回

下面程序用于输出主机的硬件地址

 1 #include    "unpifi.h"
 2 #include    <net/if_arp.h>
 3 
 4 int
 5 main(int argc, char **argv)
 6 {
 7     int                    sockfd;
 8     struct ifi_info            *ifi;
 9     unsigned char        *ptr;
10     struct arpreq        arpreq;
11     struct sockaddr_in    *sin;
12 
13     sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
14     for (ifi = get_ifi_info(AF_INET, 0); ifi != NULL; ifi = ifi->ifi_next) {
15         printf("%s: ", Sock_ntop(ifi->ifi_addr, sizeof(struct sockaddr_in)));
16 
17         sin = (struct sockaddr_in *) &arpreq.arp_pa;
18         memcpy(sin, ifi->ifi_addr, sizeof(struct sockaddr_in));
19 
20         if (ioctl(sockfd, SIOCGARP, &arpreq) < 0) {
21             err_ret("ioctl SIOCGARP");
22             continue;
23         }
24 
25         ptr = &arpreq.arp_ha.sa_data[0];
26         printf("%x:%x:%x:%x:%x:%x\n", *ptr, *(ptr+1),
27                *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
28     }
29     exit(0);
30 }
View Code

先调用get_ifi_info获取本机所有的IP地址,然后在一个循环中遍历每个地址

使用inet_ntop显示IP地址

使用ioctl调用返回硬件地址(SIOCGARP)

 

 

 

路由表操作

有些系统提供两个用于操纵路由表的ioctl请求,在支持路由域套接字的系统中,这些请求改由路由套接字完成

SIOCADDRT   往路由表中增加一个表项

SIOCDELRT    从路由表中删除一个表项

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值