network: Serialize DNR servers

Implement serialization/deserialization for DNR servers. This re-uses
the string format in place for user configuration of DoT servers, and as
a consequence non-DoT servers are discarded when recording the link
configuration, for correctness.

This also enables sd-resolved to use these servers as it would other DNS
servers.
This commit is contained in:
Ronan Pigott 2024-01-16 00:04:41 -07:00
parent b0e716310d
commit 3fd6708cde
6 changed files with 105 additions and 5 deletions

View File

@ -1290,6 +1290,14 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
fputc('\n', f); fputc('\n', f);
} }
sd_dns_resolver *resolvers;
r = sd_dhcp_lease_get_dnr(lease, &resolvers);
if (r > 0) {
fputs("DNR=", f);
serialize_dnr(f, resolvers, r, NULL);
fputc('\n', f);
}
r = sd_dhcp_lease_get_ntp(lease, &addresses); r = sd_dhcp_lease_get_ntp(lease, &addresses);
if (r > 0) { if (r > 0) {
fputs("NTP=", f); fputs("NTP=", f);
@ -1398,6 +1406,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
*next_server = NULL, *next_server = NULL,
*broadcast = NULL, *broadcast = NULL,
*dns = NULL, *dns = NULL,
*dnr = NULL,
*ntp = NULL, *ntp = NULL,
*sip = NULL, *sip = NULL,
*pop3 = NULL, *pop3 = NULL,
@ -1435,6 +1444,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
"NEXT_SERVER", &next_server, "NEXT_SERVER", &next_server,
"BROADCAST", &broadcast, "BROADCAST", &broadcast,
"DNS", &dns, "DNS", &dns,
"DNR", &dnr,
"NTP", &ntp, "NTP", &ntp,
"SIP", &sip, "SIP", &sip,
"POP3", &pop3, "POP3", &pop3,
@ -1537,6 +1547,13 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
lease->servers[SD_DHCP_LEASE_DNS].size = r; lease->servers[SD_DHCP_LEASE_DNS].size = r;
} }
if (dnr) {
r = deserialize_dnr(&lease->dnr, dnr);
if (r < 0)
log_debug_errno(r, "Failed to deserialize DNR servers %s, ignoring: %m", dnr);
lease->n_dnr = r;
}
if (ntp) { if (ntp) {
r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_NTP].addr, ntp); r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_NTP].addr, ntp);
if (r < 0) if (r < 0)

View File

@ -1558,7 +1558,7 @@ static int dhcp4_configure(Link *link) {
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m"); return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m");
} }
if (network_dhcp_use_dnr(link->network)) { if (link_get_use_dnr(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_V4_DNR); r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_V4_DNR);
if (r < 0) if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for DNR: %m"); return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for DNR: %m");

View File

@ -94,6 +94,31 @@ bool link_get_use_dns(Link *link, NetworkConfigSource proto) {
return true; return true;
} }
bool link_get_use_dnr(Link *link, NetworkConfigSource proto) {
int n;
assert(link);
if (!link->network)
return false;
switch (proto) {
case NETWORK_CONFIG_SOURCE_DHCP4:
n = link->network->dhcp_use_dnr;
break;
default:
assert_not_reached();
}
/* If set explicitly, use that */
if (n >= 0)
return n;
/* Otherwise, default to the same as the UseDNS setting. After all,
* this is just another way for the server to tell us about DNS configuration. */
return link_get_use_dns(link, proto);
}
int config_parse_domains( int config_parse_domains(
const char *unit, const char *unit,
const char *filename, const char *filename,

View File

@ -17,6 +17,7 @@ typedef enum UseDomains {
UseDomains link_get_use_domains(Link *link, NetworkConfigSource proto); UseDomains link_get_use_domains(Link *link, NetworkConfigSource proto);
bool link_get_use_dns(Link *link, NetworkConfigSource proto); bool link_get_use_dns(Link *link, NetworkConfigSource proto);
bool link_get_use_dnr(Link *link, NetworkConfigSource proto);
const char* use_domains_to_string(UseDomains p) _const_; const char* use_domains_to_string(UseDomains p) _const_;
UseDomains use_domains_from_string(const char *s) _pure_; UseDomains use_domains_from_string(const char *s) _pure_;

View File

@ -421,10 +421,6 @@ int network_load(Manager *manager, OrderedHashmap **networks);
int network_reload(Manager *manager); int network_reload(Manager *manager);
int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename); int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename);
int network_verify(Network *network); int network_verify(Network *network);
static inline int network_dhcp_use_dnr(Network *network) {
assert(network);
return network->dhcp_use_dnr < 0 ? network->dhcp_use_dns : network->dhcp_use_dnr;
}
int manager_build_dhcp_pd_subnet_ids(Manager *manager); int manager_build_dhcp_pd_subnet_ids(Manager *manager);

View File

@ -114,6 +114,24 @@ static int link_put_dns(Link *link, OrderedSet **s) {
} }
} }
if (link->dhcp_lease && link_get_use_dnr(link, NETWORK_CONFIG_SOURCE_DHCP4)) {
sd_dns_resolver *resolvers;
r = sd_dhcp_lease_get_dnr(link->dhcp_lease, &resolvers);
if (r >= 0) {
struct in_addr_full **dot_servers;
size_t n = 0;
CLEANUP_ARRAY(dot_servers, n, in_addr_full_array_free);
r = dns_resolvers_to_dot_addrs(resolvers, r, &dot_servers, &n);
if (r < 0)
return r;
r = ordered_set_put_dns_servers(s, link->ifindex, dot_servers, n);
if (r < 0)
return r;
}
}
if (link->dhcp6_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP6)) { if (link->dhcp6_lease && link_get_use_dns(link, NETWORK_CONFIG_SOURCE_DHCP6)) {
const struct in6_addr *addresses; const struct in6_addr *addresses;
@ -523,6 +541,42 @@ static void serialize_addresses(
fputc('\n', f); fputc('\n', f);
} }
static void serialize_resolvers(
FILE *f,
const char *lvalue,
bool *space,
sd_dhcp_lease *lease,
bool conditional) {
bool _space = false;
if (!space)
space = &_space;
if (lvalue)
fprintf(f, "%s=", lvalue);
if (lease && conditional) {
sd_dns_resolver *resolvers;
_cleanup_strv_free_ char **names = NULL;
int r;
r = sd_dhcp_lease_get_dnr(lease, &resolvers);
if (r < 0)
return (void) log_warning_errno(r, "Failed to get DNR from DHCP lease, ignoring.");
r = dns_resolvers_to_dot_strv(resolvers, r, &names);
if (r < 0)
return (void) log_warning_errno(r, "Failed to get DoT servers from DHCP DNR, ignoring.");
if (r > 0)
fputstrv(f, names, NULL, space);
}
if (lvalue)
fputc('\n', f);
return;
}
static void link_save_domains(Link *link, FILE *f, OrderedSet *static_domains, UseDomains use_domains) { static void link_save_domains(Link *link, FILE *f, OrderedSet *static_domains, UseDomains use_domains) {
bool space = false; bool space = false;
const char *p; const char *p;
@ -666,6 +720,13 @@ static int link_save(Link *link) {
space = false; space = false;
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space); link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
/* DNR resolvers are not required to provide Do53 service, however resolved doesn't
* know how to handle such a server so for now Do53 service is required, and
* assumed. */
serialize_resolvers(f, NULL, &space,
link->dhcp_lease,
link_get_use_dnr(link, NETWORK_CONFIG_SOURCE_DHCP4));
serialize_addresses(f, NULL, &space, serialize_addresses(f, NULL, &space,
NULL, NULL,
link->dhcp_lease, link->dhcp_lease,