summaryrefslogtreecommitdiff
path: root/src/network/networkd-link.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/networkd-link.c')
-rw-r--r--src/network/networkd-link.c407
1 files changed, 366 insertions, 41 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index f20f68b482..aa09065cf5 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -29,7 +29,10 @@
#include "socket-util.h"
#include "bus-util.h"
#include "udev-util.h"
+#include "netlink-util.h"
+#include "dhcp-lease-internal.h"
#include "network-internal.h"
+
#include "networkd-link.h"
#include "networkd-netdev.h"
@@ -498,8 +501,13 @@ void link_client_handler(Link *link) {
!link->ipv4ll_route)
return;
- if (link_dhcp4_enabled(link) && !link->dhcp4_configured)
- return;
+ if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured) ||
+ (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
+ !link->dhcp6_configured) ||
+ (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured && !link->dhcp6_configured))
+ return;
if (link->state != LINK_STATE_CONFIGURED)
link_enter_configured(link);
@@ -613,6 +621,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;
@@ -637,8 +735,9 @@ static int link_enter_set_addresses(Link *link) {
/* now that we can figure out a default address for the dhcp server,
start it */
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) {
@@ -647,16 +746,9 @@ static int link_enter_set_addresses(Link *link) {
return 0;
}
- r = sd_dhcp_server_set_address(link->dhcp_server,
- &address->in_addr.in,
- address->prefixlen);
- if (r < 0)
- return r;
-
- /* offer 32 addresses starting from the address following the server address */
- pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1);
- r = sd_dhcp_server_set_lease_pool(link->dhcp_server,
- &pool_start, 32);
+ /* use the server address' subnet as the pool */
+ r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen,
+ link->network->dhcp_server_pool_offset, link->network->dhcp_server_pool_size);
if (r < 0)
return r;
@@ -665,13 +757,83 @@ static int link_enter_set_addresses(Link *link) {
&main_address->in_addr.in);
if (r < 0)
return r;
-
- r = sd_dhcp_server_set_prefixlen(link->dhcp_server,
- main_address->prefixlen);
- if (r < 0)
- return r;
*/
+ if (link->network->dhcp_server_max_lease_time_usec > 0) {
+ r = sd_dhcp_server_set_max_lease_time(
+ link->dhcp_server,
+ DIV_ROUND_UP(link->network->dhcp_server_max_lease_time_usec, USEC_PER_SEC));
+ if (r < 0)
+ return r;
+ }
+
+ if (link->network->dhcp_server_default_lease_time_usec > 0) {
+ r = sd_dhcp_server_set_default_lease_time(
+ link->dhcp_server,
+ DIV_ROUND_UP(link->network->dhcp_server_default_lease_time_usec, USEC_PER_SEC));
+ if (r < 0)
+ return r;
+ }
+
+ if (link->network->dhcp_server_emit_dns) {
+
+ 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);
+ 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)
+ r = sd_dhcp_server_set_ntp(link->dhcp_server, link->network->dhcp_server_ntp, link->network->n_dhcp_server_ntp);
+ 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) {
+ _cleanup_free_ char *buffer = NULL;
+ const char *tz = NULL;
+
+ if (link->network->dhcp_server_timezone)
+ tz = link->network->dhcp_server_timezone;
+ else {
+ r = get_timezone(&buffer);
+ if (r < 0)
+ log_warning_errno(r, "Failed to determine timezone: %m");
+ else
+ tz = buffer;
+ }
+
+ if (tz) {
+ r = sd_dhcp_server_set_timezone(link->dhcp_server, tz);
+ if (r < 0)
+ return r;
+ }
+ }
+
r = sd_dhcp_server_start(link->dhcp_server);
if (r < 0) {
log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m");
@@ -743,7 +905,7 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
_cleanup_link_unref_ Link *link = userdata;
- int r;
+ const sd_bus_error *e;
assert(m);
assert(link);
@@ -751,21 +913,20 @@ static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
- r = sd_bus_message_get_errno(m);
- if (r > 0)
- log_link_warning_errno(link, r, "Could not set hostname: %m");
+ e = sd_bus_message_get_error(m);
+ if (e)
+ log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message);
return 1;
}
int link_set_hostname(Link *link, const char *hostname) {
- int r = 0;
+ int r;
assert(link);
assert(link->manager);
- assert(hostname);
- log_link_debug(link, "Setting transient hostname: '%s'", hostname);
+ log_link_debug(link, "Setting transient hostname: '%s'", strna(hostname));
if (!link->manager->bus) {
/* TODO: replace by assert when we can rely on kdbus */
@@ -794,6 +955,57 @@ int link_set_hostname(Link *link, const char *hostname) {
return 0;
}
+static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ _cleanup_link_unref_ Link *link = userdata;
+ const sd_bus_error *e;
+
+ assert(m);
+ assert(link);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ e = sd_bus_message_get_error(m);
+ if (e)
+ log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message);
+
+ return 1;
+}
+
+int link_set_timezone(Link *link, const char *tz) {
+ int r;
+
+ assert(link);
+ assert(link->manager);
+ assert(tz);
+
+ log_link_debug(link, "Setting system timezone: '%s'", tz);
+
+ if (!link->manager->bus) {
+ log_link_info(link, "Not connected to system bus, ignoring timezone.");
+ return 0;
+ }
+
+ r = sd_bus_call_method_async(
+ link->manager->bus,
+ NULL,
+ "org.freedesktop.timedate1",
+ "/org/freedesktop/timedate1",
+ "org.freedesktop.timedate1",
+ "SetTimezone",
+ set_timezone_handler,
+ link,
+ "sb",
+ tz,
+ false);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set timezone: %m");
+
+ link_ref(link);
+
+ return 0;
+}
+
static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -905,13 +1117,16 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
assert(link->network);
assert(link->manager);
- if (event != UPDATE_INFO)
- return;
-
- r = sd_lldp_save(link->lldp, link->lldp_file);
- if (r < 0)
- log_link_warning_errno(link, r, "Could not save LLDP: %m");
+ switch (event) {
+ case SD_LLDP_EVENT_UPDATE_INFO:
+ r = sd_lldp_save(link->lldp, link->lldp_file);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Could not save LLDP: %m");
+ break;
+ default:
+ break;
+ }
}
static int link_acquire_conf(Link *link) {
@@ -1582,6 +1797,45 @@ static int link_set_ipv6_privacy_extensions(Link *link) {
return 0;
}
+static int link_set_ipv6_accept_ra(Link *link) {
+ const char *p = NULL, *v = NULL;
+ int r;
+
+ /* Make this a NOP if IPv6 is not available */
+ if (!socket_ipv6_is_supported())
+ return 0;
+
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
+ /* If unset use system default (enabled if local forwarding is disabled.
+ * disabled if local forwarding is enabled).
+ * If set, ignore or enforce RA independent of local forwarding state.
+ */
+ if (link->network->ipv6_accept_ra < 0)
+ /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
+ v = "1";
+ else if (link->network->ipv6_accept_ra > 0)
+ /* "2" means accept RA even if ip_forward is enabled */
+ v = "2";
+ else
+ /* "0" means ignore RA */
+ v = "0";
+
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
+
+ r = write_string_file(p, v, 0);
+ if (r < 0) {
+ /* If the right value is set anyway, don't complain */
+ if (verify_one_line_file(p, v) > 0)
+ return 0;
+
+ log_link_warning_errno(link, r, "Cannot configure IPv6 accept_ra for interface: %m");
+ }
+
+ return 0;
+}
+
static int link_configure(Link *link) {
int r;
@@ -1605,6 +1859,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = link_set_ipv6_accept_ra(link);
+ if (r < 0)
+ return r;
+
if (link_ipv4ll_enabled(link)) {
r = ipv4ll_configure(link);
if (r < 0)
@@ -1945,7 +2203,7 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
log_link_debug(link, "Link %d added", link->ifindex);
- if (detect_container(NULL) <= 0) {
+ if (detect_container() <= 0) {
/* not in a container, udev will be around */
sprintf(ifindex_str, "n%d", link->ifindex);
device = udev_device_new_from_device_id(m->udev, ifindex_str);
@@ -2059,10 +2317,9 @@ int link_update(Link *link, sd_netlink_message *m) {
link_free_carrier_maps(link);
- free(link->ifname);
- link->ifname = strdup(ifname);
- if (!link->ifname)
- return -ENOMEM;
+ r = free_and_strdup(&link->ifname, ifname);
+ if (r < 0)
+ return r;
r = link_new_carrier_maps(link);
if (r < 0)
@@ -2241,6 +2498,14 @@ int link_save(Link *link) {
if (link->network) {
char **address, **domain;
bool space;
+ sd_dhcp6_lease *dhcp6_lease = NULL;
+
+ if (link->dhcp6_client) {
+ r = sd_dhcp6_client_get_lease(link->dhcp6_client,
+ &dhcp6_lease);
+ if (r < 0)
+ log_link_debug(link, "No DHCPv6 lease");
+ }
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
@@ -2262,6 +2527,18 @@ int link_save(Link *link) {
if (space)
fputc(' ', f);
serialize_in_addrs(f, addresses, r);
+ space = true;
+ }
+ }
+
+ if (link->network->dhcp_dns && dhcp6_lease) {
+ struct in6_addr *in6_addrs;
+
+ r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
+ if (r > 0) {
+ if (space)
+ fputc(' ', f);
+ serialize_in6_addrs(f, in6_addrs, r);
}
}
@@ -2285,6 +2562,32 @@ int link_save(Link *link) {
if (space)
fputc(' ', f);
serialize_in_addrs(f, addresses, r);
+ space = true;
+ }
+ }
+
+ if (link->network->dhcp_ntp && dhcp6_lease) {
+ struct in6_addr *in6_addrs;
+ char **hosts;
+ char **hostname;
+
+ r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease,
+ &in6_addrs);
+ if (r > 0) {
+ if (space)
+ fputc(' ', f);
+ serialize_in6_addrs(f, in6_addrs, r);
+ space = true;
+ }
+
+ r = sd_dhcp6_lease_get_ntp_fqdn(dhcp6_lease, &hosts);
+ if (r > 0) {
+ STRV_FOREACH(hostname, hosts) {
+ if (space)
+ fputc(' ', f);
+ fputs(*hostname, f);
+ space = true;
+ }
}
}
@@ -2308,6 +2611,21 @@ int link_save(Link *link) {
if (space)
fputc(' ', f);
fputs(domainname, f);
+ space = true;
+ }
+ }
+
+ if (link->network->dhcp_domains && dhcp6_lease) {
+ char **domains;
+
+ r = sd_dhcp6_lease_get_domains(dhcp6_lease, &domains);
+ if (r >= 0) {
+ STRV_FOREACH(domain, domains) {
+ if (space)
+ fputc(' ', f);
+ fputs(*domain, f);
+ space = true;
+ }
}
}
@@ -2317,7 +2635,7 @@ int link_save(Link *link) {
yes_no(link->network->wildcard_domain));
fprintf(f, "LLMNR=%s\n",
- llmnr_support_to_string(link->network->llmnr));
+ resolve_support_to_string(link->network->llmnr));
}
if (!hashmap_isempty(link->bound_to_links)) {
@@ -2353,9 +2671,17 @@ int link_save(Link *link) {
}
if (link->dhcp_lease) {
+ const char *tz = NULL;
+
+ r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
+ if (r >= 0)
+ fprintf(f, "TIMEZONE=%s\n", tz);
+ }
+
+ if (link->dhcp_lease) {
assert(link->network);
- r = sd_dhcp_lease_save(link->dhcp_lease, link->lease_file);
+ r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
goto fail;
@@ -2388,14 +2714,13 @@ int link_save(Link *link) {
}
return 0;
+
fail:
- log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
(void) unlink(link->state_file);
-
if (temp_path)
(void) unlink(temp_path);
- return r;
+ return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
}
static const char* const link_state_table[_LINK_STATE_MAX] = {