WSL2中使用Rust nix crate查询eth0接口重复显示三次问题
问题:WSL2中用Rust nix crate查询网络接口时eth0重复显示三次
我在WSL 2环境下,使用Rust的nix crate编写代码查询网络接口,代码如下:
let ifaces = nix::ifaddrs::getifaddrs().unwrap(); for iface in ifaces { println!("{:#?}", iface); }
执行后发现eth0被列出三次,其中一次netmask为None,一次broadcast为None。我想知道出现这种重复显示的原因,是否是WSL配置问题?我预期它像执行ip link show的结果一样只显示一次。
三次显示的内容如下:
InterfaceAddress { interface_name: "eth0", flags: IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST | IFF_LOWER_UP | IFF_NO_PI | IFF_TUN | IFF_TAP, address: Some( SockaddrStorage { ss: sockaddr_storage { ss_family: 17, __ss_align: 140736544452160, }, }, ), netmask: None, broadcast: Some( SockaddrStorage { ss: sockaddr_storage { ss_family: 17, __ss_align: 140736544451856, }, }, ), destination: None, } InterfaceAddress { interface_name: "eth0", flags: IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST | IFF_LOWER_UP | IFF_NO_PI | IFF_TUN | IFF_TAP, address: Some( SockaddrStorage { ss: sockaddr_storage { ss_family: 2, __ss_align: 94107083991267, }, }, ), netmask: Some( SockaddrStorage { ss: sockaddr_storage { ss_family: 2, __ss_align: 94107084128296, }, }, ), broadcast: Some( SockaddrStorage { ss: sockaddr_storage { ss_family: 2, __ss_align: 94107084192256, }, }, ), destination: None, } InterfaceAddress { interface_name: "eth0", flags: IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST | IFF_LOWER_UP | IFF_NO_PI | IFF_TUN | IFF_TAP, address: Some( SockaddrStorage { ss: sockaddr_storage { ss_family: 10, __ss_align: 94107083991267, }, }, ), netmask: Some( SockaddrStorage { ss: sockaddr_storage { ss_family: 10, __ss_align: 94107084128296, }, }, ), broadcast: None, destination: None, }
解答
这不是WSL的配置问题,nix::ifaddrs::getifaddrs()本质是调用系统底层的getifaddrs()函数,该函数的设计逻辑就是为每个网络接口的每个协议族地址单独返回一条记录,而ip link show只展示接口本身,不会展开各个协议的地址条目。
逐个解析三条记录的含义:
- 第一条:
ss_family:17对应AF_PACKET(链路层地址),也就是接口的MAC地址相关条目,链路层不需要子网掩码,所以netmask为None,但存在链路层广播地址,因此broadcast有值。 - 第二条:
ss_family:2对应AF_INET(IPv4地址),包含完整的IPv4地址、子网掩码和广播地址,符合IPv4网络的配置特性。 - 第三条:
ss_family:10对应AF_INET6(IPv6地址),IPv6不使用广播地址(改用多播机制),所以broadcast为None,同时包含IPv6地址和前缀长度(对应netmask字段)。
如果想要实现类似ip link show的效果,只显示每个接口一次,需要自己对结果做过滤处理:可以按接口名称分组去重,或者根据协议族筛选特定类型的地址。
示例1:按接口名称去重(保留每个接口的第一条记录)
use std::collections::HashSet; let ifaces = nix::ifaddrs::getifaddrs().unwrap(); let mut seen_interfaces = HashSet::new(); for iface in ifaces { if !seen_interfaces.contains(&iface.interface_name) { println!("{:#?}", iface); seen_interfaces.insert(iface.interface_name); } }
示例2:筛选特定协议族的地址(比如只保留IPv4)
let ifaces = nix::ifaddrs::getifaddrs().unwrap(); for iface in ifaces { if let Some(addr) = iface.address { match addr.ss_family() { nix::sys::socket::AddressFamily::Inet => { println!("{:#?}", iface); } _ => continue, } } }
内容的提问来源于stack exchange,提问作者user14587380
相关产品推荐
相关产品推荐

