Retrieve IPv4 and IPv6 nameservers programmatically

975 Views Asked by At

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?

1

There are 1 best solutions below

5
On BEST ANSWER

You really should not access the _u._ext parts of the resolver state, they are an internal implementation detail. The nscount6 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.