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成员设置接口的路由测度。
ARP高速缓存操作
ARP告诉缓存也通过ioctl函数操纵。使用路由域套接口的系统往往改用路由套接口访问
ARP高速缓存。这些请求使用如下的arpreq结构,定义在<net/if_arp.h>
struct arpreq {
struct sockaddr arp_pa;
struct sockaddr arp_ha;
int arp_flags;
};
#define ATF_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 (respond for other host )
Ioctl的第三个必须指向某个arpreq结构,操纵ARP高速缓存的ioctl请求有以下三个:
SIOCSARP: 把一个新的表项加入ARP告诉缓存中区,或者修改其中已经存在的一个表项,其中arp_pa是一个含有IP地址的网际套接口地址结构,arp_ha则是一个通用套接口地址结构,他的sa_family值为AF_unspec,sa_data中含有硬件地址(例如6直接的以太网地址)。ATF_PERM和ATF_PUBL这两个标志也可以由应用进程指定。另外两个标志(ATF_INUSE和ATF_COM)则由内核设置。
SIOCDARP: 从ARP告诉缓存中删除一个表项。调用者指定要删除表项的网际地址。
SIOCGARP: 从ARP高速缓存中获取一个表项。调用者指定网际地址,相应的硬件地址(例外以太网地址)随标志一起返回。
只有超级用户才能增加或删除表项。这三个请求通常由arp程序发出。
注意ioctl没有办法列出ARP高速缓存中的所有表项。当指定-a标志执行arp命令时,大多
数版本的arp程序通过读取内核的内存( /dev/kmem )获得ARP高速缓存的当前内容。
路由表操作
有些系统提供2个用于操纵路由表的ioctl请求。这2个请求要求ioctl的第三个参数是指向
某个rtentry结构的一个指针,该结构定义在<net/route.h>头文件中。这些请求通常由route
程序发出。只有超级用户才能发出这些请求。
SIOCADDRT:往路由表中增加一个表项
SIOCDELRT:从路由表中删除一个表项
Ioctl没有办法列出路由表中的所有表项。这个操作通常由netstat程序在指定-r标志自行四
完成。netstat程序通过读取内核的内存 (/dev/kmem)获得整个路由表。用sysctl同样可
以做到。
#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);
}