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结构体的指针,用做输入输出参数。
在编写程序的时候遇到的小问题:
- 用什么结构体来存取硬件地址信息(mac地址)?硬件地址信息如何转换为可以输出的字符串类型?
- DNS相关信息如何获取?
- 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下获取网络接口信息的主要内容,如果未能解决你的问题,请参考以下文章