在路由器接口中支持三种类型的操作 1). 进程能通过写路由套接口向内核发消息。 2). 进程能在路由套接口上从内核读消息,这是核心通知进程已收到一个ICMP重定向消息并进行了处理的方式。 3). 进程可以用sysctl函数得到路由表或列出所有已配置的接口。
在路由套接口上返回的一些消息中包含数据链路套接口地址结构,他在
struct sockaddr_dl {
uint8_t sdl_len;
sa_family_t sdl_family; /* AF_LINK */
uint16_t sdl_index; /* system assigned index, if > 0 */
uint8_t sdl_type; /* IFT_ETHER, etc. from <net/if_types.h> */
uint8_t sdl_nlen; /* name length, starting in sdl_data[0] */
uint8_t sdl_alen; /* link-layer address length */
uint8_t sdl_slen; /* link-layer selector length */
char sdl_data[12]; /* minimum work area, can be larger;contains if name and link-layer address */
};
每个接口都有一个唯一的大于0的索引号。sdl_data成员包含名字和链路层地址,名字从sdl_data[0]开始,而且不以空字符终止。链路层地址从名字后面的sdl_nlen字节开始。这些套接口地址结构是可变长度的。
我们对于路由套接口的主要兴趣点在于使用sysctl函数检查路由表和接口清单,使用该函数检查路由表清单不需要超级用户权限。
#include <sys/param.h>
#include <sys/sysctl.h>
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
//返回:若成功为0,若出错-1
这个函数使用类似SNMP(简单网络管理协议)MIB(管理信息库)的名字 参数name是指定名字的一个整数数组,namelen是数组中的元素数目。数组的第一个元素指明请求被发往内核的哪个子系统 第二个参数指明这个子系统的某个部分,依次类推。 要取一个值,oldp需指向一个缓冲区,以让内核存放该值。 oldlenp是一个值-结果参数:调用函数时oldlenp指向的值是缓冲区的大小,返回的值是内核在缓冲区中返回的数据量,如果缓冲区不够大,就返回ENOMEM错误。作为一个特例,oldp可以是一个空指针而oldlenp是一个非空指针,内核确定这个调用本应返回的数据量,并通过oldlenp返回这个值。 要设置一个新值,newp需指向一个大小为newlen的缓冲区,如果没有指定新值,newp应为一个空指针,newlen应为0
下面四个函数用于需要描述一个解耦的场合,这里存在一个概念,即每个接口都有一个唯一的名字和一个唯一的正值索引(0从不用做索引)
#include <net/if.h>
unsigned int if_nametoindex(const char * ifname);
// 返回:成功时为正的接口索引,出错时为0
char * if_indextoname(unsigned int ifindex, char * ifname);
// 返回: 成功时为指向接口名的指针,出错时为NULL
struct if_nameindex * if_nameindex(void);
//返回: 成功时为非空指针,出错时为NULL
void if_freenameindex(struct if_nameindex * ptr);
if_nametoindex返回名为ifname的接口的索引,if_indextoname对给定的ifindex返回一个指向其接口名的指针,ifname参数指向一个大小为IFNAMSIZ头文件中定义的缓冲区,调用者必须分配这个缓冲区以保存结果,成功时这个指针也是函数的返回值,if_nameindex返回一个指向if_nameindex结构的数组的指针
struct if_nameindex{
unsigned int if_index; /* 1,2... */
char * if_name; /* null terninated name: "le0", ... */
};
数组的最后一项是一个index为0,if_name为空指针的结构。这个数组和数组中各元素指向的名字所用的内存是动态分配的,调用if_freenameindex可释放这些内存