1. 擷取接口其它資訊
前面我們已經了解了 ioctl 的使用方法,現在我們希望擷取更多的接口資訊,最後将其封裝成一個獨立函數,名為 getIfiInfo.
我們先來看看這個函數的示範示例,後面再給出詳細過程。getIfiInfo 擷取所有接口的配置資訊,并儲存在數組 ifi 中。該函數傳回值是數組大小,也就是接口的個數。
圖1 getIfiInfo 函數使用示例
上面的程式隻是擷取了接口資訊,并将所有接口資訊輸出到了螢幕。經過編譯運作後,結果如圖 2 所示。
圖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. 總結
- 掌握擷取接口配置的方法