Linux下获取域名服务器列表的非res_(n)init类API及可移植方案咨询
Linux下获取域名服务器列表的可移植方案
1. 使用dns_getservers与dns_setservers(libbind)
这组函数是BIND库提供的标准接口,在Linux、BSD等类UNIX系统中都能兼容,可直接获取当前系统的DNS服务器列表,无需手动解析配置文件或依赖res_init的内部结构体:
#include <arpa/nameser.h> #include <resolv.h> void get_dns_servers() { struct in_addr servers[MAXNS]; int count = dns_getservers(servers, MAXNS); for (int i = 0; i < count; i++) { printf("DNS Server %d: %s\n", i+1, inet_ntoa(servers[i])); } }
编译时需链接BIND库:gcc your_code.c -lbind
2. 标准化配置文件解析
如果选择手动解析配置,可遵循POSIX标准的resolv.conf格式,兼容多数类UNIX系统的配置路径(如Linux、BSD、macOS的/etc/resolv.conf),直接提取nameserver字段即可。这种方法的可移植性源于遵循通用格式,不受特定API限制:
#include <stdio.h> #include <string.h> void parse_resolv_conf() { FILE *fp = fopen("/etc/resolv.conf", "r"); if (!fp) return; char line[256]; while (fgets(line, sizeof(line), fp)) { char *ptr = strtok(line, " \t\n"); if (ptr && strcmp(ptr, "nameserver") == 0) { ptr = strtok(NULL, " \t\n"); if (ptr) { printf("DNS Server: %s\n", ptr); } } } fclose(fp); }
注:使用systemd-resolved、NetworkManager等工具的系统,/etc/resolv.conf通常是动态生成的符号链接,解析结果仍能反映当前生效的DNS配置。
3. 借助res_ninit的标准化用法
你提到的res_(n)init其实具备一定可移植性——只要遵循POSIX标准的resolv.h接口,在多数类UNIX系统中都能通过初始化后的_res结构体获取DNS服务器信息,无需依赖系统特定扩展:
#include <resolv.h> #include <arpa/inet.h> #include <stdio.h> void get_resolv_dns() { struct __res_state res; if (res_ninit(&res) == 0) { for (int i = 0; i < res.nscount; i++) { printf("DNS Server %d: %s\n", i+1, inet_ntoa(res.nsaddr_list[i].sin_addr)); } res_nclose(&res); } }
这种方法避免了直接访问全局_res变量,线程安全性更好,跨平台兼容性也更强。
4. systemd环境下的DBus接口(针对性方案)
如果目标系统统一使用systemd-resolved,可通过DBus API查询动态更新的DNS配置,适用于现代Linux发行版:
#include <dbus/dbus.h> #include <stdint.h> void get_systemd_dns() { DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (!conn) return; DBusMessage *msg = dbus_message_new_method_call( "org.freedesktop.resolve1", "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", "GetLinkDNS" ); uint32_t if_index = 2; // 替换为实际网络接口索引,可通过getifaddrs获取 dbus_message_append_args(msg, DBUS_TYPE_UINT32, &if_index, DBUS_TYPE_INVALID); DBusMessage *reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL); if (reply) { // 此处可解析回复中的DNS服务器数组,需处理DBus的变体类型 dbus_message_unref(reply); } dbus_message_unref(msg); dbus_connection_unref(conn); }
编译时需链接dbus库:gcc your_code.c -ldbus-1
内容的提问来源于stack exchange,提问作者yvs2014
相关产品推荐
相关产品推荐

