天天看點

擷取網絡接口資訊——ioctl()函數與結構體struct ifreq、 struct ifconf (擷取或設定 網卡 IP 子網路遮罩 本地廣播位址)

Linux 下 可以使用ioctl()函數 以及 結構體 struct ifreq  結構體struct ifconf來擷取網絡接口的各種資訊。

ioctl

首先看ioctl()用法

ioctl()原型如下:

#include <sys/ioctl.h>
int ioctl(int fd, int request, ...);
參數:
fd     :  檔案描述符
request:  表示要請求的資訊。如IP位址、網絡掩碼等
...    :  後面的可變參數根據request而定
           

比如我們請求所有網絡接口的清單:

struct ifconf IoCtlReq;
...
ioctl( Sock, SIOCGIFCONF, &IoCtlReq )
           

其中IoCtlReq 是一個

與接口相關的request如下表所示(來源: <http://baike.baidu.com/view/1081282.htm?fr=aladdin>):

擷取網絡接口資訊——ioctl()函數與結構體struct ifreq、 struct ifconf (擷取或設定 網卡 IP 子網路遮罩 本地廣播位址)

關于ioctl的詳細解釋清查閱本博其它博文

struct ifreq

結構體 struct ifreq用來儲存某個接口的資訊。

// if.h
/*
 * 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
	union
	{
		char	ifrn_name[IFNAMSIZ];		/* if 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	ifru_flags;
		int	ifru_ivalue;
		int	ifru_mtu;
		struct  ifmap ifru_map;
		char	ifru_slave[IFNAMSIZ];	/* Just fits the size */
		char	ifru_newname[IFNAMSIZ];
		void __user *	ifru_data;
		struct	if_settings ifru_settings;
	} 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 ifr_settings	ifr_ifru.ifru_settings	/* Device/proto settings*/
           

ifr_name 辨別了某一接口。

可以通過ioctl擷取該接口的資訊。如:

ioctl(Sock, SIOCGIFNETMASK, &IfReq);//擷取網絡接口位址掩碼
           

該代碼需要先對IfReq->ifr_name指派,然後擷取與IfReq->ifr_name向比對的網絡接口 的位址掩碼

struct ifconf

結構體struct ifconf通常用來儲存所有接口資訊

// if.h
/*
 * 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 {
		char __user *ifcu_buf;
		struct ifreq __user *ifcu_req;
	} ifc_ifcu;
};
#define	ifc_buf	ifc_ifcu.ifcu_buf		/* buffer address	*/
#define	ifc_req	ifc_ifcu.ifcu_req		/* array of structures	*/
           

該結構體可以用來擷取所喲網絡接口的名字和資訊(不是全部資訊,是ip位址)

(圖檔來自:http://tech.sunplusedu.com/space/post-4064.aspx)

擷取網絡接口資訊——ioctl()函數與結構體struct ifreq、 struct ifconf (擷取或設定 網卡 IP 子網路遮罩 本地廣播位址)

Example:

#include <sys/types.h>  
#include <sys/ioctl.h>  
#include <sys/socket.h>  
#include <net/if.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <netdb.h>  
#include <string.h>  
#include <fcntl.h>  
#include <string.h>  
#include <errno.h>
typedef uint32_t uint32; 
#define MAX_IF 10
int 
main()
{
	struct ifreq ifVec[MAX_IF];//用來儲存所有接口
	
	int sock = -1;
	if ( (sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 )
		fprintf(stderr, "Error:%d, cannot open RAM;\n");
	
	// get if vector
 	struct ifconf ioIfConf;
    	ioIfConf.ifc_buf = (void *)ifVec;
       	ioIfConf.ifc_len = sizeof(ifVec);
	 printf("Len:%d\n", ioIfConf.ifc_len);     
		
	if (ioctl(sock, SIOCGIFCONF, &ioIfConf) < 0 )//擷取所有網絡接口資訊
		fprintf(stderr, "Error:%d   ioctl IFCONF\n");
	
	 printf("Len:%d\n", ioIfConf.ifc_len);// 和前面到len對比,發現ioctl修改裡len到大小     
	//循環列印每個網絡接口到資訊
	{
		struct ifreq *ifPt;
		struct ifreq *ifEndPt;
		ifPt = ifVec;
		ifEndPt = (void *)((char *)ifVec + ioIfConf.ifc_len);
		for (ifPt = ifVec; ifPt < ifEndPt; ifPt++)
		{
			struct ifreq ifReq;
			if ( ifPt->ifr_addr.sa_family != AF_INET ) {
                		continue;
            		}
			
			// Temp keepers of interface params...
			uint32 u32_addr, u32_mask;
			
			/*	列印ip位址	*/
			char ipDotBuf[16], subnetDotBuf[16], maskDotBuf[16]; // 儲存點分十進制到ip位址
			u32_addr = ((struct sockaddr_in *)&ifPt->ifr_addr)->sin_addr.s_addr;
			inet_ntop(AF_INET, &u32_addr, ipDotBuf, (socklen_t )sizeof(ipDotBuf)); 
			printf("IP Address: %s\n", ipDotBuf);
			
			/*    列印位址掩碼    */
			bzero(&ifReq,sizeof(struct ifreq));  
			memcpy(ifReq.ifr_name, ifPt->ifr_name, sizeof(ifReq.ifr_name));  
			if (ioctl(sock, SIOCGIFNETMASK, &ifReq ) < 0){
				fprintf(stderr, "Error: %d, cannot get mask\n", errno);
			}
			else{
				u32_mask = ((struct sockaddr_in *)&ifReq.ifr_addr)->sin_addr.s_addr;
				inet_ntop(AF_INET, &u32_mask, maskDotBuf, (socklen_t )sizeof(maskDotBuf));
				printf("Mask: %s\n", maskDotBuf);
			}	
			/*    列印MTU    */
			bzero(&ifReq,sizeof(struct ifreq));  
			memcpy(ifReq.ifr_name, ifPt->ifr_name, sizeof(ifReq.ifr_name));  
			if (ioctl(sock, SIOCGIFMTU, &ifReq ) < 0){
				fprintf(stderr, "Error: %d, cannot get MTU\n", errno);
			}
			else{
				printf("SIOCGIFMTU:%d\n", ifReq.ifr_mtu); 
			}
	           /*    其他資訊的列印方式與掩碼和MTU相同    */
		}
	}
}
           

運作結果:

[email protected]:~/Windeal/apue$ ./exe 
Len:320
Len:64
IP Address: 127.0.0.1
Mask: 255.0.0.0
SIOCGIFMTU:16436
IP Address: 172.17.92.198
Mask: 255.255.254.0
SIOCGIFMTU:1500
[email protected]:~/Windeal/apue$