I'm trying to use libresolv to read both the IPv4 and IPv6 nameservers in my /etc/resolv.conf
file:
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
# 127.0.0.53 is the systemd-resolved stub resolver.
# run "systemd-resolve --status" to see details about the actual nameservers.
nameserver 127.0.0.53
nameserver 2001:4860:4860:0:0:0:0:8888
This is my C program:
#include <resolv.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
res_state res = malloc(sizeof(struct __res_state));
res_ninit(res);
printf("IPv4 nscount: %d\n", res->nscount);
printf("IPv6 nscount6: %d\n", res->_u._ext.nscount6);
return 0;
}
Which produces this output:
IPv4 nscount: 2
IPv6 nscount6: 0
Which surprises me. Why is it counting the IPv6 address as an IPv4 address?
GDB shows that the second address is zeroed out:
(gdb) display res.nsaddr_list[0]
5: res.nsaddr_list[0] = {sin_family = 2, sin_port = 13568, sin_addr = {s_addr = 889192575}, sin_zero = "\000\000\000\000\000\000\000"}
(gdb) display res.nsaddr_list[1]
6: res.nsaddr_list[1] = {sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0}, sin_zero = "\000\000\000\000\000\000\000"}
Can anyone help me understand this behavior?
You really should not access the
_u._ext
parts of the resolver state, they are an internal implementation detail. Thenscount6
member is currently unused and always zero. It had to be kept to avoid changing the ABI as the result of struct offset/size changes.If you need the nameserver list, you should parse
/etc/resolv.conf
yourself. Note that eventually, glibc will also support more than three name servers, and those extra resolvers will not be reflected in the public resolver state.