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._extparts of the resolver state, they are an internal implementation detail. Thenscount6member 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.confyourself. 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.