You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过pcap动态获取Ubuntu系统的有线以太网接口名称

动态获取有线以太网接口名称的几种方案

针对你用pcap库开发链路层应用、需要替换硬编码接口名的需求,这里有几个可靠的实现思路,都是适配Ubuntu 16.04这类采用systemd可预测命名的系统的:

方案1:利用pcap库自身的接口枚举(推荐,跨平台友好)

pcap本身提供了枚举系统所有网络接口的API,你可以遍历这些接口,筛选出符合有线以太网特征的接口。判断依据可以是:

  • 接口处于UP状态(避免选到禁用的接口)
  • 接口类型是以太网(通过检查链路层类型为DLT_EN10MB)
  • 排除无线接口(比如名字包含wlan/wlp前缀,systemd命名的无线接口大多是这类开头)

代码示例

#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define ETH_SNAPLEN 65536
#define ETH_PROMISCUOUS 1
#define ETH_TIMEOUT 1000

char* get_wired_eth_interface() {
    pcap_if_t *alldevs, *d;
    char errbuf[PCAP_ERRBUF_SIZE];
    char* target_iface = NULL;

    // 获取所有网络接口列表
    if (pcap_findalldevs(&alldevs, errbuf) == -1) {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        return NULL;
    }

    // 遍历接口筛选目标
    for (d = alldevs; d != NULL; d = d->next) {
        // 跳过非活跃接口
        if (!(d->flags & PCAP_IF_UP)) continue;

        // 临时打开接口判断是否为以太网类型
        pcap_t* temp_pcap = pcap_open_live(d->name, ETH_SNAPLEN, 0, ETH_TIMEOUT, errbuf);
        if (!temp_pcap) continue;

        if (pcap_datalink(temp_pcap) == DLT_EN10MB) {
            // 排除无线接口
            if (strncmp(d->name, "wlp", 3) != 0 && strncmp(d->name, "wlan", 4) != 0) {
                target_iface = strdup(d->name);
                pcap_close(temp_pcap);
                break;
            }
        }
        pcap_close(temp_pcap);
    }

    pcap_freealldevs(alldevs);
    return target_iface;
}

// 调用示例
int main() {
    char* iface = get_wired_eth_interface();
    if (iface) {
        printf("Found wired eth interface: %s\n", iface);
        // 这里替换硬编码的接口名执行后续逻辑
        pcap_t* pcap = pcap_open_live(iface, ETH_SNAPLEN, ETH_PROMISCUOUS, ETH_TIMEOUT, errbuf);
        free(iface); // 记得释放内存
    } else {
        fprintf(stderr, "No valid wired eth interface found\n");
    }
    return 0;
}

方案2:读取Linux sysfs文件(Linux专属,高效直接)

Linux的sysfs文件系统(/sys/class/net/)存储了所有网络接口的底层信息,我们可以遍历目录下的接口,通过以下规则判断:

  • /sys/class/net/<iface>/type 文件内容为1(以太网的类型标识)
  • 不存在/sys/class/net/<iface>/wireless目录(排除无线接口)
  • 可选:/sys/class/net/<iface>/carrier 文件内容为1(接口已连接网线)

代码示例

#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* get_wired_eth_interface_sysfs() {
    DIR* dir = opendir("/sys/class/net/");
    struct dirent* entry;
    char* target_iface = NULL;

    if (!dir) {
        perror("Failed to access /sys/class/net/");
        return NULL;
    }

    while ((entry = readdir(dir)) != NULL) {
        // 跳过.和..目录
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        // 检查是否为以太网类型
        char type_path[1024];
        snprintf(type_path, sizeof(type_path), "/sys/class/net/%s/type", entry->d_name);
        FILE* type_file = fopen(type_path, "r");
        if (!type_file) continue;

        int type;
        fscanf(type_file, "%d", &type);
        fclose(type_file);
        if (type != 1) continue;

        // 排除无线接口
        char wireless_path[1024];
        snprintf(wireless_path, sizeof(wireless_path), "/sys/class/net/%s/wireless", entry->d_name);
        DIR* wireless_dir = opendir(wireless_path);
        if (wireless_dir) {
            closedir(wireless_dir);
            continue;
        }

        // 可选:检查接口是否已连接
        char carrier_path[1024];
        snprintf(carrier_path, sizeof(carrier_path), "/sys/class/net/%s/carrier", entry->d_name);
        FILE* carrier_file = fopen(carrier_path, "r");
        if (carrier_file) {
            int carrier;
            fscanf(carrier_file, "%d", &carrier);
            fclose(carrier_file);
            if (carrier != 1) continue;
        }

        // 找到目标接口,复制名称
        target_iface = strdup(entry->d_name);
        break;
    }

    closedir(dir);
    return target_iface;
}

方案3:解析ip link命令输出(快速原型,依赖命令格式)

如果不想写复杂的系统调用,也可以执行ip link show命令,解析输出内容找到link/ether类型的接口,同时排除无线接口名称。

代码示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* get_wired_eth_interface_ipcmd() {
    FILE* pipe = popen("ip link show", "r");
    if (!pipe) {
        perror("Failed to run ip link command");
        return NULL;
    }

    char line[256];
    char* target_iface = NULL;
    char current_iface[64];

    while (fgets(line, sizeof(line), pipe) != NULL) {
        // 提取接口名称(格式:X: <iface>: ...)
        if (sscanf(line, "%*d: %[^:]:", current_iface) == 1) {
            // 检查下一行是否包含以太网标识
            if (fgets(line, sizeof(line), pipe) != NULL) {
                if (strstr(line, "link/ether") != NULL) {
                    // 排除无线接口
                    if (strncmp(current_iface, "wlp", 3) != 0 && strncmp(current_iface, "wlan", 4) != 0) {
                        target_iface = strdup(current_iface);
                        break;
                    }
                }
            }
        }
    }

    pclose(pipe);
    return target_iface;
}

选择建议

  • 如果你的应用需要跨平台(比如后续要适配Windows/macOS),优先选方案1,pcap的API是跨平台兼容的。
  • 如果只针对Linux系统,方案2最高效,不需要依赖外部命令或额外的pcap调用,直接读取系统底层文件。
  • 方案3适合快速原型开发,但要注意ip命令的输出格式可能在不同系统版本有细微变化,稳定性稍差。

内容的提问来源于stack exchange,提问作者bph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:51:39