diff --git a/src/network/meson.build b/src/network/meson.build index 387cf0a0b7..6bed37a170 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -156,6 +156,8 @@ if conf.get('ENABLE_NETWORKD') == 1 install_dir : dbuspolicydir) install_data('org.freedesktop.network1.service', install_dir : dbussystemservicedir) + install_data('org.freedesktop.network1.policy', + install_dir : polkitpolicydir) if install_polkit install_data('systemd-networkd.rules', install_dir : polkitrulesdir) diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index eda0325c2b..03552725ed 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -1,13 +1,20 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include +#include +#include + #include "alloc-util.h" #include "bus-common-errors.h" #include "bus-util.h" +#include "dns-domain.h" #include "networkd-link-bus.h" #include "networkd-link.h" #include "networkd-manager.h" #include "parse-util.h" +#include "resolve-util.h" #include "strv.h" +#include "user-util.h" BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState); BUS_DEFINE_PROPERTY_GET_ENUM(property_get_carrier_state, link_carrier_state, LinkCarrierState); @@ -59,6 +66,515 @@ static int property_get_bit_rates( return sd_bus_message_append(reply, "(tt)", tx, rx); } +static int verify_managed_link(Link *l, sd_bus_error *error) { + assert(l); + + if (l->flags & IFF_LOOPBACK) + return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname); + + return 0; +} + +int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_strv_free_ char **ntp = NULL; + Link *l = userdata; + int r; + char **i; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &ntp); + if (r < 0) + return r; + + STRV_FOREACH(i, ntp) { + r = dns_name_is_valid_or_address(*i); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NTP server: %s", *i); + } + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-ntp-servers", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + strv_free_and_replace(l->ntp, ntp); + + (void) link_dirty(l); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ struct in_addr_data *dns = NULL; + size_t allocated = 0, n = 0; + Link *l = userdata; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(message, 'a', "(iay)"); + if (r < 0) + return r; + + for (;;) { + int family; + size_t sz; + const void *d; + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_enter_container(message, 'r', "iay"); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_read(message, "i", &family); + if (r < 0) + return r; + + if (!IN_SET(family, AF_INET, AF_INET6)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + + r = sd_bus_message_read_array(message, 'y', &d, &sz); + if (r < 0) + return r; + if (sz != FAMILY_ADDRESS_SIZE(family)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + + if (!dns_server_address_valid(family, d)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (!GREEDY_REALLOC(dns, allocated, n+1)) + return -ENOMEM; + + dns[n].family = family; + memcpy(&dns[n].address, d, sz); + n++; + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-dns-servers", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + free_and_replace(l->dns, dns); + l->n_dns = n; + + (void) link_dirty(l); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(ordered_set_freep) OrderedSet *search_domains = NULL, *route_domains = NULL; + Link *l = userdata; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(message, 'a', "(sb)"); + if (r < 0) + return r; + + for (;;) { + _cleanup_free_ char *str = NULL; + OrderedSet **domains; + const char *name; + int route_only; + + r = sd_bus_message_read(message, "(sb)", &name, &route_only); + if (r < 0) + return r; + if (r == 0) + break; + + r = dns_name_is_valid(name); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name); + if (!route_only && dns_name_is_root(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain"); + + r = dns_name_normalize(name, 0, &str); + if (r < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name); + + domains = route_only ? &route_domains : &search_domains; + r = ordered_set_ensure_allocated(domains, &string_hash_ops); + if (r < 0) + return r; + + r = ordered_set_put(*domains, str); + if (r < 0) + return r; + + TAKE_PTR(str); + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-domains", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + ordered_set_free_free(l->search_domains); + ordered_set_free_free(l->route_domains); + l->search_domains = TAKE_PTR(search_domains); + l->route_domains = TAKE_PTR(route_domains); + + (void) link_dirty(l); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + int r, b; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-default-route", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + if (l->dns_default_route != b) { + l->dns_default_route = b; + (void) link_dirty(l); + } + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + ResolveSupport mode; + const char *llmnr; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "s", &llmnr); + if (r < 0) + return r; + + if (isempty(llmnr)) + mode = RESOLVE_SUPPORT_YES; + else { + mode = resolve_support_from_string(llmnr); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr); + } + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-llmnr", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + if (l->llmnr != mode) { + l->llmnr = mode; + (void) link_dirty(l); + } + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + ResolveSupport mode; + const char *mdns; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "s", &mdns); + if (r < 0) + return r; + + if (isempty(mdns)) + mode = RESOLVE_SUPPORT_NO; + else { + mode = resolve_support_from_string(mdns); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns); + } + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-mdns", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + if (l->mdns != mode) { + l->mdns = mode; + (void) link_dirty(l); + } + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + const char *dns_over_tls; + DnsOverTlsMode mode; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "s", &dns_over_tls); + if (r < 0) + return r; + + if (isempty(dns_over_tls)) + mode = _DNS_OVER_TLS_MODE_INVALID; + else { + mode = dns_over_tls_mode_from_string(dns_over_tls); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls); + } + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-dns-over-tls", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + if (l->dns_over_tls_mode != mode) { + l->dns_over_tls_mode = mode; + (void) link_dirty(l); + } + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + const char *dnssec; + DnssecMode mode; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "s", &dnssec); + if (r < 0) + return r; + + if (isempty(dnssec)) + mode = _DNSSEC_MODE_INVALID; + else { + mode = dnssec_mode_from_string(dnssec); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec); + } + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-dnssec", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + if (l->dnssec_mode != mode) { + l->dnssec_mode = mode; + (void) link_dirty(l); + } + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_set_free_free_ Set *ns = NULL; + _cleanup_strv_free_ char **ntas = NULL; + Link *l = userdata; + int r; + char **i; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = sd_bus_message_read_strv(message, &ntas); + if (r < 0) + return r; + + STRV_FOREACH(i, ntas) { + r = dns_name_is_valid(*i); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i); + } + + ns = set_new(&dns_name_hash_ops); + if (!ns) + return -ENOMEM; + + STRV_FOREACH(i, ntas) { + r = set_put_strdup(ns, *i); + if (r < 0) + return r; + } + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.set-dnssec-negative-trust-anchors", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + set_free_free(l->dnssec_negative_trust_anchors); + l->dnssec_negative_trust_anchors = TAKE_PTR(ns); + + (void) link_dirty(l); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.revert-ntp", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + link_ntp_settings_clear(l); + (void) link_dirty(l); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + int r; + + assert(message); + assert(l); + + r = verify_managed_link(l, error); + if (r < 0) + return r; + + r = bus_verify_polkit_async(message, CAP_NET_ADMIN, + "org.freedesktop.network1.revert-dns", + NULL, true, UID_INVALID, + &l->manager->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Polkit will call us back */ + + link_dns_settings_clear(l); + (void) link_dirty(l); + + return sd_bus_reply_method_return(message, NULL); +} + const sd_bus_vtable link_vtable[] = { SD_BUS_VTABLE_START(0), @@ -68,6 +584,18 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0), + SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_VTABLE_END }; diff --git a/src/network/networkd-link-bus.h b/src/network/networkd-link-bus.h index 58005a4bbe..2a653f5058 100644 --- a/src/network/networkd-link-bus.h +++ b/src/network/networkd-link-bus.h @@ -18,3 +18,15 @@ int link_send_changed(Link *link, const char *property, ...) _sentinel_; int property_get_operational_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int property_get_carrier_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int property_get_address_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); + +int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 46830290c6..a08ad80f15 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -609,6 +609,13 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { .ifindex = ifindex, .iftype = iftype, .sysctl_ipv6_enabled = -1, + + .n_dns = (unsigned) -1, + .dns_default_route = -1, + .llmnr = _RESOLVE_SUPPORT_INVALID, + .mdns = _RESOLVE_SUPPORT_INVALID, + .dnssec_mode = _DNSSEC_MODE_INVALID, + .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID, }; link->ifname = strdup(ifname); @@ -655,11 +662,34 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { return 0; } +void link_ntp_settings_clear(Link *link) { + link->ntp = strv_free(link->ntp); +} + +void link_dns_settings_clear(Link *link) { + link->dns = mfree(link->dns); + link->n_dns = (unsigned) -1; + + link->search_domains = ordered_set_free_free(link->search_domains); + link->route_domains = ordered_set_free_free(link->route_domains); + + link->dns_default_route = -1; + link->llmnr = _RESOLVE_SUPPORT_INVALID; + link->mdns = _RESOLVE_SUPPORT_INVALID; + link->dnssec_mode = _DNSSEC_MODE_INVALID; + link->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID; + + link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors); +} + static Link *link_free(Link *link) { Address *address; assert(link); + link_ntp_settings_clear(link); + link_dns_settings_clear(link); + link->routes = set_free_with_destructor(link->routes, route_free); link->routes_foreign = set_free_with_destructor(link->routes_foreign, route_free); @@ -3386,6 +3416,26 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { fputc('\n', f); } +static void link_save_dns(FILE *f, struct in_addr_data *dns, unsigned n_dns, bool *space) { + unsigned j; + int r; + + for (j = 0; j < n_dns; j++) { + _cleanup_free_ char *b = NULL; + + r = in_addr_to_string(dns[j].family, &dns[j].address, &b); + if (r < 0) { + log_debug_errno(r, "Failed to format address, ignoring: %m"); + continue; + } + + if (*space) + fputc(' ', f); + fputs(b, f); + *space = true; + } +} + int link_save(Link *link) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -3437,7 +3487,6 @@ int link_save(Link *link) { char **dhcp6_domains = NULL, **dhcp_domains = NULL; const char *dhcp_domainname = NULL, *p; sd_dhcp6_lease *dhcp6_lease = NULL; - unsigned j; bool space; fprintf(f, "REQUIRED_FOR_ONLINE=%s\n", @@ -3457,21 +3506,10 @@ int link_save(Link *link) { fputs("DNS=", f); space = false; - for (j = 0; j < link->network->n_dns; j++) { - _cleanup_free_ char *b = NULL; - - r = in_addr_to_string(link->network->dns[j].family, - &link->network->dns[j].address, &b); - if (r < 0) { - log_debug_errno(r, "Failed to format address, ignoring: %m"); - continue; - } - - if (space) - fputc(' ', f); - fputs(b, f); - space = true; - } + if (link->n_dns != (unsigned) -1) + link_save_dns(f, link->dns, link->n_dns, &space); + else + link_save_dns(f, link->network->dns, link->network->n_dns, &space); if (link->network->dhcp_use_dns && link->dhcp_lease) { @@ -3514,7 +3552,7 @@ int link_save(Link *link) { fputs("NTP=", f); space = false; - fputstrv(f, link->network->ntp, NULL, &space); + fputstrv(f, link->ntp ?: link->network->ntp, NULL, &space); if (link->network->dhcp_use_ntp && link->dhcp_lease) { @@ -3557,7 +3595,7 @@ int link_save(Link *link) { fputs("DOMAINS=", f); space = false; - ORDERED_SET_FOREACH(p, link->network->search_domains, i) + ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains, i) fputs_with_space(f, p, NULL, &space); if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) { @@ -3580,7 +3618,7 @@ int link_save(Link *link) { fputs("ROUTE_DOMAINS=", f); space = false; - ORDERED_SET_FOREACH(p, link->network->route_domains, i) + ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains, i) fputs_with_space(f, p, NULL, &space); if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) { @@ -3602,21 +3640,37 @@ int link_save(Link *link) { fputc('\n', f); fprintf(f, "LLMNR=%s\n", - resolve_support_to_string(link->network->llmnr)); + resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr)); fprintf(f, "MDNS=%s\n", - resolve_support_to_string(link->network->mdns)); - if (link->network->dns_default_route >= 0) + resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns)); + if (link->dns_default_route >= 0) + fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(link->dns_default_route)); + else if (link->network->dns_default_route >= 0) fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(link->network->dns_default_route)); - if (link->network->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID) + if (link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID) + fprintf(f, "DNS_OVER_TLS=%s\n", + dns_over_tls_mode_to_string(link->dns_over_tls_mode)); + else if (link->network->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID) fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(link->network->dns_over_tls_mode)); - if (link->network->dnssec_mode != _DNSSEC_MODE_INVALID) + if (link->dnssec_mode != _DNSSEC_MODE_INVALID) + fprintf(f, "DNSSEC=%s\n", + dnssec_mode_to_string(link->dnssec_mode)); + else if (link->network->dnssec_mode != _DNSSEC_MODE_INVALID) fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(link->network->dnssec_mode)); - if (!set_isempty(link->network->dnssec_negative_trust_anchors)) { + if (!set_isempty(link->dnssec_negative_trust_anchors)) { + const char *n; + + fputs("DNSSEC_NTA=", f); + space = false; + SET_FOREACH(n, link->dnssec_negative_trust_anchors, i) + fputs_with_space(f, n, NULL, &space); + fputc('\n', f); + } else if (!set_isempty(link->network->dnssec_negative_trust_anchors)) { const char *n; fputs("DNSSEC_NTA=", f); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 43efa42312..e8680bbb1f 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -18,6 +18,8 @@ #include "log-link.h" #include "network-util.h" #include "networkd-util.h" +#include "ordered-set.h" +#include "resolve-util.h" #include "set.h" typedef enum LinkState { @@ -130,6 +132,20 @@ typedef struct Link { bool stats_updated; int sysctl_ipv6_enabled; + + /* All kinds of DNS configuration */ + struct in_addr_data *dns; + unsigned n_dns; + OrderedSet *search_domains, *route_domains; + + int dns_default_route; + ResolveSupport llmnr; + ResolveSupport mdns; + DnssecMode dnssec_mode; + DnsOverTlsMode dns_over_tls_mode; + Set *dnssec_negative_trust_anchors; + + char **ntp; } Link; typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*); @@ -137,6 +153,8 @@ typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, DUID *link_get_duid(Link *link); int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error); +void link_ntp_settings_clear(Link *link); +void link_dns_settings_clear(Link *link); Link *link_unref(Link *link); Link *link_ref(Link *link); DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref); diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index 6174104f5e..37b04ce556 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -116,6 +116,73 @@ static int method_get_link_by_index(sd_bus_message *message, void *userdata, sd_ return sd_bus_send(NULL, reply, NULL); } +static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) { + int ifindex, r; + Link *l; + + assert(m); + assert(message); + assert(handler); + + assert_cc(sizeof(int) == sizeof(int32_t)); + r = sd_bus_message_read(message, "i", &ifindex); + if (r < 0) + return r; + + if (ifindex <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); + + l = hashmap_get(m->links, INT_TO_PTR(ifindex)); + if (!l) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex); + + return handler(message, l, error); +} + +static int bus_method_set_link_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_ntp_servers, error); +} + +static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dns_servers, error); +} + +static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_domains, error); +} + +static int bus_method_set_link_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_default_route, error); +} + +static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_llmnr, error); +} + +static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_mdns, error); +} + +static int bus_method_set_link_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dns_over_tls, error); +} + +static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dnssec, error); +} + +static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error); +} + +static int bus_method_revert_link_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_revert_ntp, error); +} + +static int bus_method_revert_link_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_revert_dns, error); +} + const sd_bus_vtable manager_vtable[] = { SD_BUS_VTABLE_START(0), @@ -126,6 +193,17 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("ListLinks", NULL, "a(iso)", method_list_links, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetLinkByName", "s", "io", method_get_link_by_name, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetLinkByIndex", "i", "so", method_get_link_by_index, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkNTP", "ias", NULL, bus_method_set_link_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDefaultRoute", "ib", NULL, bus_method_set_link_default_route, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RevertLinkNTP", "i", NULL, bus_method_revert_link_ntp, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RevertLinkDNS", "i", NULL, bus_method_revert_link_dns, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 8d72d290a0..51cc8f654b 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1164,15 +1164,15 @@ static int manager_save(Manager *m) { if (r < 0) return r; - r = ordered_set_put_strdupv(ntp, link->network->ntp); + r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp); if (r < 0) return r; - r = ordered_set_put_string_set(search_domains, link->network->search_domains); + r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains); if (r < 0) return r; - r = ordered_set_put_string_set(route_domains, link->network->route_domains); + r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains); if (r < 0) return r; @@ -1433,6 +1433,7 @@ void manager_free(Manager *m) { sd_device_monitor_unref(m->device_monitor); + bus_verify_polkit_async_registry_free(m->polkit_registry); sd_bus_flush_close_unref(m->bus); free(m->dynamic_timezone); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index e5bf7ac9f7..5422b56dc2 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -25,6 +25,7 @@ struct Manager { sd_resolve *resolve; sd_bus *bus; sd_device_monitor *device_monitor; + Hashmap *polkit_registry; bool enumerating:1; bool dirty:1; diff --git a/src/network/org.freedesktop.network1.conf b/src/network/org.freedesktop.network1.conf index 56a78ee7dc..366c630702 100644 --- a/src/network/org.freedesktop.network1.conf +++ b/src/network/org.freedesktop.network1.conf @@ -20,34 +20,7 @@ - - - - - - - - - - - - - - - - + diff --git a/src/network/org.freedesktop.network1.policy b/src/network/org.freedesktop.network1.policy new file mode 100644 index 0000000000..07091bffe5 --- /dev/null +++ b/src/network/org.freedesktop.network1.policy @@ -0,0 +1,142 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Set NTP servers + Authentication is required to set NTP servers. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Set DNS servers + Authentication is required to set DNS servers. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Set domains + Authentication is required to set domains. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Set default route + Authentication is required to set default route. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Enable/disable LLMNR + Authentication is required to enable or disable LLMNR. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Enable/disable multicast DNS + Authentication is required to enable or disable multicast DNS. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Enable/disable DNS over TLS + Authentication is required to enable or disable DNS over TLS. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Enable/disable DNSSEC + Authentication is required to enable or disable DNSSEC. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Set DNSSEC Negative Trust Anchors + Authentication is required to set DNSSEC Negative Trust Anchros. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Revert NTP settings + Authentication is required to revert NTP settings. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + + + Revert DNS settings + Authentication is required to revert DNS settings. + + auth_admin + auth_admin + auth_admin_keep + + unix-user:systemd-network + + +