diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-08-27 16:45:24 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-08-27 16:45:24 +0200 |
commit | 4f5f911e81ae6377ab925c1dd133013c640ab32e (patch) | |
tree | f0da3484c737997027a89945e76c047e7de16846 /src | |
parent | 1a04db0fc9d08fffe80d6d7b5b60459295922b11 (diff) |
networkd: propagate DNS/NTP server from uplink to dhcp server
When handing out DHCP leases, try to propagate DNS/NTP server
information from "uplink". The "uplink" is automatically determined as
the network interface with the highest priority default route on it.
Diffstat (limited to 'src')
-rw-r--r-- | src/network/networkd-link.c | 129 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 38 | ||||
-rw-r--r-- | src/network/networkd.h | 2 |
3 files changed, 159 insertions, 10 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 0d85005c8c..ff693ed0fd 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -616,6 +616,96 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda return 1; } +static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) { + _cleanup_free_ struct in_addr *addresses = NULL; + size_t n_addresses = 0, n_allocated = 0; + char **a; + + log_debug("Copying DNS server information from %s", link->ifname); + + if (!link->network) + return 0; + + STRV_FOREACH(a, link->network->dns) { + struct in_addr ia; + + /* Only look for IPv4 addresses */ + if (inet_pton(AF_INET, *a, &ia) <= 0) + continue; + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) + return log_oom(); + + addresses[n_addresses++] = ia; + } + + if (link->network->dhcp_dns && + link->dhcp_lease) { + const struct in_addr *da = NULL; + int n; + + n = sd_dhcp_lease_get_dns(link->dhcp_lease, &da); + if (n > 0) { + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n)) + return log_oom(); + + memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr)); + n_addresses += n; + } + } + + if (n_addresses <= 0) + return 0; + + return sd_dhcp_server_set_dns(s, addresses, n_addresses); +} + +static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) { + _cleanup_free_ struct in_addr *addresses = NULL; + size_t n_addresses = 0, n_allocated = 0; + char **a; + + if (!link->network) + return 0; + + log_debug("Copying NTP server information from %s", link->ifname); + + STRV_FOREACH(a, link->network->ntp) { + struct in_addr ia; + + /* Only look for IPv4 addresses */ + if (inet_pton(AF_INET, *a, &ia) <= 0) + continue; + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) + return log_oom(); + + addresses[n_addresses++] = ia; + } + + if (link->network->dhcp_ntp && + link->dhcp_lease) { + const struct in_addr *da = NULL; + int n; + + n = sd_dhcp_lease_get_ntp(link->dhcp_lease, &da); + if (n > 0) { + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n)) + return log_oom(); + + memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr)); + n_addresses += n; + } + } + + if (n_addresses <= 0) + return 0; + + return sd_dhcp_server_set_ntp(s, addresses, n_addresses); +} + static int link_enter_set_addresses(Link *link) { Address *ad; int r; @@ -642,6 +732,8 @@ static int link_enter_set_addresses(Link *link) { if (link_dhcp4_server_enabled(link)) { struct in_addr pool_start; Address *address; + Link *uplink = NULL; + bool acquired_uplink = false; address = link_find_dhcp_server_address(link); if (!address) { @@ -693,23 +785,40 @@ static int link_enter_set_addresses(Link *link) { if (link->network->dhcp_server_emit_dns) { - if (link->network->n_dhcp_server_dns > 0) { + if (link->network->n_dhcp_server_dns > 0) r = sd_dhcp_server_set_dns(link->dhcp_server, link->network->dhcp_server_dns, link->network->n_dhcp_server_dns); - if (r < 0) - log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m"); - } else - log_link_warning_errno(link, r, "DNS server emitting enabled, but no DNS servers set, ignoring: %m"); + else { + uplink = manager_find_uplink(link->manager, link); + acquired_uplink = true; + + if (!uplink) { + log_link_debug(link, "Not emitting DNS server information on link, couldn't find suitable uplink."); + r = 0; + } else + r = link_push_dns_to_dhcp_server(uplink, link->dhcp_server); + } + if (r < 0) + log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m"); } if (link->network->dhcp_server_emit_ntp) { - if (link->network->n_dhcp_server_ntp > 0) { + if (link->network->n_dhcp_server_ntp > 0) r = sd_dhcp_server_set_ntp(link->dhcp_server, link->network->dhcp_server_ntp, link->network->n_dhcp_server_ntp); - if (r < 0) - log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m"); - } else - log_link_warning_errno(link, r, "NTP server emitting enabled, but no NTP servers set, ignoring: %m"); + else { + if (!acquired_uplink) + uplink = manager_find_uplink(link->manager, link); + + if (!uplink) { + log_link_debug(link, "Not emitting NTP server information on link, couldn't find suitable uplink."); + r = 0; + } else + r = link_push_ntp_to_dhcp_server(uplink, link->dhcp_server); + + } + if (r < 0) + log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m"); } if (link->network->dhcp_server_emit_timezone) { diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index ab89c1bc47..46bcdff1cf 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -34,6 +34,7 @@ #include "def.h" #include "virt.h" #include "set.h" +#include "local-addresses.h" #include "networkd.h" @@ -845,3 +846,40 @@ int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, uni return 0; } + +Link* manager_find_uplink(Manager *m, Link *exclude) { + _cleanup_free_ struct local_address *gateways = NULL; + int n, i; + + assert(m); + + /* Looks for a suitable "uplink", via black magic: an + * interface that is up and where the default route with the + * highest priority points to. */ + + n = local_gateways(m->rtnl, 0, AF_UNSPEC, &gateways); + if (n < 0) { + log_warning_errno(n, "Failed to determine list of default gateways: %m"); + return NULL; + } + + for (i = 0; i < n; i++) { + Link *link; + + link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex)); + if (!link) { + log_debug("Weird, found a gateway for a link we don't now. Ignoring."); + continue; + } + + if (link == exclude) + continue; + + if (link->operstate < LINK_OPERSTATE_ROUTABLE) + continue; + + return link; + } + + return NULL; +} diff --git a/src/network/networkd.h b/src/network/networkd.h index 7122c1b6f4..eea57ac158 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -85,5 +85,7 @@ int manager_save(Manager *m); int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found); +Link* manager_find_uplink(Manager *m, Link *exclude); + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define _cleanup_manager_free_ _cleanup_(manager_freep) |