Linux下获取网络接口信息

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux下获取网络接口信息相关的知识,希望对你有一定的参考价值。

Linux下的网络接口信息在shell下可以很方便地使用ifconfig查看。同样,使用C/C++也可以很方便地获取接口信息。

netdevice是一个低级别的访问Linux网络设备的方法。此方法通过ioctl来获取网络接口的相关信息。

这里需要借助<net/if.h>头文件中定义的ifreq结构体。此结构体包含了网络接口的名称、IP地址、广播地址、网络地址、

掩码等相关信息。在获取上述相关信息的时候需要指明网络接口的名称。

 1  struct ifreq {
 2                char ifr_name[IFNAMSIZ]; /* Interface name */
 3                union {
 4                    struct sockaddr ifr_addr;
 5                    struct sockaddr ifr_dstaddr;
 6                    struct sockaddr ifr_broadaddr;
 7                    struct sockaddr ifr_netmask;
 8                    struct sockaddr ifr_hwaddr;
 9                    short           ifr_flags;
10                    int             ifr_ifindex;
11                    int             ifr_metric;
12                    int             ifr_mtu;
13                    struct ifmap    ifr_map;
14                    char            ifr_slave[IFNAMSIZ];
15                    char            ifr_newname[IFNAMSIZ];
16                    char           *ifr_data;
17                };
18  };

ifreq结构体的定义如上图所示,此结构体中包含了一段联合体,它们共享一段内存空间。

int ioctl(int fd, unsigned long request, ...);

ioctl()函数此处可以用于获取网络接口信息。fd为打开的文件指针,此处可以为任意类型的socket(套接字),一般使用

int sockfd = socket(AF_INET, SOCK_DGRAM, 0)

由于网络接口信息对应变量共享一段内存,所以每次使用ioctl请求得到的网络接口信息只能是一种。对应不同的网络接口

信息可以使用不同的请求常量。

1 //用于请求硬件地址
2 SIOCGIFHWADDR      
3 //用于请求IP地址                       
4 SIOCGIFADDR                                     
5 //用于请求IP广播地址
6 SIOCGIFBRDADDR
7 //用于请求子网掩码
8 SIOCGIFNETMASK

ioctl()的第三个参数需要传入一个ifreq结构体的指针,用做输入输出参数。

在编写程序的时候遇到的小问题:

  1. 用什么结构体来存取硬件地址信息(mac地址)?硬件地址信息如何转换为可以输出的字符串类型?
  2. DNS相关信息如何获取?
  3. std::string如何查找和拷贝字符串?

1. 使用ether_addr来存储硬件地址信息。这个结构体位于<netinet/ether.h>头文件中,使用ioctl获取到

硬件地址后可以使用内存拷贝的方法将值拷贝至ether_addr当中。ether_addr可以通过ether_ntoa()函数

转换成字符数组的形式。此函数同样位于<netinet/ether.h>头文件中,可以使用命令man ether_ntoa来

查看更多相关信息。

2. 主流Linux桌面发行版使用的Network Manager作为网络管理器,这个网络管理器会在etc目录下生成一

个resolv.conf文件,里面包含了当前DNS的相关信息。可以采用读这个文件的方式来获取DNS信息。

3. C++ string常用操作可以查看http://www.cppblog.com/lmlf001/archive/2006/04/19/5883.html

这篇博客,查找字符串通常使用find()函数,给新字符串分配已有字符串的一部分可以使用assign() 函数。

 

附上完整程序:

m_netdevice.h

 1 #ifndef M_NETDEVICE_H
 2 #define M_NETDEVICE_H
 3 
 4 #include <st_header.h>
 5 #include <arpa/inet.h>
 6 #include <netinet/in.h>
 7 #include <netinet/ether.h>
 8 #include <net/if.h>
 9 #include <sys/ioctl.h>
10 #include <string.h>
11 #include <iostream>
12 #include <fstream>
13 #include <vector>
14 #include <string>
15 
16 struct Netdev_int
17 {
18     struct deviceInfo {
19         char int_name[IFNAMSIZ];
20         sockaddr_in ip_addr;
21         sockaddr_in bc_addr;
22         sockaddr_in net_mask;
23         ether_addr hw_addr;
24         std::vector<std::string> dns_name;
25         std::vector<std::string> dns_addr;
26 
27     } m_dev;
28     void getIfInfo(char *if_name);
29     void printDeviceInfo();
30     void help();
31 };
32 
33 #endif // M_NETDEVICE_H

m_netdevice.cpp

 1 #include <m_netdevice.h>
 2 void Netdev_int::getIfInfo(char *if_name)
 3 {
 4     struct ifreq ifr;
 5     memcpy(ifr.ifr_ifrn.ifrn_name, if_name, strlen(if_name));
 6     memcpy(m_dev.int_name, if_name, strlen(if_name));
 7     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
 8     if(ioctl(sockfd, SIOCGIFHWADDR, &ifr) == -1)
 9     {
10         perror("ioctl error");
11         exit(1);
12     }
13     memcpy(&m_dev.hw_addr, (ether_addr*)ifr.ifr_ifru.ifru_hwaddr.sa_data,
14            sizeof(ether_addr));
15     if(ioctl(sockfd, SIOCGIFADDR, &ifr) == -1)
16     {
17         perror("ioctl error");
18         exit(1);
19     }
20     memcpy(&m_dev.ip_addr, (sockaddr_in*)&ifr.ifr_ifru.ifru_addr,
21            sizeof(sockaddr_in));
22     if(ioctl(sockfd, SIOCGIFBRDADDR, &ifr) == -1)
23     {
24         perror("ioctl error");
25         exit(1);
26     }
27     memcpy(&m_dev.bc_addr, (sockaddr_in*)&ifr.ifr_ifru.ifru_broadaddr,
28            sizeof(sockaddr_in));
29     if(ioctl(sockfd, SIOCGIFNETMASK, &ifr) == -1)
30     {
31         perror("ioctl error");
32         exit(1);
33     }
34     memcpy(&m_dev.net_mask, (sockaddr_in*)&ifr.ifr_ifru.ifru_netmask,
35            sizeof(sockaddr_in));
36     std::ifstream in;
37     in.open("/etc/resolv.conf");
38     std::string str;
39     while(std::getline(in, str))
40     {
41         if(str.at(0) == #) continue;
42         int pos = str.find_first_of( );
43         std::string d_name;
44         std::string d_addr;
45         d_name.assign(str, 0, pos);
46         d_addr.assign(str, pos, str.length());
47         m_dev.dns_name.push_back(d_name);
48         m_dev.dns_addr.push_back(d_addr);
49     }
50 
51 }
52 
53 void Netdev_int::printDeviceInfo()
54 {
55     std::cout << m_dev.int_name << std::endl;
56     std::cout << "Hardware Address:" << ether_ntoa(&m_dev.hw_addr) << std::endl;
57     std::cout << "IP Address:" << inet_ntoa(m_dev.ip_addr.sin_addr) << std::endl;
58     std::cout << "Boardcast Address:" << inet_ntoa(m_dev.bc_addr.sin_addr) << std::endl;
59     std::cout << "Net Mask:" << inet_ntoa(m_dev.net_mask.sin_addr) << std::endl;
60     std::vector<std::string>::iterator it2addr = m_dev.dns_addr.begin();
61     for(std::vector<std::string>::iterator it = m_dev.dns_name.begin();
62         it != m_dev.dns_name.end(); it++)
63     {
64         std::cout << *it << ":" << *it2addr << std::endl;
65         it2addr++;
66     }
67 }
68 
69 void Netdev_int::help()
70 {
71     std::cout << "ifdev if_name" << std::endl;
72     std::cout << "for example:" << std::endl;
73     std::cout << "ifdev eth0" << std::endl;
74 }

st_header.h

1 #ifndef ST_HEADER_H
2 #define ST_HEADER_H
3 
4 #include <error.h>
5 
6 #endif // ST_HEADER_H

main.cpp

 1 #include <iostream>
 2 #include <m_netdevice.h>
 3 
 4 using namespace std;
 5 
 6 int main(int argc, char **argv)
 7 {
 8     Netdev_int *netdev_int = new Netdev_int();
 9     if(argc == 1) {
10         netdev_int->help();
11     }
12     else {
13         netdev_int->getIfInfo(argv[1]);
14         netdev_int->printDeviceInfo();
15     }
16 }

 


以上是关于Linux下获取网络接口信息的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 Linux/UNIX 上当前的网络接口吞吐量统计信息? [关闭]

在 Linux 上获取有关网络接口更改的通知

Linux 获取物理网口/或虚拟网络接口

Linux下如何获取网卡信息

Linux环境下pcap程序获取网络设备接口的问题

linux网络配置