summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-08-27 16:45:24 +0200
committerLennart Poettering <lennart@poettering.net>2015-08-27 16:45:24 +0200
commit4f5f911e81ae6377ab925c1dd133013c640ab32e (patch)
treef0da3484c737997027a89945e76c047e7de16846 /src
parent1a04db0fc9d08fffe80d6d7b5b60459295922b11 (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.c129
-rw-r--r--src/network/networkd-manager.c38
-rw-r--r--src/network/networkd.h2
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)