1. 程式人生 > >Linux下利用ioctl函式獲取網絡卡資訊

Linux下利用ioctl函式獲取網絡卡資訊

linux下的ioctl函式原型如下:

#include <sys/ioctl.h>

int ioctl(int handle, int cmd, [int *argc, int argv])

函式成功返回0,失敗返回-1.

其相關命令介面如下:

類別 Request 說明 資料型別
SIOCATMARK SIOCSPGRP SIOCGPGRP 是否位於帶外標記 設定套介面的程序ID 或程序組ID 獲取套介面的程序ID 或程序組ID int int int
FIONBIO FIOASYNC FIONREAD FIOSETOWN
FIOGETOWN
設定/ 清除非阻塞I/O 標誌 設定/ 清除訊號驅動非同步I/O 標誌 獲取接收快取區中的位元組數 設定檔案的程序ID 或程序組ID 獲取檔案的程序ID 或程序組ID int int int int int
SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFFLAGS SIOCGIFFLAGS SIOCSIFDSTADDR SIOCGIFDSTADDR SIOCGIFBRDADDR SIOCSIFBRDADDR SIOCGIFNETMASK SIOCSIFNETMASK SIOCGIFMETRIC SIOCSIFMETRIC
SIOCGIFMTU SIOCxxx
獲取所有介面的清單 設定介面地址 獲取介面地址 設定介面標誌 獲取介面標誌 設定點到點地址 獲取點到點地址 獲取廣播地址 設定廣播地址 獲取子網掩碼 設定子網掩碼 獲取介面的測度 設定介面的測度 獲取介面MTU (還有很多取決於系統的實現) struct ifconf struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq
struct ifreq struct ifreq
ARP SIOCSARP SIOCGARP SIOCDARP 建立/ 修改ARP 表項 獲取ARP 表項 刪除ARP 表項 struct arpreq struct arpreq struct arpreq
SIOCADDRT SIOCDELRT 增加路徑 刪除路徑 struct rtentry struct rtentry

在這裡我們需要用到的結構體

#include<netinet/in.h>

struct sockaddr_in { short sin_family; /* Address family */ unsigned short sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ unsigned char sin_zero[8]; /* Same size as struct sockaddr */ };

#include <net/if.h>

struct ifreq
{
#define IFHWADDRLEN 6
union
{
charifrn_name[IFNAMSIZ]; 
} ifr_ifrn;

union {
structsockaddr ifru_addr;
structsockaddr ifru_dstaddr;
structsockaddr ifru_broadaddr;
structsockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
shortifru_flags;
intifru_ivalue;
intifru_mtu;
struct ifmap ifru_map;
charifru_slave[IFNAMSIZ]; charifru_newname[IFNAMSIZ];
void __user * ifru_data;
structif_settings ifru_settings;
} ifr_ifru;
};

#define ifr_name ifr_ifrn.ifrn_name #define ifr_hwaddr ifr_ifru.ifru_hwaddr 
#defineifr_addr ifr_ifru.ifru_addr #defineifr_dstaddr ifr_ifru.ifru_dstaddr #defineifr_broadaddr ifr_ifru.ifru_broadaddr #defineifr_netmask ifr_ifru.ifru_netmask#defineifr_flags ifr_ifru.ifru_flags 
#defineifr_metric ifr_ifru.ifru_ivalue#defineifr_mtu ifr_ifru.ifru_mtu#define ifr_map ifr_ifru.ifru_map#define ifr_slave ifr_ifru.ifru_slave#defineifr_data ifr_ifru.ifru_data #define ifr_ifindex ifr_ifru.ifru_ivalue#define ifr_bandwidth ifr_ifru.ifru_ivalue #define ifr_qlen ifr_ifru.ifru_ivalue#define ifr_newname ifr_ifru.ifru_newname#define ifr_settings ifr_ifru.ifru_setting

ioctl函式能獲取到IP地址、子網掩碼、廣播地址、硬體MAC地址等資訊,至於閘道器及路由表比較複雜,在此不討論。

具體程式碼如下:(測試通過)

#include <stdio.h>

#include <stdlib.h>

#include <net/if.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <arpa/inet.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <errno.h>

#include <fcntl.h>

#include <netinet/in.h>

#include <net/route.h>

#include <string.h>

#include <net/if_arp.h>

int main()

{

   struct sockaddr_in *sin;

   struct ifreq ifr;

   FILE *dns;

   FILE *gw;

   char *ip = new char(16);

   char *netmask = new char(16);

   char *broadcast = new char(16);

   //char *ip = (char *)malloc(16);

   char *mac = new  char(32);

   //char *mac = (char *)malloc(32);

   int socket_fd;

       if((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){

               perror("socket");

               exit(1);

       }

       memset(&ifr, 0, sizeof(ifr));

       strcpy(ifr.ifr_name, "eth0");

       memset(&sin, 0, sizeof(sin));

//獲取IP地址

       if(ioctl(socket_fd, SIOCGIFADDR, &ifr) != -1){

               sin = (struct sockaddr_in *)&ifr.ifr_addr;

               strcpy(ip, inet_ntoa(sin->sin_addr));

               printf("IP address is %s\n", ip);

       }

//獲取廣播地址

       if(ioctl(socket_fd, SIOCGIFBRDADDR, &ifr) != -1){

               sin = (struct sockaddr_in *)&ifr.ifr_broadaddr;

               strcpy(broadcast, inet_ntoa(sin->sin_addr));

               printf("Broadcast is %s\n", broadcast);

       }

//獲取子網掩碼

       if(ioctl(socket_fd, SIOCGIFNETMASK, &ifr) != -1){

               sin = (struct sockaddr_in *)&ifr.ifr_broadaddr;

               strcpy(netmask, inet_ntoa(sin->sin_addr));

               printf("Net-mask is %s\n", netmask);

       }

//獲取硬體MAC地址

       if(ioctl(socket_fd, SIOCGIFHWADDR, &ifr) != -1){

               sin = (struct sockaddr_in *)&ifr.ifr_netmask;

               sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",

               (unsigned char)ifr.ifr_netmask.sa_data[0],

               (unsigned char)ifr.ifr_netmask.sa_data[1],

               (unsigned char)ifr.ifr_netmask.sa_data[2],

               (unsigned char)ifr.ifr_netmask.sa_data[3],

               (unsigned char)ifr.ifr_netmask.sa_data[4],

               (unsigned char)ifr.ifr_netmask.sa_data[5]);

               printf("Mac address is %s\n", mac);

       }

   return 0;

}

至於獲取閘道器以及DNS,我是通過相關命令獲得的。

主要程式碼如下:

//獲取閘道器,利用route -n 命令可以看到相關的閘道器。連線標誌是‘UG’

if(gw_fd = popen("route -n | grep 'UG'", "r")){

   fread(temp,1,128, gw_fd);

   sscanf(temp, "%*s%s", szNetGate);

   printf("Gateway is %s\n", szNetGate);

}

//獲取DNS;一般DNS儲存在/etc/reslov.conf檔案中。具體獲得方法要根據實際情況而定。

我的配置檔案中是這樣的

[email protected]:/home/arm-none-linux# cat /etc/resolv.conf

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)

#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 202.96.134.133  

上面的202.96.134.133就是我需要獲取的主DNS,沒有備用DNS

if(dns_fd = popen("cat /etc/reslov.conf | grep 'nameserver'", "r")){

   fread(temp,1,128, gw_fd);

   sscanf(temp, "%*s%s%*s%s", szDNS1,szDNS2);

   printf("DNS1 is %s",szDNS1);

   printf("DNS2is %s", szDNS2);

}

寫在前面

獲取與設定網絡卡資訊的方法有很多種,本文就傳統的通過ioctl介面獲取的方法做個記錄。

此外,通過ioctl還可以獲取網絡卡裝置的對映屬性。更進一步,可以讓我們檢視,修改,刪除系統的ARP快取記憶體和路由表資訊。

相關結構體

這裡主要相關的兩個結構體定義在glibc標頭檔案/usr/include/net/if.h中,分別為struct ifconf和struct ifreq。

/* Structure used in SIOCGIFCONF request.  Used to retrieve interface
   configuration for machine (useful for programs which must know all
   networks accessible).  */

struct ifconf
  {
    int ifc_len;                        /* Size of buffer.  */
    union
      {
        __caddr_t ifcu_buf;
        struct ifreq *ifcu_req;
      } ifc_ifcu;
  };
# define ifc_buf        ifc_ifcu.ifcu_buf       /* Buffer address.  */
# define ifc_req        ifc_ifcu.ifcu_req       /* Array of structures.  */
# define _IOT_ifconf _IOT(_IOTS(struct ifconf),1,0,0,0,0) /* not right */
#endif  /* Misc.  */

從註釋資訊中可以看出struct ifconf主要是用來利用ioctl函式的SIOCGIFCONF request來獲取系統中所有網路介面的資訊。關於它的具體用法,後文會有示例。

既然是關於系統中所有的網路介面資訊,那麼一個網路介面資訊用什麼結構來表示呢? 這就是struct ifreq的用處了。

/* Interface request structure used for socket ioctl's.  All interface
   ioctl's must have parameter definitions which begin with ifr_name.
   The remainder may be interface specific.  */

struct ifreq
  {
# define IFHWADDRLEN	6
# define IFNAMSIZ	IF_NAMESIZE
    union
      {
	char ifrn_name[IFNAMSIZ];	/* Interface name, e.g. "en0".  */
      } ifr_ifrn;

    union
      {
	struct sockaddr ifru_addr;
	struct sockaddr ifru_dstaddr;
	struct sockaddr ifru_broadaddr;
	struct sockaddr ifru_netmask;
	struct sockaddr ifru_hwaddr;
	short int ifru_flags;
	int ifru_ivalue;
	int ifru_mtu;
	struct ifmap ifru_map;
	char ifru_slave[IFNAMSIZ];	/* Just fits the size */
	char ifru_newname[IFNAMSIZ];
	__caddr_t ifru_data;
      } ifr_ifru;
  };
# define ifr_name	ifr_ifrn.ifrn_name	/* interface name 	*/
# define ifr_hwaddr	ifr_ifru.ifru_hwaddr	/* MAC address 		*/
# define ifr_addr	ifr_ifru.ifru_addr	/* address		*/
# define ifr_dstaddr	ifr_ifru.ifru_dstaddr	/* other end of p-p lnk	*/
# define ifr_broadaddr	ifr_ifru.ifru_broadaddr	/* broadcast address	*/
# define ifr_netmask	ifr_ifru.ifru_netmask	/* interface net mask	*/
# define ifr_flags	ifr_ifru.ifru_flags	/* flags		*/
# define ifr_metric	ifr_ifru.ifru_ivalue	/* metric		*/
# define ifr_mtu	ifr_ifru.ifru_mtu	/* mtu			*/
# define ifr_map	ifr_ifru.ifru_map	/* device map		*/
# define ifr_slave	ifr_ifru.ifru_slave	/* slave device		*/
# define ifr_data	ifr_ifru.ifru_data	/* for use by interface	*/
# define ifr_ifindex	ifr_ifru.ifru_ivalue    /* interface index      */
# define ifr_bandwidth	ifr_ifru.ifru_ivalue	/* link bandwidth	*/
# define ifr_qlen	ifr_ifru.ifru_ivalue	/* queue length		*/
# define ifr_newname	ifr_ifru.ifru_newname	/* New name		*/
# define _IOT_ifreq	_IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
# define _IOT_ifreq_int	_IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)
struct ifreq中的資訊就是一個網路介面的所有屬性了,平時用的最多的ifconfig命令的輸出就是這些屬性的陳列。

相關推薦

Linux利用ioctl函式獲取資訊

linux下的ioctl函式原型如下: #include <sys/ioctl.h> int ioctl(int handle, int cmd, [int *argc, int argv]) 函式成功返回0,失敗返回-1. 其相關命令介面如下:

linux通過c語言介面獲取資訊

方法一 通過ioctl的SIOCGIFCONF 例項1. 檢查特定的網絡卡是否存在 // ppp、wifi是否正常 static int check_ppp_wifi (int wifi_switch) { struct ifreq ifr

linux c/c++按規則獲取ip

linux c/c++按規則獲取網絡卡ip 輸出專案到雲或者輸出給外部客戶,會遇到伺服器多網絡卡多ip的情形,如果有多個應用都需要這個主機ip,而且多應用需要獲取相同的ip,此時可以約定一種規則來獲取相同的ip,比如: 獲得所有網絡卡名,然後對網絡卡名按從小到大排序,查詢最小

linux如何實現為一個繫結多個IP地址

Linux的網路裝置配置檔案存放在/etc/sysconfig/network-scripts裡面,對於乙太網的第一個網路裝置,配置檔名一般為 ifcfg-eth0 如果需要為第一個網路裝置繫結多一個IP地址,只需要在/

Linux 小米WIFI 的無線驅動

在小米的罈子裡看到了大神發的 小米WIFI 驅動 for Linux。於是就下載下來為自己的linux(Fedora 21 ,  kernel:3.17.8-300 )安裝小米WIFI 驅動。 過程記錄如下(其實也適用於 小度WIFI 和 360 WIFI ,只要用的是晶

API函式GetAdaptersAddresses獲取資訊MAC &IP &描述資訊

一 , 兩個函式 The GetAdaptersInfo function retrieves adapter information for the local computer The GetAdaptersAddresses function retrieves t

linux獲取資訊

sar -n DEV 1 1|grep -E "(Average)|(平均)"|awk '{if(NR>1){a="";"dmesg |grep "$2"|grep \"Link is up\""|getline

linux中使用ifconfig命令檢視資訊時顯示為eth1,但是在network-scripts中只有ifcfg-eth0的配置檔案,並且裡面的NAME="eth0"

除了題目中的問題,其實在執行命令:service network restart時,會報錯: 解決辦法: 首先需要修改70-persistent-net.rules檔案: vim /etc/udev/rules.d/70-persistent-net.rules 然

c# 多 由【網路介面卡名】獲取資訊,IP

c# 多網絡卡 由【網路介面卡名】獲取網絡卡資訊,IP 多網絡卡電腦中,網路介面卡的名字 多樣化! 專案中需要,根據網路介面卡 名字 獲取 單個網絡卡的IP: using System.Net.NetworkInformation;

linux中使用ifconfig命令檢視資訊時顯示為eth1,但是在network-scripts中只有ifcfg-eth0的配置檔案,並且裡面的NAME="eth0"。

除了題目中的問題,其實在執行命令:service network restart時,會報錯:  解決辦法: 首先需要修改70-persistent-net.rules檔案: vim /etc/udev/rules.d/70-persistent-net.rules 然後修改ifcfg-eth0檔案: v

c# 獲取資訊

private IList<IPInfo> GetIPInfo() { IList<IPInfo> rIPList = new List<IPInfo>(); Networ

Linux通過shell獲取的ip地址和mac地址

ip=`ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'` mac=`ifconfig | grep HWaddr | awk -F" " '{print $5}'` 轉自:http://blog.csdn.

LinuxC獲取所有可用資訊

在Linux下開發網路程式時,經常會遇到需要取本地網路介面名、IP、廣播地址、子網掩碼或者MAC地址等資訊的需求,最常見的辦法是配合巨集SIOCGIFHWADDR、SIOCGIFADDR、SIOCGIFBRDADDR與SIOCGIFNETMASK作為引數呼叫函式

Linux多程序程式設計小例——獲取的IP地址

Linux下多程序程式設計的核心是呼叫fork()系統呼叫用來建立一個新的程序:pid_t   fork(void);  由fork()建立的新程序被稱為子程序。fork()函式被呼叫一次,但有兩次返回。 返回值=0:  子程序              返回值>0: 

linuxC語言獲取MAC地址

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/socket.h&g

LINUX獲取IP地址和MAC地址,子掩碼程式參考

/* mode time:20120727 LINUX下獲取IP地址和MAC地址.程式相關結構體在程式後面。 列印網絡卡的ip地址 子網掩碼 廣播地址 mac地址 環境: [[email protected] temp]# uname -a Linux b

Linux用netstat查看狀態、端口狀態

服務端 哪些 ipv4 foreign udp協議 nat 進行 ets 當我 在linux一般使用netstat 來查看系統端口使用情況步。 netstat命令是一個監控TCP/IP網絡的非常有用的工具,它可以顯示路由表、實際的網絡連接以及每一個網絡接口設備的

LinuxC語言的socket編程

網絡編程 服務器 enter 編程 scanf 路由 client p s drl Server.c 1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <n

linux程式設計獲取本機資訊

轉自:https://blog.csdn.net/shaderdx/article/details/78403437 ifaddrs結構體定義如下: struct ifaddrs    {      &

(筆記)Linuxioctl()函式詳解

我這裡說的ioctl函式是指驅動程式裡的,因為我不知道還有沒有別的場合用到了它,所以就規定了我們討論的範圍。寫這篇文章是因為我前一陣子被ioctl給搞混了,這幾天才弄明白它,於是在這裡清理一下頭腦。 一、 什麼是ioctl      ioctl是裝置驅動程