1. sysctl Operations
#include
#include
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen);
Returns: 0 if OK, −1 on error
对于最基本的API操作,并不需要额外关注,注意name
参数可能的选项搭配方式:
UNP着重介绍了NET_RT_IFLIST
,这里也看看该选项的解释:
- returns information on all configured interfaces. If name[5] is nonzero, it is an interface index number, and only information on that interface is returned.
- All the addresses assigned to each interface are also returned, and if name[3] is nonzero, only addresses for that address family are returned.
- For each interface, one RTM_IFINFO message is returned, followed by one RTM_NEWADDR message for each address assigned to the interface. The RTM_IFINFO message is followed by one datalink socket address structure, and each RTM_NEWADDR message is followed by up to three socket address structures: the interface address, the network mask, and the broadcast address.
上面的话总结一下就是如果sysctl
都采用默认的选项,那么返回每个接口上每个地址的相关信息:网络地址,子网掩码,广播地址;因为可能某些接口绑定的不只一个地址,这种现象叫地址别名。如下图所示一种返回的数据结构情况:
2. 相对应的API修改
char * net_rt_iflist(int family, int flags, size_t *lenp)
{
int mib[6];
char *buf;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = family;
mib[4] = NET_RT_IFLIST;
mib[5] = flags;
if (sysctl(mib, 6, NULL, lenp, NULL, 0) <0)
return (NULL);
if ( (buf = malloc(*lenp)) == NULL)
return (NULL);
if (sysctl(mib, 6, buf, lenp, NULL, 0) <0) {
free(buf);
return (NULL);
}
return (buf);
}
struct ifi_info * get_ifi_info(int family, int doaliases)
{
int flags;
char *buf, *next, *lim;
size_t len;
struct if_msghdr *ifm;
struct ifa_msghdr *ifam;
struct sockaddr *sa, *rti_info[RTAX_MAX];
struct sockaddr_dl *sdl;
struct ifi_info *ifi, *ifisave, *ifihead, **ifipnext;
buf = Net_rt_iflist(family, 0, &len);
ifihead = NULL;
ifipnext = &ifihead;
lim = buf + len;
for (next = buf; next ifm_msglen) {
ifm = (struct if_msghdr *) next;
if (ifm->ifm_type == RTM_IFINFO) {
if (((flags = ifm->ifm_flags) & IFF_UP) == 0)
continue;
sa = (struct sockaddr *) (ifm + 1);
get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
if ( (sa = rti_info[RTAX_IFP]) != NULL) {
ifi = Calloc(1, sizeof(struct ifi_info));
*ifipnext = ifi;
ifipnext = &ifi->ifi_next;
ifi->ifi_flags = flags;
if (sa->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *) sa;
ifi->ifi_index = sdl->sdl_index;
if (sdl->sdl_nlen > 0)
snprintf(ifi->ifi_name, IFI_NAME, "%*s",sdl->sdl_nlen, &sdl->sdl_data[0]);
else
snprintf(ifi->ifi_name, IFI_NAME, "index %d",sdl->sdl_index);
if ( (ifi->ifi_hlen = sdl->sdl_alen) > 0)
memcpy(ifi->ifi_haddr, LLADDR(sdl), min(IFI_HADDR, sdl->sdl_alen));
}
}
} else if (ifm->ifm_type == RTM_NEWADDR) {
if (ifi->ifi_addr) {
if (doaliases == 0)
continue;
ifisave = ifi;
ifi = Calloc(1, sizeof(struct ifi_info));
*ifipnext = ifi;
ifipnext = &ifi->ifi_next;
ifi->ifi_flags = ifisave->ifi_flags;
ifi->ifi_index = ifisave->ifi_index;
ifi->ifi_hlen = ifisave->ifi_hlen;
memcpy(ifi->ifi_name, ifisave->ifi_name, IFI_NAME);
memcpy(ifi->ifi_haddr, ifisave->ifi_haddr, IFI_HADDR);
}
ifam = (struct ifa_msghdr *) next;
sa = (struct sockaddr *) (ifam + 1);
get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
if ( (sa = rti_info[RTAX_IFA]) != NULL) {
ifi->ifi_addr = Calloc(1, sa->sa_len);
memcpy(ifi->ifi_addr, sa, sa->sa_len);
}
if ((flags & IFF_BROADCAST) && (sa = rti_info[RTAX_BRD]) != NULL) {
ifi->ifi_brdaddr = Calloc(1, sa->sa_len);
memcpy(ifi->ifi_brdaddr, sa, sa->sa_len);
}
if ((flags & IFF_POINTOPOINT) &&(sa = rti_info[RTAX_BRD]) != NULL) {
ifi->ifi_dstaddr = Calloc(1, sa->sa_len);
memcpy(ifi->ifi_dstaddr, sa, sa->sa_len);
}
} else
err_quit("unexpected message type %d", ifm->ifm_type);
}
return (ifihead);
}
特别强调上面程序一点:只有不同的接口或者该接口有多个地址才会调用修改链表的语句,来使当前ifi
结构体添加到链表尾端。
3. Interface Name and Index Functions
#include
unsigned int if_nametoindex(const char *ifname);
Returns: positive interface index if OK, 0 on error
char *if_indextoname(unsigned int ifindex, char *ifname);
Returns: pointer to interface name if OK, NULL on error
struct if_nameindex *if_nameindex(void);
Returns: non-null pointer if OK, NULL on error
void if_freenameindex(struct if_nameindex *ptr);
struct if_nameindex {
unsigned int if_index;
char *if_name;
};
从函数名字也能看出来该组API的用法,特别强调参数的用法:
- The ifname argument points to a buffer of size IFNAMSIZ that the caller must allocate to hold the result, and this pointer is also the return value upon success.
- if_nameindex returns a pointer to an array of if_nameindex structures. The final entry in this array contains a structure with an if_index of 0 and an if_name that is a null pointer. The memory for this array, along with the names pointed to by the array members, is dynamically obtained and is returned by calling if_freenameindex.
4. 最后
该部分内容包括网络编程之ioctl Operations,并不是重点,但是也应该稍微了解下。系统提供了这样的接口及route
或者arp
等程序的作用机理。