获取网络接口信息——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 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)

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相同    */
		}
	}
}

运行结果:

windeal@ubuntu:~/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
windeal@ubuntu:~/Windeal/apue$ 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用getifaddrs函数获取网络接口信息的C程序,包括名称、MAC地址、子网掩码IP地址和网关信息。请注意,获取网关信息需要使用系统调用来实现,因此这个程序只能在类Unix系统上运行。 ```c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <ifaddrs.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> #include <string.h> #include <unistd.h> int main(int argc, char *argv[]) { struct ifaddrs *ifaddr, *ifa; int family, s, n; char host[NI_MAXHOST]; char gateway[NI_MAXHOST]; char mac[18]; if (getifaddrs(&ifaddr) == -1) { perror("getifaddrs"); return EXIT_FAILURE; } /* Walk through linked list, maintaining head pointer so we can free list later */ for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) { if (ifa->ifa_addr == NULL) { continue; } family = ifa->ifa_addr->sa_family; /* Display interface name and family (including symbolic form of the latter for the common families) */ printf("%-8s %s (%d)\n", ifa->ifa_name, (family == AF_PACKET) ? "AF_PACKET" : (family == AF_INET) ? "AF_INET" : (family == AF_INET6) ? "AF_INET6" : "???", family); /* For an AF_PACKET interface, display the MAC address. */ if (family == AF_PACKET && ifa->ifa_data != NULL) { struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr; sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x", s->sll_addr[0], s->sll_addr[1], s->sll_addr[2], s->sll_addr[3], s->sll_addr[4], s->sll_addr[5]); printf("\t\tAddress: %s\n", mac); } /* For an AF_INET or AF_INET6 interface, display the address and subnet mask */ else if (family == AF_INET || family == AF_INET6) { s = socket(family, SOCK_DGRAM, 0); if (s == -1) { perror("socket"); return EXIT_FAILURE; } if (getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) { printf("\t\tAddress: <%s>\n", host); } if (getnameinfo(ifa->ifa_netmask, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) { printf("\t\tNetmask: <%s>\n", host); } /*Get the gateway address*/ if (family == AF_INET) { struct rtentry *route; memset(&route, 0, sizeof(route)); route->rt_dst.sa_family = AF_INET; ((struct sockaddr_in *) &route->rt_dst)->sin_addr.s_addr = 0; route->rt_flags = RTF_UP; if (ioctl(s, SIOCADDRT, &route) < 0) { perror("SIOCADDRT failed"); return EXIT_FAILURE; } struct sockaddr_in *addr; for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { addr = (struct sockaddr_in *) ifa->ifa_addr; if (ifa->ifa_flags & IFF_LOOPBACK) { continue; } if (addr->sin_addr.s_addr == ((struct sockaddr_in *) &route->rt_dst)->sin_addr.s_addr) { continue; } if (ioctl(s, SIOCGIFHWADDR, ifa) == -1) { perror("ioctl failed"); return EXIT_FAILURE; } if (ifa->ifa_addr) { inet_ntop(AF_INET, &addr->sin_addr, gateway, NI_MAXHOST); printf("\t\tGateway: %s\n", gateway); } } } if (ioctl(s, SIOCDELRT, &route) < 0) { perror("SIOCDELRT failed"); return EXIT_FAILURE; } } close(s); } } freeifaddrs(ifaddr); return EXIT_SUCCESS; } ``` 这个程序将会打印出每个网络接口的名称、MAC地址、IP地址、子网掩码和网关信息。如果某个接口没有网关,它将不会打印网关信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值