Rust网络接口信息获取库get_if_addrs-sys的使用,高效获取和管理系统网络接口地址信息

Rust网络接口信息获取库get_if_addrs-sys的使用,高效获取和管理系统网络接口地址信息

安装方法

在项目目录中运行以下Cargo命令:

cargo add get_if_addrs-sys

或者在Cargo.toml中添加以下行:

get_if_addrs-sys = "0.1.1"

基本使用示例

以下是使用get_if_addrs-sys库获取网络接口信息的完整示例代码:

extern crate libc;
extern crate get_if_addrs_sys;

use std::mem;
use std::ptr;

fn main() {
    unsafe {
        // 获取接口列表
        let mut interfaces: *mut get_if_addrs_sys::ifaddrs = ptr::null_mut();
        if get_if_addrs_sys::getifaddrs(&mut interfaces) != 0 {
            panic!("Failed to get network interfaces");
        }
        
        // 遍历接口列表
        let mut current = interfaces;
        while !current.is_null() {
            let ifa = *current;
            let name = String::from_utf8_lossy(std::ffi::CStr::from_ptr(ifa.ifa_name).to_bytes());
            
            println!("Interface: {}", name);
            
            // 检查地址类型
            if !ifa.ifa_addr.is_null() {
                let sa_family = (*ifa.ifa_addr).sa_family as i32;
                
                match sa_family {
                    libc::AF_INET => {
                        let sockaddr: *mut libc::sockaddr_in = ifa.ifa_addr as *mut _;
                        let addr = (*sockaddr).sin_addr.s_addr;
                        println!("  IPv4 Address: {}.{}.{}.{}", 
                            (addr & 0xff) as u8,
                            ((addr >> 8) & 0xff) as u8,
                            ((addr >> 16) & 0xff) as u8,
                            ((addr >> 24) & 0xff) as u8);
                    },
                    libc::AF_INET6 => {
                        let sockaddr: *mut libc::sockaddr_in6 = ifa.ifa_addr as *mut _;
                        let addr = (*sockaddr).sin6_addr.s6_addr;
                        println!("  IPv6 Address: {:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}",
                            addr[0], addr[1], addr[2], addr[3],
                            addr[4], addr[5], addr[6], addr[7],
                            addr[8], addr[9], addr[10], addr[11],
                            addr[12], addr[13], addr[14], addr[15]);
                    },
                    _ => println!("  Unknown address family: {}", sa_family),
                }
            }
            
            current = ifa.ifa_next;
        }
        
        // 释放接口列表
        get_if_addrs-sys::freeifaddrs(interfaces);
    }
}

代码说明

  1. 首先调用getifaddrs函数获取网络接口列表
  2. 遍历返回的接口链表,打印每个接口的名称
  3. 根据地址族类型(AF_INET/AF_INET6)解析IP地址
  4. 最后调用freeifaddrs释放分配的内存

注意事项

  • 这是一个底层系统接口的Rust绑定,使用时需要注意内存安全
  • 示例中使用了unsafe代码块,因为直接调用C函数
  • 需要处理可能的错误情况,如获取接口失败等

完整示例代码

以下是一个更完整的示例,包含了错误处理和更详细的网络接口信息输出:

extern crate libc;
extern crate get_if_addrs_sys;

use std::ffi::CStr;
use std::ptr;
use std::process;

fn main() {
    unsafe {
        // 获取网络接口列表
        let mut ifaddr: *mut get_if_addrs_sys::ifaddrs = ptr::null_mut();
        
        // 检查getifaddrs调用是否成功
        if get_if_addrs_sys::getifaddrs(&mut ifaddr) == -1 {
            eprintln!("错误: 无法获取网络接口列表");
            process::exit(1);
        }
        
        // 遍历接口链表
        let mut current = ifaddr;
        while !current.is_null() {
            let ifa = *current;
            
            // 获取接口名称
            let name = CStr::from_ptr(ifa.ifa_name).to_string_lossy();
            println!("接口名称: {}", name);
            
            // 检查是否有地址信息
            if !ifa.ifa_addr.is_null() {
                let sa_family = (*ifa.ifa_addr).sa_family as i32;
                
                match sa_family {
                    libc::AF_INET => {
                        // IPv4地址处理
                        let sockaddr = ifa.ifa_addr as *mut libc::sockaddr_in;
                        let addr = (*sockaddr).sin_addr.s_addr;
                        println!("  类型: IPv4");
                        println!("  地址: {}.{}.{}.{}",
                            (addr & 0xff) as u8,
                            ((addr >> 8) & 0xff) as u8,
                            ((addr >> 16) & 0xff) as u8,
                            ((addr >> 24) & 0xff) as u8);
                    },
                    libc::AF_INET6 => {
                        // IPv6地址处理
                        let sockaddr = ifa.ifa_addr as *mut libc::sockaddr_in6;
                        let addr = (*sockaddr).sin6_addr.s6_addr;
                        println!("  类型: IPv6");
                        println!("  地址: {:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}",
                            addr[0], addr[1], addr[2], addr[3],
                            addr[4], addr[5], addr[6], addr[7],
                            addr[8], addr[9], addr[10], addr[11],
                            addr[12], addr[13], addr[14], addr[15]);
                    },
                    libc::AF_PACKET => {
                        // 链路层地址处理
                        println!("  类型: 链路层(如以太网)");
                    },
                    _ => {
                        println!("  未知地址类型: {}", sa_family);
                    }
                }
            }
            
            // 检查是否有网络掩码
            if !ifa.ifa_netmask.is_null() {
                println!("  有网络掩码信息");
            }
            
            // 检查是否有广播地址
            if (ifa.ifa_flags & libc::IFF_BROADCAST as u32) != 0 && !ifa.ifa_ifu.is_null() {
                println!("  有广播地址信息");
            }
            
            // 移动到下一个接口
            current = ifa.ifa_next;
            println!("----------------------------------------");
        }
        
        // 释放接口列表内存
        get_if_addrs_sys::freeifaddrs(ifaddr);
    }
}

这个完整示例增加了以下功能:

  1. 更详细的错误处理
  2. 显示网络掩码和广播地址信息
  3. 支持更多地址类型(如链路层)
  4. 更清晰的输出格式
  5. 处理了更多网络接口标志

1 回复

Rust网络接口信息获取库get_if_addrs-sys使用指南

概述

get_if_addrs-sys是Rust的一个底层系统绑定库,用于获取系统的网络接口地址信息。它提供了跨平台的能力来枚举网络接口及其关联的IP地址。

主要特性

  • 跨平台支持(Linux, macOS, Windows等)
  • 获取所有网络接口的详细信息
  • 支持IPv4和IPv6地址
  • 轻量级的系统级绑定

安装

在Cargo.toml中添加依赖:

[dependencies]
get_if_addrs-sys = "0.1"

基本使用方法

extern crate get_if_addrs_sys;

fn main() {
    unsafe {
        let mut ifap: *mut get_if_addrs_sys::ifaddrs = std::ptr::null_mut();
        
        // 获取接口列表
        if get_if_addrs_sys::getifaddrs(&mut ifap) != 0 {
            eprintln!("Failed to get interface addresses");
            return;
        }
        
        // 遍历接口列表
        let mut ifa = ifap;
        while !ifa.is_null() {
            let current = *ifa;
            
            // 获取接口名称
            let name = std::ffi::CStr::from_ptr(current.ifa_name)
                .to_string_lossy()
                .into_owned();
            
            println!("Interface: {}", name);
            
            // 检查地址族并打印IP地址
            if !current.ifa_addr.is_null() {
                let addr = *current.ifa_addr;
                match addr.sa_family as i32 {
                    get_if_addrs_sys::AF_INET => {
                        let sockaddr_in: &get_if_addrs_sys::sockaddr_in = 
                            &*(current.ifa_addr as *const get_if_addrs_sys::sockaddr_in);
                        let ip = u32::from_be(sockaddr_in.sin_addr.s_addr);
                        println!("  IPv4: {}.{}.{}.{}", 
                            (ip >> 24) & 0xff,
                            (ip >> 16) & 0xff,
                            (ip >> 8) & 0xff,
                            ip & 0xff);
                    },
                    get_if_addrs_sys::AF_INET6 => {
                        let sockaddr_in6: &get_if_addrs_sys::sockaddr_in6 = 
                            &*(current.ifa_addr as *const get_if_addrs_sys::sockaddr_in6);
                        let segments = sockaddr_in6.sin6_addr.s6_addr;
                        println!("  IPv6: {:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}",
                            segments[0], segments[1], segments[2], segments[3],
                            segments[4], segments[5], segments[6], segments[7]);
                    },
                    _ => {}
                }
            }
            
            ifa = current.ifa_next;
        }
        
        // 释放接口列表
        get_if_addrs_sys::freeifaddrs(ifap);
    }
}

高级封装

由于get_if_addrs-sys是底层绑定,通常我们会使用更高级的封装库如get_if_addrs

use get_if_addrs::{get_if_addrs, IfAddr};

fn main() {
    match get_if_addrs() {
        Ok(interfaces) => {
            for interface in interfaces {
                println!("{}:", interface.name);
                match interface.addr {
                    IfAddr::V4(addr) => {
                        println!("  IPv4: {}", addr.ip);
                        println!("  Netmask: {}", addr.netmask);
                        println!("  Broadcast: {:?}", addr.broadcast);
                    },
                    IfAddr::V6(addr) => {
                        println!("  IPv6: {}", addr.ip);
                        println!("  Netmask: {}", addr.netmask);
                    }
                }
            }
        },
        Err(e) => println!("Error: {}", e),
    }
}

完整示例

下面是一个结合了基本使用方法和高级封装的完整示例,展示了如何获取并打印网络接口信息:

// 使用高级封装库的示例
use get_if_addrs::{get_if_addrs, IfAddr};

fn print_interface_info() {
    println!("=== 使用高级封装库获取网络接口信息 ===");
    match get_if_addrs() {
        Ok(interfaces) => {
            for interface in interfaces {
                println!("\n接口名称: {}", interface.name);
                match interface.addr {
                    IfAddr::V4(addr) => {
                        println!("  类型: IPv4");
                        println!("  IP地址: {}", addr.ip);
                        println!("  子网掩码: {}", addr.netmask);
                        if let Some(broadcast) = addr.broadcast {
                            println!("  广播地址: {}", broadcast);
                        }
                    },
                    IfAddr::V6(addr) => {
                        println!("  类型: IPv6");
                        println!("  IP地址: {}", addr.ip);
                        println!("  子网掩码: {}", addr.netmask);
                    }
                }
            }
        },
        Err(e) => println!("获取接口信息失败: {}", e),
    }
}

// 使用底层系统绑定的示例
extern crate get_if_addrs_sys;
use std::ffi::CStr;

fn print_raw_interface_info() {
    println!("\n=== 使用底层系统绑定获取网络接口信息 ===");
    unsafe {
        let mut ifap: *mut get_if_addrs_sys::ifaddrs = std::ptr::null_mut();
        
        if get_if_addrs_sys::getifaddrs(&mut ifap) != 0 {
            eprintln!("获取接口地址失败");
            return;
        }
        
        let mut ifa = ifap;
        while !ifa.is_null() {
            let current = *ifa;
            let name = CStr::from_ptr(current.ifa_name)
                .to_string_lossy()
                .into_owned();
            
            println!("\n接口名称: {}", name);
            
            if !current.ifa_addr.is_null() {
                let addr = *current.ifa_addr;
                match addr.sa_family as i32 {
                    get_if_addrs_sys::AF_INET => {
                        println!("  类型: IPv4");
                        let sockaddr_in: &get_if_addrs_sys::sockaddr_in = 
                            &*(current.ifa_addr as *const get_if_addrs_sys::sockaddr_in);
                        let ip = u32::from_be(sockaddr_in.sin_addr.s_addr);
                        println!("  IP地址: {}.{}.{}.{}", 
                            (ip >> 24) & 0xff,
                            (ip >> 16) & 0xff,
                            (ip >> 8) & 0xff,
                            ip & 0xff);
                    },
                    get_if_addrs_sys::AF_INET6 => {
                        println!("  类型: IPv6");
                        let sockaddr_in6: &get_if_addrs_sys::sockaddr_in6 = 
                            &*(current.ifa_addr as *const get_if_addrs_sys::sockaddr_in6);
                        let segments = sockaddr_in6.sin6_addr.s6_addr;
                        println!("  IP地址: {:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}",
                            segments[0], segments[1], segments[2], segments[3],
                            segments[4], segments[5], segments[6], segments[7]);
                    },
                    _ => println!("  未知地址类型")
                }
            }
            
            ifa = current.ifa_next;
        }
        
        get_if_addrs_sys::freeifaddrs(ifap);
    }
}

fn main() {
    print_interface_info();
    print_raw_interface_info();
}

注意事项

  1. get_if_addrs-sys是unsafe的,使用时需要谨慎
  2. 记得调用freeifaddrs释放资源
  3. 在生产环境中建议使用更高级的封装库
  4. 不同平台的网络接口表现可能有所不同

应用场景

  • 网络监控工具
  • 系统诊断工具
  • 需要根据网络接口做决策的应用程序
  • 网络配置管理工具

这个库为Rust程序提供了访问系统网络接口信息的底层能力,是构建网络相关工具的基础组件之一。

回到顶部