1. 获取接口其它信息

前面我们已经了解了 ioctl 的使用方法,现在我们希望获取更多的接口信息,最后将其封装成一个独立函数,名为 getIfiInfo.

我们先来看看这个函数的演示示例,后面再给出详细过程。getIfiInfo 获取所有接口的配置信息,并保存在数组 ifi 中。该函数返回值是数组大小,也就是接口的个数。


110-获取接口信息(二)_数组


图1 getIfiInfo 函数使用示例


上面的程序只是获取了接口信息,并将所有接口信息输出到了屏幕。经过编译运行后,结果如图 2 所示。


110-获取接口信息(二)_接口_02


图2 getIfiInfo 获取到的接口信息


我们的目的就是写出 getIfiInfo 这个函数。

所有代码托管在​​
本文程序路径:​​​unp/program/interface/getifinfo​

2. ioctl 接口相关的其他命令

从图 2 中我们看到打印的信息有:

  • 接口功能,即标志位
  • 接口索引号
  • MTU
  • MAC 地址
  • 配置的 IP 地址
  • 子网掩码
  • 广播地址

每一个信息都需要通过 ioctl 函数来获取,有点麻烦,这也是封装 getIfiInfo 的初衷。

下表列举了操作接口的常用的 ioctl 命令:

命令

说明

数据类型

SIOCGIFCONF, SIOCSIFCONF

获取,设置所有接口列表

struct ifconf

SIOCGIFADDR, SIOCSIFADDR

获取,设置接口地址

struct ifreq

SIOCGIFINDEX

获取接口索引号

struct ifreq

SIOCGIFFLAGS, SIOCSIFFLAGS

获取,设置接口标志

struct ifreq

SIOCGIFMTU, SIOCSIFMTU

获取,设置接口 MTU

struct ifreq

SIOCGIFDSTADDR, SIOCSIFDSTADDR

获取,设置P2P地址

struct ifreq

SIOCGIFBRDADDR, SIOCSIFBRDADDR

获取,设置广播地址

struct ifreq

SIOCGIFNETMASK, SIOCSIFNETMASK

获取,设置子网掩码

struct ifreq

SIOCGIFMETRIC, SIOCSIFMETRIC

获取,设置接口管理距离

struct ifreq

SIOCGIFHWADDR, SIOCSIFHWADDR

获取,设置接口 MAC 地址

struct ifreq

3. 封装 getIfiInfo 函数

首先需要定义一个新的结构体,如下:

struct ifi_info {              
char ifi_name[IFI_NAMESIZE]; // 接口名称 16 字节
short ifi_index; // 接口索引
short ifi_mtu; // 接口 MTU
unsigned char ifi_haddr[IFI_HADDRSIZE]; // 物理地址 8 字节
unsigned short ifi_hlen; // 物理地址长度
short ifi_flags;
struct sockaddr *ifi_addr; // 主地址
struct sockaddr *ifi_netmask; // 子网掩码
struct sockaddr *ifi_brdaddr; // 广播地址
struct sockaddr *ifi_dstaddr; // 目标地址

接下来,定义 getIfiInfo 函数:

// 该函数通过参数返回一个struct ifi_info 类型数组地址,将地址保存在 ifi 中。
// 返回值:数组大小
int getIfiInfo(struct

我不打算把 getIfiInfo 函数的完整代码贴在这里,想要看完整代码,可以在 ​​unp/program/util/common.cc​​ 这个文件中找到它。这里我以获取接口 mac 地址为例:

int getIfiInfo(struct ifi_info **ifi) {
struct ifi_info *_ifi = malloc(/*...*/);
// ...

struct ifreq ifrcopy;
// 给 ifrcopy 填充接口名称。

// 获取 mac 地址
ret = ioctl(sockfd, SIOCGIFHWADDR, &ifrcopy);
if (ret < 0) ERR_EXIT("ioctl");

// 将 mac 地址保存到申请的内存中去
memcpy(_ifi[k].ifi_haddr, ((struct sockaddr*)&ifrcopy.ifr_hwaddr)->sa_data, 6);
_ifi[k].ifi_hlen = 6;

// ...

*ifi = _ifi;

return

4. 总结

  • 掌握获取接口配置的方法