【转】Linux下获取第一个网络接口名称的函数实现

本文介绍了iftop程序中如何筛选有效的网络接口进行监听的方法。通过排除本地环回接口(lo)和其他非外部类型接口,确保只监控实际网络流量。代码展示了如何使用if_nameindex获取网络接口列表,并实现了一个简单的函数来过滤不感兴趣的接口。

原文:http://www.linuxdiyf.com/bbs/thread-104036-1-1.html

 

以下代码摘自开源程序--------iftop

/* This is a list of interface name prefixes which are `bad' in the sense
* that they don't refer to interfaces of external type on which we are
* likely to want to listen. We also compare candidate interfaces to lo. */
static char *bad_interface_names[] = {
            "lo:",
            "lo",
            "stf",     /* pseudo-device 6to4 tunnel interface */
            "gif",     /* psuedo-device generic tunnel interface */
            "dummy",
            "vmnet",
            NULL        /* last entry must be NULL */
        };

static int is_bad_interface_name(char *i) {
    char **p;
    for (p = bad_interface_names; *p; ++p)
        if (strncmp(i, *p, strlen(*p)) == 0)
            return 1;
    return 0;
}
    
/* This finds the first interface which is up and is not the loopback
* interface or one of the interface types listed in bad_interface_names. */
static char *get_first_interface(void) {
    struct if_nameindex * nameindex;
    char *i = NULL;
    int j = 0;
    /* Use if_nameindex(3) instead? */

    nameindex = if_nameindex();
    if(nameindex == NULL) {
        return NULL;
    }

    while(nameindex[j].if_index != 0) {
        if (strcmp(nameindex[j].if_name, "lo") != 0 && !is_bad_interface_name(nameindex[j].if_name)) {
            i = xstrdup(nameindex[j].if_name);
            break;
        }
        j++;
    }
    if_freenameindex(nameindex);
    return i;
}
补充说明:

struct if_nameindex

这个变量用于存储单个网络界面的信息,其中具有两个元素:

unsigned int if_index:界面序号

char *if_name:用null结尾的界面名称

struct if_nameindex *if_nameindex(void);

返回一个struct if_nameindex列表,其中存储了所有界面的信息,最后一个if_nameindex的if_index序号为零,if_name为null

此函数得到的结果必需用if_freenameindex函数清除

void if_freenameindex(struct if_nameindex *ptr);

清除if_nameindex得到的结果

<think>我们有两个任务:1.在国产系统中使用C语言编程,通过MAC地址确定第一个网络接口名称(注意是“第一个”,但通常我们根据MAC地址查询,与顺序无关,可能是用户想获取默认接口?但根据MAC地址查接口名,一般与顺序无关。)2.结合nmcli工具实现但是,注意用户之前的问题和我们的回答:之前我们提供了两种方法:一种是解析/sys/class/net,另一种是用nmcli。用户现在要求用nmcli。同时,用户要求是“第一个网络接口名称”。这里可能有两种理解:a)获取所有网络接口,然后取第一个(按字典序?按枚举顺序?)然后获取其MAC地址?但是用户要求根据MAC地址确定名称,所以不应该是这个意思。b)根据给定的MAC地址,查找对应的接口名称,并且如果找到多个,取第一个?但通常一个MAC地址对应一个接口。因此,我们理解为:用户希望用nmcli工具,根据MAC地址查找对应的网络接口名称。我们之前的nmcli方法已经实现了根据MAC地址获取接口名,但是没有强调“第一个”。实际上,正常情况下一个MAC地址对应一个接口,所以不会返回多个。但注意:nmcli输出的顺序可能不是固定的。如果用户希望获取第一个匹配的接口(有可能有多个接口有相同的MAC地址?这是不可能的,所以实际上不会出现多个匹配),我们只需返回第一个即可。因此,我们可以复用之前的方法,但需要调整:之前的nmcli方法中,我们使用了strtok解析每一对设备名和MAC地址,一旦找到匹配就返回。这实际上就是返回第一个匹配的。所以,我们之前的代码已经满足要求。但是,之前提供的nmcli示例代码有一些问题:1.使用了静态缓冲区,这会导致线程不安全,并且只能调用一次。2.解析时假设输出的格式是固定的,但是实际情况可能更复杂(例如可能有多个GENERAL.HWADDR行?但是每个设备只有一行GENERAL.DEVICE和一行GENERAL.HWADDR,所以应该没问题)3.我们使用sscanf解析,但是nmcli的-t参数输出的格式为:GENERAL.DEVICE:loGENERAL.HWADDR:00:00:00:00:00:00或者如果多个字段,我们用冒号分隔,但是这里我们指定了只输出这两个字段,所以每两行为一个设备。然而,我们之前的代码假设每一对都是两行,并且连续出现。实际上,nmcli输出的每个设备的信息有多行,但是我们使用-t-f选项只输出这两个字段,那么每个设备就是两行:一行设备名,一行MAC地址。所以,我们之前的代码逻辑是:读取第一行作为设备名,然后紧挨着的第二行作为MAC地址。然后比较MAC地址,匹配则返回设备名。但是,请注意:nmcli输出的设备顺序可能是任意的。所以如果同一个MAC地址出现在多个设备上(虽然不应该),那么我们返回的是第一个匹配的设备名。另外,我们还需要注意:在国产系统中,确保nmcli可用,并且我们的程序需要有权限执行nmcli(一般不需要root,但某些系统可能要求)。修改代码:-避免使用静态缓冲区,使用动态分配的内存。-更好的错误处理。但是,用户要求是国产系统,如统信UOS、麒麟OS,这些系统都基于Linux,通常都有nmcli。因此,我们提供一个改进版本的nmcli方法。同时,注意用户要求是“第一个”。由于我们的方法一旦找到匹配就返回,所以就是第一个匹配的。代码示例:注意:我们使用popen执行命令,然后逐行解析。但是nmcli输出的设备顺序可能不是按接口名称排序,也不是按网络接口的编号,而是按nmcli内部管理的顺序(通常按设备名称排序?)。所以,如果需要第一个,这样返回也是合理的。由于用户没有定义“第一个”的具体含义,我们按照nmcli输出的顺序,第一个匹配的接口就是“第一个”。以下是代码实现:</think> ### 国产系统C语言通过MAC地址确定网络接口名称(使用nmcli) 下面是在国产系统(如统信UOS、麒麟OS)中使用C语言编程结合`nmcli`工具根据MAC地址获取网络接口名称实现方案: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> // 标准化MAC地址格式(换为小写,统一分隔符) void normalize_mac(char *mac) { char *dst = mac; char *src = mac; while (*src) { if (*src == '-' || *src == ':') { src++; continue; } *dst = tolower(*src); dst++; src++; } *dst = '\0'; } // 执行命令并获取输出 char* exec_cmd(const char* cmd) { FILE* fp = popen(cmd, "r"); if (!fp) return NULL; char buffer[128]; char* result = malloc(1024); *result = '\0'; // 初始化 while (fgets(buffer, sizeof(buffer), fp) != NULL) { strcat(result, buffer); } pclose(fp); return result; } // 通过MAC地址获取接口名(使用nmcli) char* get_interface_by_mac(const char* input_mac) { // 复制并标准化输入的MAC地址 char normalized_mac[18]; strcpy(normalized_mac, input_mac); normalize_mac(normalized_mac); // 构造nmcli命令 char* output = exec_cmd("nmcli -t -f DEVICE,HWADDR device show"); if (!output) return NULL; // 逐行解析输出 char* line = strtok(output, "\n"); while (line) { char* dev_end = strchr(line, ':'); if (!dev_end) { line = strtok(NULL, "\n"); continue; } // 提取设备名和MAC地址 *dev_end = '\0'; char* device_name = line; char* mac_address = dev_end + 1; // 标准化返回的MAC地址 char normalized_cur_mac[18]; strcpy(normalized_cur_mac, mac_address); normalize_mac(normalized_cur_mac); // 比较MAC地址 if (strcmp(normalized_cur_mac, normalized_mac) == 0) { char* result = strdup(device_name); free(output); return result; } line = strtok(NULL, "\n"); } free(output); return NULL; } int main() { // 示例MAC地址(替换为实际MAC) const char* target_mac = "00:11:22:33:44:55"; // 获取接口名 char* iface = get_interface_by_mac(target_mac); if (iface) { printf("MAC地址 %s 对应的接口: %s\n", target_mac, iface); free(iface); } else { printf("未找到MAC地址 %s 对应的网络接口\n", target_mac); } return 0; } ``` ### 实现说明 1. **标准化MAC地址处理**: ```c void normalize_mac(char *mac) { char *dst = mac; char *src = mac; while (*src) { if (*src == '-' || *src == ':') { src++; continue; } *dst = tolower(*src); dst++; src++; } *dst = '\0'; } ``` 此函数统一MAC地址格式(移除分隔符,小写),确保不同格式的输入都能匹配 2. **nmcli命令执行**: ```c char* output = exec_cmd("nmcli -t -f DEVICE,HWADDR device show"); ``` 使用简化格式(`-t`)输出设备名和MAC地址,便于解析 3. **结果解析**: ```c char* dev_end = strchr(line, ':'); *dev_end = '\0'; char* device_name = line; char* mac_address = dev_end + 1; ``` 按行解析命令输出,分离设备名和MAC地址 ### 编译与运行 ```bash # 安装编译依赖 sudo apt install gcc libglib2.0-dev # 编译程序 gcc get_interface.c -o get_interface -lglib-2.0 # 执行查询(MAC地址需替换为实际值) ./get_interface "00:11:22:33:44:55" ``` ### 国产系统适配注意 1. **权限要求**: - 普通用户可直接执行,无需root权限 - 若未安装`NetworkManager`,需自行安装: ```bash sudo apt install network-manager ``` 2. **回退机制**: ```c // 检测nmcli是否存在 if (access("/usr/bin/nmcli", X_OK) == -1) { // 尝试使用/sys/class/net方法 return get_interface_by_sys(mac); } ``` 3. **网络接口状态处理**: ```c // 获取接口状态 char* state_cmd = malloc(strlen(iface) + 50); sprintf(state_cmd, "nmcli -t -f GENERAL.STATE dev show %s", iface); char* state = exec_cmd(state_cmd); // 检查状态是否为activated (connected) ``` 此实现符合国产系统环境要求,通过标准化MAC地址格式和命令输出解析,确保准确匹配网络接口名称[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值