C/C++ Linux 所有接口的 MAC 地址
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9034575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C/C++ Linux MAC Address of all interfaces
提问by user1173626
I am using the following code to retrieve all MAC addresses for current computer:
我正在使用以下代码检索当前计算机的所有 MAC 地址:
ifreq ifr;
ifconf ifc;
char buf[1024];
int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) { ... };
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { ... }
ifreq *it = ifc.ifc_req;
const ifreq* const end = it + (ifc.ifc_len / sizeof(ifreq));
for (; it != end; ++it) {
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (!(ifr.ifr_flags & IFF_LOOPBACK)) {
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
unsigned char mac_address[6];
memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
...
}
}
}
else { ... }
}
By running simple shell command ifconfig i can see lo, eth0 and wlan0. I would like to retrieve MAC addresses for eth0 and wlan0 by my C/C++ code. But only wlan0 is returned - eth0 is missing (I got ifr_names lo, lo, wlan0). Probably because eth0 is not active (no ethernet cable connected, with cable it is returned). Can I somehow alter that ioctl(SIOCGIFCONF) command to retrieve eth0 too even if it is "turned off"?
通过运行简单的 shell 命令 ifconfig,我可以看到 lo、eth0 和 wlan0。我想通过我的 C/C++ 代码检索 eth0 和 wlan0 的 MAC 地址。但只返回 wlan0 - eth0 丢失(我得到了 ifr_names lo, lo, wlan0)。可能是因为 eth0 未激活(未连接以太网电缆,电缆已返回)。我可以以某种方式更改 ioctl(SIOCGIFCONF) 命令以检索 eth0 即使它被“关闭”?
I can get its HW address by using directly
我可以通过直接使用获得它的硬件地址
struct ifreq s;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
strcpy(s.ifr_name, "eth0");
if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) { ... }
but what if the name would be not eth0 but something else (eth1, em0,...)? I would like to get all of them. Thanks for help.
但是如果名称不是 eth0 而是其他名称 (eth1, em0,...) 呢?我想得到所有这些。感谢帮助。
采纳答案by j?rgensen
You should stop using net-tools and the archaic ioctl interface, and start on using the modern Netlink/sysfs interfaces. You have no less than 5 possibilities:
您应该停止使用 net-tools 和过时的 ioctl 接口,并开始使用现代 Netlink/sysfs 接口。你有不少于5种可能性:
- write your own Netlink-interfacing code
- your own NL code, in combination utilizing libmnl(-> see rtnl-link-dump in Examples
- or utilize autonomous libs like libnl3
- parse text output of
ip -o link
(-o is to get output meant for text parsing, unlike ifconfig) - or use sysfs and just look at
/sys/class/net/eth0/address
- 编写您自己的 Netlink 接口代码
- 自己NL代码,并结合利用libmnl( - >见rtnl链接转储例子
- 或使用像libnl3这样的自治库
- parse text output of
ip -o link
(-o 是获取用于文本解析的输出,与 ifconfig 不同) - 或使用 sysfs 并查看
/sys/class/net/eth0/address
回答by Scott Hunter
Maybe not as elegant, but you could capture & parse the results from ifconfig, since it sounds like it has just what you are looking for.
也许不那么优雅,但您可以从 ifconfig 捕获并解析结果,因为听起来它正是您想要的。
回答by Niklas Hansson
You can find a solution here: Get mac address given a specific interface
您可以在此处找到解决方案:Get mac address given a specific interface
You can just skip the specific interface part.
您可以跳过特定的界面部分。
回答by Shalom Craimer
Inspired by j?rgensen's answer, the C++17 code below uses Netlink to get the MAC address and name of each interface. It is a modified version of this gist, which helped me overcome my shyness about using Netlink. It really isn't as complex as it seems at first.
受j?rgensen's answer 的启发,下面的 C++17 代码使用 Netlink 来获取每个接口的 MAC 地址和名称。这是这个要点的修改版本,它帮助我克服了使用 Netlink 的害羞。它真的没有乍一看那么复杂。
#include <linux/rtnetlink.h>
#include <net/if_arp.h>
#include <unistd.h>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
using std::byte;
using std::string;
using std::vector;
struct RtReq {
nlmsghdr header;
ifinfomsg msg;
};
class fd_wrapper
{
public:
fd_wrapper( int const fd_arg ) : fd_( fd_arg ) {}
~fd_wrapper() { close( fd_ ); }
int fd() const noexcept { return fd_; }
private:
int fd_;
};
void print_all_macs()
{
fd_wrapper fd = ( []() -> fd_wrapper {
RtReq req = ( []() {
RtReq req;
memset( &req, 0, sizeof( req ) );
req.header.nlmsg_len = NLMSG_LENGTH( sizeof( struct ifinfomsg ) );
req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
req.header.nlmsg_type = RTM_GETLINK;
req.header.nlmsg_seq = 1; // We're only sending one message
req.msg.ifi_family = AF_UNSPEC;
req.msg.ifi_change = 0xffffffff;
return std::move( req );
} )();
sockaddr_nl sa;
memset( &sa, 0, sizeof( sa ) );
sa.nl_family = AF_NETLINK;
iovec iov = {&req, req.header.nlmsg_len};
msghdr msg = {&sa, sizeof( sa ), &iov, 1, nullptr, 0, 0};
int fd = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
sendmsg( fd, &msg, 0 );
return fd_wrapper( fd );
} )();
enum class Result { not_done, done };
auto read_message = []( fd_wrapper const& fd ) -> Result {
char buf[16 * 1024];
iovec iov = {buf, sizeof( buf )};
sockaddr_nl sa;
msghdr msg = {&sa, sizeof( sa ), &iov, 1, nullptr, 0, 0};
int len = recvmsg( fd.fd(), &msg, 0 );
for( nlmsghdr* nh = (nlmsghdr*)buf; NLMSG_OK( nh, len ); nh = NLMSG_NEXT( nh, len ) ) {
if( nh->nlmsg_type == NLMSG_DONE ) {
return Result::done;
}
if( nh->nlmsg_type != RTM_BASE )
continue;
ifinfomsg* msg = (ifinfomsg*)NLMSG_DATA( nh );
if( msg->ifi_type != ARPHRD_ETHER )
continue;
rtattr* rta = IFLA_RTA( msg );
int alen = nh->nlmsg_len - NLMSG_LENGTH( sizeof( *msg ) );
string name;
vector<byte> addr;
for( ; RTA_OK( rta, alen ); rta = RTA_NEXT( rta, alen ) ) {
if( rta->rta_type == IFLA_ADDRESS ) {
auto const p = reinterpret_cast<byte const*>( RTA_DATA( rta ) );
addr.insert( addr.begin(), p, p + 6 );
}
if( rta->rta_type == IFLA_IFNAME ) {
name = string{(char*)RTA_DATA( rta )};
}
}
auto const c = reinterpret_cast<uint8_t const*>( addr.data() );
printf( "%02x:%02x:%02x:%02x:%02x:%02x %s\n", c[0], c[1], c[2], c[3], c[4], c[5],
name.c_str() );
}
};
Result result;
while( ( result = read_message( fd ) ) == Result::not_done )
;
}
int main( int /*argc*/, char** /*argv*/ )
{
print_all_macs();
return 0;
}