#include <netinet/in.h>
#include <linux/if.h>
+#include <linux/if_arp.h>
#include <unistd.h>
#include "alloc-util.h"
return &link->manager->duid;
}
-int link_sysctl_ipv6_enabled(Link *link) {
- _cleanup_free_ char *value = NULL;
- int r;
-
- assert(link);
- assert(link->ifname);
-
- if (link->sysctl_ipv6_enabled >= 0)
- return link->sysctl_ipv6_enabled;
-
- r = sysctl_read_ip_property(AF_INET6, link->ifname, "disable_ipv6", &value);
- if (r < 0)
- return log_link_warning_errno(link, r,
- "Failed to read net.ipv6.conf.%s.disable_ipv6 sysctl property: %m",
- link->ifname);
-
- link->sysctl_ipv6_enabled = value[0] == '0';
- return link->sysctl_ipv6_enabled;
-}
-
static bool link_dhcp6_enabled(Link *link) {
assert(link);
if (link->network->bond)
return false;
- if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
- return false;
-
- if (link_sysctl_ipv6_enabled(link) == 0)
+ if (link->iftype == ARPHRD_CAN)
return false;
return link->network->dhcp & ADDRESS_FAMILY_IPV6;
if (link->network->bond)
return false;
- if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ if (link->iftype == ARPHRD_CAN)
return false;
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
if (link->network->bond)
return false;
- if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ if (link->iftype == ARPHRD_CAN)
return false;
return link->network->dhcp_server;
}
-bool link_ipv4ll_enabled(Link *link, AddressFamilyBoolean mask) {
+bool link_ipv4ll_enabled(Link *link, AddressFamily mask) {
assert(link);
assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0);
if (!link->network)
return false;
- if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "ip6gre", "ip6tnl", "sit", "vti", "vti6", "can", "vcan", "vxcan", "nlmon"))
+ if (link->iftype == ARPHRD_CAN)
return false;
- /* L3 or L3S mode do not support ARP. */
- if (IN_SET(link_get_ipvlan_mode(link), NETDEV_IPVLAN_MODE_L3, NETDEV_IPVLAN_MODE_L3S))
+ if (STRPTR_IN_SET(link->kind,
+ "vrf", "wireguard", "ipip", "gre", "ip6gre","ip6tnl", "sit", "vti",
+ "vti6", "nlmon", "xfrm"))
return false;
- if (link->network->bond)
+ /* L3 or L3S mode do not support ARP. */
+ if (IN_SET(link_get_ipvlan_mode(link), NETDEV_IPVLAN_MODE_L3, NETDEV_IPVLAN_MODE_L3S))
return false;
if (link->network->bond)
if (!link->network)
return false;
- if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "can", "vcan", "vxcan", "nlmon"))
+ if (link->iftype == ARPHRD_CAN)
return false;
- if (link->network->bond)
+ if (STRPTR_IN_SET(link->kind, "vrf", "wireguard", "ipip", "gre", "sit", "vti", "nlmon"))
return false;
- if (link_sysctl_ipv6_enabled(link) == 0)
+ if (link->network->bond)
return false;
return link->network->link_local & ADDRESS_FAMILY_IPV6;
if (link->network->bond)
return false;
- if (link_sysctl_ipv6_enabled(link) == 0)
- return false;
-
- if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ if (link->iftype == ARPHRD_CAN)
return false;
/* DHCPv6 client will not be started if no IPv6 link-local address is configured. */
- return link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network);
+ if (link_ipv6ll_enabled(link))
+ return true;
+
+ if (network_has_static_ipv6_configurations(link->network))
+ return true;
+
+ return false;
}
static bool link_radv_enabled(Link *link) {
if (!link->network)
return false;
- if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+ if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID)
return false;
return link->network->ip_forward & ADDRESS_FAMILY_IPV4;
if (!link->network)
return false;
- if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
- return false;
-
- if (link_sysctl_ipv6_enabled(link) == 0)
+ if (link->network->ip_forward == _ADDRESS_FAMILY_INVALID)
return false;
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
return link->network->ipv6_privacy_extensions;
}
-static int link_enable_ipv6(Link *link) {
- bool disabled;
+static int link_update_ipv6_sysctl(Link *link) {
+ bool enabled;
int r;
if (link->flags & IFF_LOOPBACK)
return 0;
- disabled = !link_ipv6_enabled(link);
+ enabled = link_ipv6_enabled(link);
+ if (enabled) {
+ r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", false);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Cannot enable IPv6: %m");
- r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", disabled);
- if (r < 0)
- log_link_warning_errno(link, r, "Cannot %s IPv6: %m", enable_disable(!disabled));
- else
- log_link_info(link, "IPv6 successfully %sd", enable_disable(!disabled));
+ log_link_info(link, "IPv6 successfully enabled");
+ }
return 0;
}
.n_ref = 1,
.manager = manager,
.state = LINK_STATE_PENDING,
- .rtnl_extended_attrs = true,
.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);
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);
+ link->neighbors = set_free_with_destructor(link->neighbors, neighbor_free);
+ link->neighbors_foreign = set_free_with_destructor(link->neighbors_foreign, neighbor_free);
+
link->addresses = set_free_with_destructor(link->addresses, address_free);
link->addresses_foreign = set_free_with_destructor(link->addresses_foreign, address_free);
sd_dhcp_server_unref(link->dhcp_server);
sd_dhcp_client_unref(link->dhcp_client);
sd_dhcp_lease_unref(link->dhcp_lease);
+ set_free(link->dhcp_routes);
link_lldp_emit_stop(link);
assert(link);
assert(link->network);
- link_set_state(link, LINK_STATE_CONFIGURING);
link->routing_policy_rules_configured = false;
LIST_FOREACH(rules, rule, link->network->rules) {
}
r = routing_policy_rule_configure(rule, link, NULL);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
- link_enter_failed(link);
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
if (r > 0)
link->routing_policy_rule_messages++;
}
if (link->routing_policy_rule_messages == 0) {
link->routing_policy_rules_configured = true;
link_check_ready(link);
- } else
+ } else {
log_link_debug(link, "Setting routing policy rules");
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ }
return 0;
}
return 1;
r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -EEXIST)
+ if (r < 0 && r != -EEXIST) {
log_link_warning_errno(link, r, "Could not set route: %m");
+ link_enter_failed(link);
+ return 1;
+ }
if (link->route_messages == 0) {
log_link_debug(link, "Routes set");
assert(link->address_messages == 0);
assert(link->state != _LINK_STATE_INVALID);
- link_set_state(link, LINK_STATE_CONFIGURING);
link->static_routes_configured = false;
+ if (!link_has_carrier(link) && !link->network->configure_without_carrier)
+ /* During configuring addresses, the link lost its carrier. As networkd is dropping
+ * the addresses now, let's not configure the routes either. */
+ return 0;
+
r = link_request_set_routing_policy_rule(link);
if (r < 0)
return r;
continue;
r = route_configure(rt, link, route_handler);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not set routes: %m");
- link_enter_failed(link);
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not set routes: %m");
if (r > 0)
link->route_messages++;
}
if (link->route_messages == 0) {
link->static_routes_configured = true;
link_check_ready(link);
- } else
+ } else {
log_link_debug(link, "Setting routes");
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ }
return 0;
}
void link_check_ready(Link *link) {
Address *a;
Iterator i;
+ int r;
assert(link);
if (!link->addresses_ready) {
link->addresses_ready = true;
- link_request_set_routes(link);
+ r = link_request_set_routes(link);
+ if (r < 0)
+ link_enter_failed(link);
return;
}
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
- link_set_state(link, LINK_STATE_CONFIGURING);
link->neighbors_configured = false;
LIST_FOREACH(neighbors, neighbor, link->network->neighbors) {
r = neighbor_configure(neighbor, link, NULL);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not set neighbor: %m");
- link_enter_failed(link);
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not set neighbor: %m");
}
if (link->neighbor_messages == 0) {
link->neighbors_configured = true;
link_check_ready(link);
- } else
+ } else {
log_link_debug(link, "Setting neighbors");
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ }
return 0;
}
return 1;
r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -EEXIST)
+ if (r < 0 && r != -EEXIST) {
log_link_warning_errno(link, r, "could not set address: %m");
- else if (r >= 0)
- manager_rtnl_process_address(rtnl, m, link->manager);
+ link_enter_failed(link);
+ return 1;
+ } else if (r >= 0)
+ (void) manager_rtnl_process_address(rtnl, m, link->manager);
if (link->address_messages == 0) {
log_link_debug(link, "Addresses set");
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
- link_set_state(link, LINK_STATE_CONFIGURING);
-
/* Reset all *_configured flags we are configuring. */
link->addresses_configured = false;
link->addresses_ready = false;
update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
r = address_configure(ad, link, address_handler, update);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not set addresses: %m");
- link_enter_failed(link);
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not set addresses: %m");
if (r > 0)
link->address_messages++;
}
LIST_FOREACH(labels, label, link->network->address_labels) {
r = address_label_configure(label, link, NULL, false);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not set address label: %m");
- link_enter_failed(link);
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not set address label: %m");
link->address_label_messages++;
}
start it */
if (link_dhcp4_server_enabled(link) && (link->flags & IFF_UP)) {
r = dhcp4_server_configure(link);
- if (r < 0) {
- link_enter_failed(link);
+ if (r < 0)
return r;
- }
log_link_debug(link, "Offering DHCPv4 leases");
}
if (link->address_messages == 0) {
link->addresses_configured = true;
link_check_ready(link);
- } else
+ } else {
log_link_debug(link, "Setting addresses");
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ }
return 0;
}
return 1;
r = sd_netlink_message_get_errno(m);
- if (r < 0) {
- log_link_warning_errno(link, r, "Could not set MTU: %m");
- return 1;
- }
-
- log_link_debug(link, "Setting MTU done.");
+ if (r < 0)
+ log_link_warning_errno(link, r, "Could not set MTU, ignoring: %m");
+ else
+ log_link_debug(link, "Setting MTU done.");
- if (link->state == LINK_STATE_INITIALIZED)
- (void) link_configure_after_setting_mtu(link);
+ if (link->state == LINK_STATE_INITIALIZED) {
+ r = link_configure_after_setting_mtu(link);
+ if (r < 0)
+ link_enter_failed(link);
+ }
return 1;
}
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
- /* If IPv6 not configured (no static IPv6 address and IPv6LL autoconfiguration is disabled)
- * for this interface, then disable IPv6 else enable it. */
- (void) link_enable_ipv6(link);
-
/* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
* on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */
if (link_ipv6_enabled(link) && mtu < IPV6_MIN_MTU) {
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "Could not set link flags: %m");
+ log_link_warning_errno(link, r, "Could not set link flags, ignoring: %m");
return 1;
}
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "Could not set address genmode for interface: %m");
+ log_link_warning_errno(link, r, "Could not set address genmode for interface, ignoring: %m");
return 1;
}
r = set_put(master->slaves, link);
if (r < 0)
return r;
+ if (r == 0)
+ return 0;
link_ref(link);
return 0;
if (!link_has_carrier(link) && !link->network->configure_without_carrier)
return 0;
+ link_set_state(link, LINK_STATE_CONFIGURING);
return link_request_set_addresses(link);
}
log_link_error_errno(link, r, "Could not join netdev: %m");
link_enter_failed(link);
return 1;
- } else
- log_link_debug(link, "Joined netdev");
+ }
+
+ log_link_debug(link, "Joined netdev");
if (link->enslaving == 0) {
- link_joined(link);
+ r = link_joined(link);
+ if (r < 0)
+ link_enter_failed(link);
}
return 1;
return false;
}
+static bool link_is_neighbor_configured(Link *link, Neighbor *neighbor) {
+ Neighbor *net_neighbor;
+
+ assert(link);
+ assert(neighbor);
+
+ if (!link->network)
+ return false;
+
+ LIST_FOREACH(neighbors, net_neighbor, link->network->neighbors)
+ if (neighbor_equal(net_neighbor, neighbor))
+ return true;
+
+ return false;
+}
+
static bool link_is_static_route_configured(Link *link, Route *route) {
Route *net_route;
static int link_drop_foreign_config(Link *link) {
Address *address;
+ Neighbor *neighbor;
Route *route;
Iterator i;
int r;
}
}
+ SET_FOREACH(neighbor, link->neighbors_foreign, i) {
+ if (link_is_neighbor_configured(link, neighbor)) {
+ r = neighbor_add(link, neighbor->family, &neighbor->in_addr, &neighbor->lladdr, neighbor->lladdr_size, NULL);
+ if (r < 0)
+ return r;
+ } else {
+ r = neighbor_remove(neighbor, link, NULL);
+ if (r < 0)
+ return r;
+ }
+ }
+
SET_FOREACH(route, link->routes_foreign, i) {
/* do not touch routes managed by the kernel */
if (route->protocol == RTPROT_KERNEL)
continue;
+ /* do not touch multicast route added by kernel */
+ /* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
+ * https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
+ if (route->protocol == RTPROT_BOOT &&
+ route->family == AF_INET6 &&
+ route->dst_prefixlen == 8 &&
+ in_addr_equal(AF_INET6, &route->dst, &(union in_addr_union) { .in6 = {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}} }))
+ continue;
+
if (route->protocol == RTPROT_STATIC &&
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
continue;
continue;
if (link_is_static_route_configured(link, route)) {
- r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL);
+ r = route_add(link, route->family, &route->dst, route->dst_prefixlen, &route->gw, route->tos, route->priority, route->table, NULL);
if (r < 0)
return r;
} else {
static int link_drop_config(Link *link) {
Address *address, *pool_address;
+ Neighbor *neighbor;
Route *route;
Iterator i;
int r;
}
}
+ SET_FOREACH(neighbor, link->neighbors, i) {
+ r = neighbor_remove(neighbor, link, NULL);
+ if (r < 0)
+ return r;
+ }
+
SET_FOREACH(route, link->routes, i) {
/* do not touch routes managed by the kernel */
if (route->protocol == RTPROT_KERNEL)
assert(link->network);
assert(link->state == LINK_STATE_INITIALIZED);
- if (STRPTR_IN_SET(link->kind, "can", "vcan", "vxcan"))
+ if (link->iftype == ARPHRD_CAN)
return link_configure_can(link);
/* Drop foreign config, but ignore loopback or critical devices.
return r;
}
+ /* If IPv6 configured that is static IPv6 address and IPv6LL autoconfiguration is enabled
+ * for this interface, then enable IPv6 */
+ (void) link_update_ipv6_sysctl(link);
+
r = link_set_proxy_arp(link);
if (r < 0)
return r;
configure:
while ((link = set_steal_first(manager->links_requesting_uuid))) {
+ link_unref(link);
+
r = link_configure(link);
if (r < 0)
- log_link_error_errno(link, r, "Failed to configure link: %m");
+ link_enter_failed(link);
}
manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
r = set_put(m->duids_requesting_uuid, duid);
if (r < 0)
return log_oom();
+
+ link_ref(link);
}
return 0;
}
static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- (void) link_initialized_and_synced(link);
+ int r;
+
+ r = link_initialized_and_synced(link);
+ if (r < 0)
+ link_enter_failed(link);
return 1;
}
continue;
}
- r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
+ r = route_add(link, family, &route_dst, prefixlen, NULL, tos, priority, table, &route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add route: %m");
return r;
}
+ link_set_state(link, LINK_STATE_CONFIGURING);
r = link_request_set_addresses(link);
if (r < 0)
return r;
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;
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",
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) {
space = true;
}
- if (link->network->dhcp_use_dns && dhcp6_lease) {
+ if (link->network->dhcp6_use_dns && dhcp6_lease) {
struct in6_addr *in6_addrs;
r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
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) {
space = true;
}
- if (link->network->dhcp_use_ntp && dhcp6_lease) {
+ if (link->network->dhcp6_use_ntp && dhcp6_lease) {
struct in6_addr *in6_addrs;
char **hosts;
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) {
- NDiscDNSSL *dd;
-
if (dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
if (dhcp_domains)
fputstrv(f, dhcp_domains, NULL, &space);
if (dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
+ }
+
+ if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) {
+ NDiscDNSSL *dd;
SET_FOREACH(dd, link->ndisc_dnssl, i)
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
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) {
- NDiscDNSSL *dd;
-
if (dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
if (dhcp_domains)
fputstrv(f, dhcp_domains, NULL, &space);
if (dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
+ }
+
+ if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) {
+ NDiscDNSSL *dd;
SET_FOREACH(dd, link->ndisc_dnssl, i)
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
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);