天天看點

110-擷取接口資訊(二)

1. 擷取接口其它資訊

前面我們已經了解了 ioctl 的使用方法,現在我們希望擷取更多的接口資訊,最後将其封裝成一個獨立函數,名為 getIfiInfo.

我們先來看看這個函數的示範示例,後面再給出詳細過程。getIfiInfo 擷取所有接口的配置資訊,并儲存在數組 ifi 中。該函數傳回值是數組大小,也就是接口的個數。

110-擷取接口資訊(二)

圖1 getIfiInfo 函數使用示例

上面的程式隻是擷取了接口資訊,并将所有接口資訊輸出到了螢幕。經過編譯運作後,結果如圖 2 所示。

110-擷取接口資訊(二)

圖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; // 目标位址      
// 該函數通過參數傳回一個struct ifi_info 類型數組位址,将位址儲存在 ifi 中。
// 傳回值:數組大小
int getIfiInfo(struct      
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. 總結

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