4 5 NET_RT_DUMP 0 NET_RT_FLAGS RTF_LLINFO NET_RT_IFLIST 0 从表3-6可以看出由name[4]指明的三种操作(NET_RT_xxx常值在
1. NET_RT_DUMP返回由name[3]指定的地址族路由表。如果这个地址族是0,则返
回所有地址族的路由表。
路由表作为可变数目的RTM_GET消息返回,每个消息后最多可接四个套接口地址结构:本路由表项的目的地址、网关、网络掩码和复制掩码。
2. NET_RT_FLAGS返回由name[3]指定的地址族的路由表,但只返回那些具有由
name[5]指定的RTF_xxx标志的路由表项。路由表中所有的ARP高速缓存项其RTF_LLINFO标志位都是置位的。信息返回的格式和前一条相同。
3. NET_RT_IFLIST返回所有已配置接口的信息。如果name[5]不为0,那它就是一个
接口的索引号,于是只返回这个接口的信息。每个接口被赋予的所有地址也都返回,但如果name[3]不为0,则只返回指定地址族的地址。 给每个接口返回一个RTM_IFINFO消息,后面接着的是赋给该接口的每个地址对应的各个RTM_NEWADDR消息。RTM_IFINFO消息后接的是一个数据链路套接口地址结构,RTM_NEWADDR消息后接最多三个套接口地址结构:接口地址、网络掩码和广播地址。图3-15说明了这两种消息。
内核返回的缓冲区
if_msghdr {}
ifm_type=RTM_IFINFO 每个接口一个RTM_IFINFO:
接口名、索引和硬件地址
数据链路套接口
地址结构
ifa_msgaddr{} ifam_type=RTM_NEWADDR
网络掩码套接口
地址结构 本接口每个已配置的地址一 单播地址套接口 个RTM_NEWADDR 地址结构
广播地址套接口
地址结构
图3-15 sysctl的CTL_NET,NET_RT_IFLIST命令返回的信息 由于源自4.4BSD的内核加入了对IPv6的支持,因此应加入对name[1]成员为AF_INET6
的支持(以设置和获取IPv6特定变量),以及对表3-6中的name[3]为AF_INET6的支持(以列出IPv6路由表或IPv6邻居高速缓存,或者返回IPv6接口地址)。 下面是一个判断UDP校验和是否打开的程序例子。这个例子使用网际协议检查UDP校验和是否打开。一些UDP应用程序(例如bind)在启动时检查UDP校验和是否打开。如果没有打开,则试图打开它。当然这需要超级用户权限打开这样的特性。下面是这个程序的代码。 #include \
#include
int
main(int argc, char **argv) {
}
exit(0);
len = sizeof(val);
Sysctl(mib, 4, &val, &len, NULL, 0); printf(\
mib[0] = CTL_NET; mib[1] = AF_INET; mib[2] = IPPROTO_UDP; mib[3] = UDPCTL_CHECKSUM;
int
mib[5], val;
size_t len;
/* for UDPCTL_xxx constants */
该程序必须包含
sysctl函数是获取和设置操作系统参数的常规方法,包括输出接口列表、输出路由表、输出ARP高速缓存等。
3.7.4 接口名和索引函数 RFC2133定义了四个处理接口名和索引的函数。这四个函数用于IPv6多播通信。基本概念是每个接口有一个唯一的名字和一个唯一的大于0的索引(0不用做索引)。这四个函数的具体使用方法如下: #include
struct if_nameindex *if_nameindex(void); void if_freenameindex(struct if_nameindex *ptr); if_nametoindex函数成功时返回名为ifname的接口的索引,出错时返回为0。if_indextoname对给定的ifindex返回一个指向其接口名的指针,出错时返回NULL。Ifname参数指向一个大小为IFNAMSIZ(在
/* Our own header for the programs that need interface configuration info. Include this file, instead of \
#ifndef __unp_ifi_h #define __unp_ifi_h
#include \#include
#define IFI_NAME 16 /* same as IFNAMSIZ in
struct ifi_info {
char ifi_name[IFI_NAME]; /* interface name, null terminated */ u_char ifi_haddr[IFI_HADDR]; /* hardware address */ u_short ifi_hlen; /* #bytes in hardware address: 0, 6, 8 */ short ifi_flags; /* IFF_xxx constants from
struct sockaddr *ifi_dstaddr;/* destination address */ struct ifi_info *ifi_next; /* next of these structures */ };
#define IFI_ALIAS 1 /* ifi_addr is an alias */ /* function prototypes */
struct ifi_info *get_ifi_info(int, int); struct ifi_info *Get_ifi_info(int, int); void free_ifi_info(struct ifi_info *); #endif /* __unp_ifi_h */
unproute.h代码如下:
#include \#include
#ifdef HAVE_SYS_SYSCTL_H #include
void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); char *net_rt_iflist(int, int, size_t *); char *net_rt_dump(int, int, size_t *);
char *sock_masktop(struct sockaddr *, socklen_t); /* wrapper functions */
char *Net_rt_iflist(int, int, size_t *); char *Net_rt_dump(int, int, size_t *); #define Sock_masktop(a,b) sock_masktop((a), (b))
1. if_nametoindex函数
下面给出了if_nametoindex函数的实现代码。
/* include if_nametoindex */ #include \#include \
unsigned int
if_nametoindex(const char *name) {
lim = buf + len;
if ( (buf = net_rt_iflist(0, 0, &len)) == NULL)
return(0); unsigned int char
size_t
index;
*buf, *next, *lim;
len;
*sa, *rti_info[RTAX_MAX]; *sdl;
struct if_msghdr *ifm; struct sockaddr struct sockaddr_dl
}
for (next = buf; next < lim; next += ifm->ifm_msglen) { }
free(buf); return(0);
/* no match for name */
ifm = (struct if_msghdr *) next; if (ifm->ifm_type == RTM_IFINFO) { }
sa = (struct sockaddr *) (ifm + 1); get_rtaddrs(ifm->ifm_addrs, sa, rti_info); if ( (sa = rti_info[RTAX_IFP]) != NULL) { }
if (sa->sa_family == AF_LINK) { }
sdl = (struct sockaddr_dl *) sa;
if (strncmp(&sdl->sdl_data[0], name, sdl->sdl_nlen) == 0) { }
index = sdl->sdl_index; /* save before free() */ free(buf); return(index);
/* end if_nametoindex */ unsigned int
If_nametoindex(const char *name) {
}
int
index;
if ( (index = if_nametoindex(name)) == 0)
err_quit(\return(index);
net_rt_iflist函数返回接口列表。该函数的主要功能是处理缓冲区中的消息(图3-15),只查找RTM_IFINFO消息。当找到一个时,调用get_rtaddrs函数设置指向各套接口地址结构的指针;如果存在一个接口名结构(rti_info数组的RTAX_IFP元素),就把该接口名和调用者使用的参数做一下比较。
2. if_indextoname函数
下面给出了if_indextoname函数的实现代码。
/* include if_indextoname */ #include \#include \
char *
if_indextoname(unsigned int index, char *name) {