#include <unistd.h>
int ioctl(int fd, int request, /* void *arg */)
返回值:成功0,失败-1
我们可以把和网络相关的请求划分为6类:
- 套接口操作
- 文件操作
- 接口操作
- ARP高速缓存操作
- 路由表操作
- 流系统
类别 | Request | 说明 | 数据类型 |
---|---|---|---|
套接字 | SIOCATMARK | 是否位于带外标记 | int |
SIOCSPGRP | 设置套接口的进程ID或进程组ID | int | |
SIOCGPGRP | 获取套接口的进程ID或进程组ID | int | |
文件 | FIONBIN | 设置/清除非阻塞I/O标志 | int |
FIOASYNC | 设置/清除信号驱动异步I/O标志 | int | |
FIONREAD | 获取接收缓存区中的字节数 | int | |
FIOSETOWN | 设置文件的进程ID或进程组ID | int | |
FIOGETOWN | 获取文件的进程ID或进程组ID | int | |
接口 | SIOCGIFCONF | 获取所有接口的清单 | struct ifconf |
SIOCSIFADDR | 设置接口地址 | struct ifreq | |
SIOCGIFADDR | 获取接口地址 | struct ifreq | |
SIOCSIFFLAGS | 设置接口标志 | struct ifreq | |
SIOCGIFFLAGS | 获取接口标志 | struct ifreq | |
SIOCSIFDSTADDR | 设置点到点地址 | struct ifreq | |
SIOCGIFDSTADDR | 获取点到点地址 | struct ifreq | |
SIOCGIFBRDADDR | 获取广播地址 | struct ifreq | |
SIOCSIFBRDADDR | 设置广播地址 | struct ifreq | |
SIOCGIFNETMASK | 获取子网掩码 | struct ifreq | |
SIOCSIFNETMASK | 设置子网掩码 | struct ifreq | |
SIOCGIFMETRIC | 获取接口的测度 | struct ifreq | |
SIOCSIFMETRIC | 设置接口的测度 | struct ifreq | |
SIOCGIFMTU | 获取接口MTU | struct ifreq | |
SIOCxxx | (还有很多取决于系统的实现) | struct ifreq | |
ARP | SIOCSARP | 创建/修改ARP表项 | struct arpreq |
SIOCGARP | 获取ARP表项 | struct arpreq | |
SIOCDARP | 删除ARP表项 | struct arpreq | |
路由 | SIOCADDRT | 增加路径 | struct rtentry |
SIOCDELRT | 删除路径 | struct rtentry | |
流 | I_xxx |
套接字操作
明确用于套接口操作的ioctl请求有三个,它们都要求ioctl的第三个参数是指向某个整数的一个指针。
- | - |
---|---|
SIOCATMARK: | POSIX以函数sockatmark替换本请求。 |
SIOCGPGRP: | 通过第三个参数指向的整数返回本套接口的进程ID或进程组ID,该ID指定针对本套接口的SIGIO或SIGURG信号的接收进程。本请求和fcntl的F_GETOWN命令等效,POSIX标准化的是fcntl函数。 |
SIOCSPGRP: | 把本套接口的进程ID或者进程组ID设置成第三个参数指向的整数,该ID指定针对本套接口的SIGIO或SIGURG信号的接收进程,本请求和fcntl的F_SETOWN命令等效,POSIX标准化的是fcntl操作 |
文件操作
- | - |
---|---|
FIONBIO: | 根据ioctl的第三个参数指向一个0或非0值分别清除或设置本套接口的非阻塞标志。本请求和O_NONBLOCK文件状态标志等效,而该标志通过fcntl的F_SETFL命令清除或设置。 |
FIOASYNC: | 根据iocl的第三个参数指向一个0值或非0值分别清除或设置针对本套接口的信号驱动异步I/O标志,它决定是否收取针对本套接口的异步I/O信号(SIGIO)。本请求和O_ASYNC文件状态标志等效,而该标志可以通过fcntl的F_SETFL命令清除或设置。 |
FIONREAD: | 通过由ioctl的第三个参数指向的整数返回当前在本套接口接收缓冲区中的字节数。本特性同样适用于文件,管道和终端。 |
FIOSETOWN: | 对于套接口和SIOCSPGRP等效 |
FIOGETOWN: | 对于套接口和SIOCGPGRP等效 |
接口配置:
得到系统中所有接口由SIOCGIFCONF请求完成,该请求使用ifconf结构,ifconf又使用ifreq结构,如下所示:
Struct ifconf{
int ifc_len; // 缓冲区的大小
union{
caddr_t ifcu_buf; // input from user->kernel
struct ifreq *ifcu_req; // return of structures returned
}ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf //buffer address
#define ifc_req ifc_ifcu.ifcu_req //array of structures returned
#define IFNAMSIZ 16
struct ifreq{
char ifr_name[IFNAMSIZ]; // interface name, e.g., “le0”
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 // address
#define ifr_dstaddr ifr_ifru.ifru_dstaddr // otner end of p-to-p link
#define ifr_broadaddr ifr_ifru.ifru_broadaddr // broadcast address
#define ifr_flags ifr_ifru.ifru_flags // flags
#define ifr_metric ifr_ifru.ifru_metric // metric
#define ifr_data ifr_ifru.ifru_data // for use by interface
再调用ioctl前我们必须先分撇一个缓冲区和一个ifconf结构,然后才初始化后者。如下图
展示了一个ifconf结构的初始化结构,其中缓冲区ifc_buf的大小ifc_len为1024,ioctl的第三个参数指向这样一个ifconf结构。假设内核返回2个ifreq结构,ioctl返回时通过同一个ifconf结构缓冲区填入了那2个ifreq结构,ifconf结构的ifc_len成员也被更新,以反映存放在缓冲区中的信息量
接口操作
SIOCGIFCONF请求为每个已配置的接口返回其名字以及一个套接口地址结构。我们接着可以发出多个接口类其他请求以设置或获取每个接口的其他特征。这些请求的获取(get)版本(SIOCGxxx)通常由netstat程序发出,设置(set)版本(SIGOCSxxx)通常由ifconfig程序发出。任何用户都可以获取接口信息,设置接口信息却要求有超级用户权限。
这些请求汲取或返回一个一个ifreq结构中的信息,而这个结构的地址则作为ioctl调用的第三个参数制定。接口总是以其名标志,在ifreq结构的ifr_name成员中指定,如le0,lo0,ppp0等。
这些请求中有许多使用套接口地址结构在应用进程和内核之间指定或返回具体接口的IP地址或地址掩码。对于IPV4,这个地址或掩码放在一个网际套接口地址结构的sin_addr成员中;对于IPV6,它是一个IPV6套接口地址结构的sin6_addr成员。
- | - |
---|---|
SIOCGIFADDR: | 在ifr_addr成员中返回单播地址。 |
SIOCSIFADDR: | 用ifr_addr成员设置接口地址,这个接口的初始化函数也被调用。 |
SIOCGIFFLAGS: | 在ifr_flags成员中返回接口标志。这些接口标志的名字格式为IFF_XXX,在<net/if.h>头文件中定义。举例来说,这些标志指示接口是否处于UP即在工状态(IFF_UP),是否为一个点到点接口(IFF_POINTOPOINT),是否支持广播(IFF_BROADCAST),等等。 |
SIOCSIFFLAGS: | 用ifr_flags成员设置接口标志。 |
SIOCGIFDSTADDR: | 在ifr_dstaddr成员中返回点到点地址。 |
SIOCSIFDSTADDR: | 在ifr_dstaddr成员中设置点到点地址 |
SIOCGIFBRDADDR: | 在ifr_broadaddr成员中返回广播地址。应用进程必须首先获取接口标志,然后发出正确的请求;对于广播接口为SIOCGIFBRDADDR,对于点到点接口为SIOCGIFDSTADDR |
SIOCSIFBRDADDR: | 用ifr_broadaddr成员设置广播地址。 |
SIOCGIFNETMASK: | 在ifr_addr成员中返回子网掩码。 |
SIOCSIFNETMASK: | 在ifr_addr成员中设置子网掩码。 |
SIOCGIFMETRIC: | 用ifr_metric成员返回接口测度。接口测度由内核为每个接口维护,不过使用他的是路由守护进程routed。接口测度被routed加到跳数上。 |
SIOCSIFMETRIC: | 用ifr_metric成员设置接口的路由测度。 |
例子
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
void err_sys(const char *errmsg);
int main(void)
{
int i, sockfd;
struct ifreq ifr;
struct arpreq arpr;
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
err_sys("socket");
/* get ip address */
if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1)
err_sys("1-ioctl");
/* get hardware address */
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == -1)
err_sys("2-ioctl");
/* output hardware address */
for (i = 0; i < 6; i++) {
unsigned char *mac = (unsigned char *) ifr.ifr_hwaddr.sa_data;
printf("%x", (int) mac[i]);
if (i != 5)
printf("%c", ':');
}
exit(0);
}
void err_sys(const char *errmsg)
{
perror(errmsg);
exit(1);
}
转载自:https://www.cnblogs.com/kunhu/p/3606427.html