summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/networkctl.c81
-rw-r--r--src/network/networkd-dhcp4.c58
-rw-r--r--src/network/networkd-link-bus.c13
-rw-r--r--src/network/networkd-link.c125
-rw-r--r--src/network/networkd-manager.c76
-rw-r--r--src/network/networkd-ndisc.c2
-rw-r--r--src/network/networkd-netdev-tunnel.c36
-rw-r--r--src/network/networkd-network-gperf.gperf30
-rw-r--r--src/network/networkd-network.c134
-rw-r--r--src/network/networkd-network.h33
10 files changed, 309 insertions, 279 deletions
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 4a8fa4d8f3..253692aa64 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -490,6 +490,9 @@ static int dump_addresses(
static void dump_list(const char *prefix, char **l) {
char **i;
+ if (strv_isempty(l))
+ return;
+
STRV_FOREACH(i, l) {
printf("%*s%s\n",
(int) strlen(prefix),
@@ -502,7 +505,7 @@ static int link_status_one(
sd_netlink *rtnl,
sd_hwdb *hwdb,
const char *name) {
- _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
+ _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
@@ -552,7 +555,6 @@ static int link_status_one(
return rtnl_log_parse_error(r);
have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
-
if (have_mac) {
const uint8_t *p;
bool all_zeroes = true;
@@ -567,44 +569,35 @@ static int link_status_one(
have_mac = false;
}
- sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
+ (void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
- sd_network_link_get_operational_state(ifindex, &operational_state);
+ (void) sd_network_link_get_operational_state(ifindex, &operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- sd_network_link_get_setup_state(ifindex, &setup_state);
+ (void) sd_network_link_get_setup_state(ifindex, &setup_state);
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
- sd_network_link_get_dns(ifindex, &dns);
- sd_network_link_get_domains(ifindex, &domains);
- r = sd_network_link_get_wildcard_domain(ifindex);
- if (r > 0) {
- char *wildcard;
-
- wildcard = strdup("*");
- if (!wildcard)
- return log_oom();
-
- if (strv_consume(&domains, wildcard) < 0)
- return log_oom();
- }
+ (void) sd_network_link_get_dns(ifindex, &dns);
+ (void) sd_network_link_get_search_domains(ifindex, &search_domains);
+ (void) sd_network_link_get_route_domains(ifindex, &route_domains);
+ (void) sd_network_link_get_ntp(ifindex, &ntp);
sprintf(devid, "n%i", ifindex);
- (void)sd_device_new_from_device_id(&d, devid);
+ (void) sd_device_new_from_device_id(&d, devid);
if (d) {
- (void)sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
- (void)sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
- (void)sd_device_get_property_value(d, "ID_PATH", &path);
+ (void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
+ (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
+ (void) sd_device_get_property_value(d, "ID_PATH", &path);
r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor);
if (r < 0)
- (void)sd_device_get_property_value(d, "ID_VENDOR", &vendor);
+ (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model);
if (r < 0)
- (void)sd_device_get_property_value(d, "ID_MODEL", &model);
+ (void) sd_device_get_property_value(d, "ID_MODEL", &model);
}
link_get_type_string(iftype, d, &t);
@@ -653,20 +646,14 @@ static int link_status_one(
dump_addresses(rtnl, " Address: ", ifindex);
dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
- if (!strv_isempty(dns))
- dump_list(" DNS: ", dns);
- if (!strv_isempty(domains))
- dump_list(" Domain: ", domains);
+ dump_list(" DNS: ", dns);
+ dump_list(" Search Domains: ", search_domains);
+ dump_list(" Route Domains: ", route_domains);
- (void) sd_network_link_get_ntp(ifindex, &ntp);
- if (!strv_isempty(ntp))
- dump_list(" NTP: ", ntp);
+ dump_list(" NTP: ", ntp);
- if (!strv_isempty(carrier_bound_to))
- dump_list("Carrier Bound To: ", carrier_bound_to);
-
- if (!strv_isempty(carrier_bound_by))
- dump_list("Carrier Bound By: ", carrier_bound_by);
+ dump_list("Carrier Bound To: ", carrier_bound_to);
+ dump_list("Carrier Bound By: ", carrier_bound_by);
(void) sd_network_link_get_timezone(ifindex, &tz);
if (tz)
@@ -691,30 +678,30 @@ static int link_status(int argc, char *argv[], void *userdata) {
if (argc <= 1 && !arg_all) {
_cleanup_free_ char *operational_state = NULL;
- _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
+ _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains;
const char *on_color_operational, *off_color_operational;
sd_network_get_operational_state(&operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- printf("%s%s%s State: %s%s%s\n",
+ printf("%s%s%s State: %s%s%s\n",
on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
on_color_operational, strna(operational_state), off_color_operational);
- dump_addresses(rtnl, " Address: ", 0);
- dump_gateways(rtnl, hwdb, " Gateway: ", 0);
+ dump_addresses(rtnl, " Address: ", 0);
+ dump_gateways(rtnl, hwdb, " Gateway: ", 0);
sd_network_get_dns(&dns);
- if (!strv_isempty(dns))
- dump_list(" DNS: ", dns);
+ dump_list(" DNS: ", dns);
+
+ sd_network_get_search_domains(&search_domains);
+ dump_list("Search Domains: ", search_domains);
- sd_network_get_domains(&domains);
- if (!strv_isempty(domains))
- dump_list(" Domain: ", domains);
+ sd_network_get_route_domains(&route_domains);
+ dump_list(" Route Domains: ", route_domains);
sd_network_get_ntp(&ntp);
- if (!strv_isempty(ntp))
- dump_list(" NTP: ", ntp);
+ dump_list(" NTP: ", ntp);
return 0;
}
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 48e3d84055..59eccb392f 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -54,7 +54,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
static int link_set_dhcp_routes(Link *link) {
struct in_addr gateway;
- struct sd_dhcp_route *static_routes;
+ _cleanup_free_ sd_dhcp_route **static_routes = NULL;
int r, n, i;
assert(link);
@@ -130,9 +130,9 @@ static int link_set_dhcp_routes(Link *link) {
route->family = AF_INET;
route->protocol = RTPROT_DHCP;
- route->gw.in = static_routes[i].gw_addr;
- route->dst.in = static_routes[i].dst_addr;
- route->dst_prefixlen = static_routes[i].dst_prefixlen;
+ assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
+ assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
+ assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
route->priority = link->network->dhcp_route_metric;
r = route_configure(route, link, &dhcp4_route_handler);
@@ -158,8 +158,8 @@ static int dhcp_lease_lost(Link *link) {
log_link_warning(link, "DHCP lease lost");
- if (link->network->dhcp_routes) {
- struct sd_dhcp_route *routes;
+ if (link->network->dhcp_use_routes) {
+ _cleanup_free_ sd_dhcp_route **routes = NULL;
int n, i;
n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
@@ -170,9 +170,9 @@ static int dhcp_lease_lost(Link *link) {
r = route_new(&route);
if (r >= 0) {
route->family = AF_INET;
- route->gw.in = routes[i].gw_addr;
- route->dst.in = routes[i].dst_addr;
- route->dst_prefixlen = routes[i].dst_prefixlen;
+ assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
+ assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
+ assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
route_remove(route, link,
&link_route_remove_handler);
@@ -223,7 +223,7 @@ static int dhcp_lease_lost(Link *link) {
}
}
- if (link->network->dhcp_mtu) {
+ if (link->network->dhcp_use_mtu) {
uint16_t mtu;
r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
@@ -238,11 +238,11 @@ static int dhcp_lease_lost(Link *link) {
}
}
- if (link->network->dhcp_hostname) {
+ if (link->network->dhcp_use_hostname) {
const char *hostname = NULL;
- if (link->network->hostname)
- hostname = link->network->hostname;
+ if (link->network->dhcp_hostname)
+ hostname = link->network->dhcp_hostname;
else
(void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
@@ -412,7 +412,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
link->dhcp_lease = sd_dhcp_lease_ref(lease);
link_dirty(link);
- if (link->network->dhcp_mtu) {
+ if (link->network->dhcp_use_mtu) {
uint16_t mtu;
r = sd_dhcp_lease_get_mtu(lease, &mtu);
@@ -423,11 +423,11 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
}
}
- if (link->network->dhcp_hostname) {
+ if (link->network->dhcp_use_hostname) {
const char *hostname = NULL;
- if (link->network->hostname)
- hostname = link->network->hostname;
+ if (link->network->dhcp_hostname)
+ hostname = link->network->dhcp_hostname;
else
(void) sd_dhcp_lease_get_hostname(lease, &hostname);
@@ -438,7 +438,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
}
}
- if (link->network->dhcp_timezone) {
+ if (link->network->dhcp_use_timezone) {
const char *tz = NULL;
(void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
@@ -571,45 +571,45 @@ int dhcp4_configure(Link *link) {
return r;
}
- if (link->network->dhcp_mtu) {
+ if (link->network->dhcp_use_mtu) {
r = sd_dhcp_client_set_request_option(link->dhcp_client,
- DHCP_OPTION_INTERFACE_MTU);
+ SD_DHCP_OPTION_INTERFACE_MTU);
if (r < 0)
return r;
}
- if (link->network->dhcp_routes) {
+ if (link->network->dhcp_use_routes) {
r = sd_dhcp_client_set_request_option(link->dhcp_client,
- DHCP_OPTION_STATIC_ROUTE);
+ SD_DHCP_OPTION_STATIC_ROUTE);
if (r < 0)
return r;
r = sd_dhcp_client_set_request_option(link->dhcp_client,
- DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
+ SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
if (r < 0)
return r;
}
- /* Always acquire the timezone and NTP*/
- r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NTP_SERVER);
+ /* Always acquire the timezone and NTP */
+ r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
if (r < 0)
return r;
- r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NEW_TZDB_TIMEZONE);
+ r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
if (r < 0)
return r;
- if (link->network->dhcp_sendhost) {
+ if (link->network->dhcp_send_hostname) {
_cleanup_free_ char *hostname = NULL;
const char *hn = NULL;
- if (!link->network->hostname) {
+ if (!link->network->dhcp_hostname) {
hostname = gethostname_malloc();
if (!hostname)
return -ENOMEM;
hn = hostname;
} else
- hn = link->network->hostname;
+ hn = link->network->dhcp_hostname;
if (!is_localhost(hn)) {
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
index d09a3c2d07..4d6ac747fd 100644
--- a/src/network/networkd-link-bus.c
+++ b/src/network/networkd-link-bus.c
@@ -59,15 +59,19 @@ static char *link_bus_path(Link *link) {
int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
Manager *m = userdata;
+ unsigned c = 0;
Link *link;
Iterator i;
- int r;
assert(bus);
assert(path);
assert(m);
assert(nodes);
+ l = new0(char*, hashmap_size(m->links) + 1);
+ if (!l)
+ return -ENOMEM;
+
HASHMAP_FOREACH(link, m->links, i) {
char *p;
@@ -75,11 +79,10 @@ int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***
if (!p)
return -ENOMEM;
- r = strv_consume(&l, p);
- if (r < 0)
- return r;
+ l[c++] = p;
}
+ l[c] = NULL;
*nodes = l;
l = NULL;
@@ -99,7 +102,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void
assert(found);
r = sd_bus_path_decode(path, "/org/freedesktop/network1/link", &identifier);
- if (r < 0)
+ if (r <= 0)
return 0;
r = parse_ifindex(identifier, &ifindex);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 10fec5e75f..a2f0eceb6d 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -767,7 +767,7 @@ static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
addresses[n_addresses++] = ia;
}
- if (link->network->dhcp_dns &&
+ if (link->network->dhcp_use_dns &&
link->dhcp_lease) {
const struct in_addr *da = NULL;
int n;
@@ -812,7 +812,7 @@ static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
addresses[n_addresses++] = ia;
}
- if (link->network->dhcp_ntp &&
+ if (link->network->dhcp_use_ntp &&
link->dhcp_lease) {
const struct in_addr *da = NULL;
int n;
@@ -2039,9 +2039,9 @@ static int link_configure(Link *link) {
assert(link->network);
assert(link->state == LINK_STATE_PENDING);
- /* Drop foreign config, but ignore loopback device.
- * We do not want to remove loopback address. */
- if (!(link->flags & IFF_LOOPBACK)) {
+ /* Drop foreign config, but ignore loopback or critical devices.
+ * We do not want to remove loopback address or addresses used for root NFS. */
+ if (!(link->flags & IFF_LOOPBACK) && !(link->network->dhcp_critical)) {
r = link_drop_foreign_config(link);
if (r < 0)
return r;
@@ -2729,9 +2729,10 @@ int link_save(Link *link) {
admin_state, oper_state);
if (link->network) {
- char **address, **domain;
bool space;
sd_dhcp6_lease *dhcp6_lease = NULL;
+ const char *dhcp_domainname = NULL;
+ char **dhcp6_domains = NULL;
if (link->dhcp6_client) {
r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
@@ -2743,14 +2744,9 @@ int link_save(Link *link) {
fputs("DNS=", f);
space = false;
- STRV_FOREACH(address, link->network->dns) {
- if (space)
- fputc(' ', f);
- fputs(*address, f);
- space = true;
- }
+ fputstrv(f, link->network->dns, NULL, &space);
- if (link->network->dhcp_dns &&
+ if (link->network->dhcp_use_dns &&
link->dhcp_lease) {
const struct in_addr *addresses;
@@ -2763,7 +2759,7 @@ int link_save(Link *link) {
}
}
- if (link->network->dhcp_dns && dhcp6_lease) {
+ if (link->network->dhcp_use_dns && dhcp6_lease) {
struct in6_addr *in6_addrs;
r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
@@ -2778,14 +2774,9 @@ int link_save(Link *link) {
fputs("NTP=", f);
space = false;
- STRV_FOREACH(address, link->network->ntp) {
- if (space)
- fputc(' ', f);
- fputs(*address, f);
- space = true;
- }
+ fputstrv(f, link->network->ntp, NULL, &space);
- if (link->network->dhcp_ntp &&
+ if (link->network->dhcp_use_ntp &&
link->dhcp_lease) {
const struct in_addr *addresses;
@@ -2798,10 +2789,9 @@ int link_save(Link *link) {
}
}
- if (link->network->dhcp_ntp && dhcp6_lease) {
+ if (link->network->dhcp_use_ntp && dhcp6_lease) {
struct in6_addr *in6_addrs;
char **hosts;
- char **hostname;
r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease,
&in6_addrs);
@@ -2813,58 +2803,41 @@ int link_save(Link *link) {
}
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;
- }
- }
+ if (r > 0)
+ fputstrv(f, hosts, NULL, &space);
}
fputc('\n', f);
- fputs("DOMAINS=", f);
- space = false;
- STRV_FOREACH(domain, link->network->domains) {
- if (space)
- fputc(' ', f);
- fputs(*domain, f);
- space = true;
+ if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
+ if (link->dhcp_lease)
+ (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
+
+ if (dhcp6_lease)
+ (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
}
- if (link->network->dhcp_domains &&
- link->dhcp_lease) {
- const char *domainname;
+ fputs("DOMAINS=", f);
+ fputstrv(f, link->network->search_domains, NULL, &space);
- r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
- if (r >= 0) {
- if (space)
- fputc(' ', f);
- fputs(domainname, f);
- space = true;
- }
- }
+ if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp_domainname)
+ fputs_with_space(f, dhcp_domainname, NULL, &space);
- 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;
- }
- }
- }
+ if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp6_domains)
+ fputstrv(f, dhcp6_domains, NULL, &space);
fputc('\n', f);
- fprintf(f, "WILDCARD_DOMAIN=%s\n",
- yes_no(link->network->wildcard_domain));
+ fputs("ROUTE_DOMAINS=", f);
+ fputstrv(f, link->network->route_domains, NULL, NULL);
+
+ if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp_domainname)
+ fputs_with_space(f, dhcp_domainname, NULL, &space);
+
+ if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp6_domains)
+ fputstrv(f, dhcp6_domains, NULL, &space);
+
+ fputc('\n', f);
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->network->llmnr));
@@ -2880,12 +2853,8 @@ int link_save(Link *link) {
fputs("DNSSEC_NTA=", f);
space = false;
- SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i) {
- if (space)
- fputc(' ', f);
- fputs(n, f);
- space = true;
- }
+ SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i)
+ fputs_with_space(f, n, NULL, &space);
fputc('\n', f);
}
@@ -2925,12 +2894,8 @@ int link_save(Link *link) {
bool space = false;
fputs("CARRIER_BOUND_TO=", f);
- HASHMAP_FOREACH(carrier, link->bound_to_links, i) {
- if (space)
- fputc(' ', f);
- fputs(carrier->ifname, f);
- space = true;
- }
+ HASHMAP_FOREACH(carrier, link->bound_to_links, i)
+ fputs_with_space(f, carrier->ifname, NULL, &space);
fputc('\n', f);
}
@@ -2940,12 +2905,8 @@ int link_save(Link *link) {
bool space = false;
fputs("CARRIER_BOUND_BY=", f);
- HASHMAP_FOREACH(carrier, link->bound_by_links, i) {
- if (space)
- fputc(' ', f);
- fputs(carrier->ifname, f);
- space = true;
- }
+ HASHMAP_FOREACH(carrier, link->bound_by_links, i)
+ fputs_with_space(f, carrier->ifname, NULL, &space);
fputc('\n', f);
}
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index aeb6e34c52..c10635d202 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -29,12 +29,14 @@
#include "bus-util.h"
#include "conf-parser.h"
#include "def.h"
+#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
#include "libudev-private.h"
#include "local-addresses.h"
#include "netlink-util.h"
#include "networkd.h"
+#include "ordered-set.h"
#include "path-util.h"
#include "set.h"
#include "udev-util.h"
@@ -659,15 +661,16 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa
} else if (ifindex <= 0) {
log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
return 0;
- } else
- link_get(m, ifindex, &link);
+ }
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
if (r < 0) {
log_warning_errno(r, "rtnl: Received link message without ifname: %m");
return 0;
- } else
- netdev_get(m, name, &netdev);
+ }
+
+ (void) link_get(m, ifindex, &link);
+ (void) netdev_get(m, name, &netdev);
switch (type) {
case RTM_NEWLINK:
@@ -775,7 +778,7 @@ static int manager_connect_rtnl(Manager *m) {
return 0;
}
-static int set_put_in_addr(Set *s, const struct in_addr *address) {
+static int ordered_set_put_in_addr(OrderedSet *s, const struct in_addr *address) {
char *p;
int r;
@@ -785,21 +788,21 @@ static int set_put_in_addr(Set *s, const struct in_addr *address) {
if (r < 0)
return r;
- r = set_consume(s, p);
+ r = ordered_set_consume(s, p);
if (r == -EEXIST)
return 0;
return r;
}
-static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
+static int ordered_set_put_in_addrv(OrderedSet *s, const struct in_addr *addresses, int n) {
int r, i, c = 0;
assert(s);
assert(n <= 0 || addresses);
for (i = 0; i < n; i++) {
- r = set_put_in_addr(s, addresses+i);
+ r = ordered_set_put_in_addr(s, addresses+i);
if (r < 0)
return r;
@@ -809,27 +812,24 @@ static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
return c;
}
-static void print_string_set(FILE *f, const char *field, Set *s) {
+static void print_string_set(FILE *f, const char *field, OrderedSet *s) {
bool space = false;
Iterator i;
char *p;
- if (set_isempty(s))
+ if (ordered_set_isempty(s))
return;
fputs(field, f);
- SET_FOREACH(p, s, i) {
- if (space)
- fputc(' ', f);
- fputs(p, f);
- space = true;
- }
+ ORDERED_SET_FOREACH(p, s, i)
+ fputs_with_space(f, p, NULL, &space);
+
fputc('\n', f);
}
static int manager_save(Manager *m) {
- _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
+ _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
Link *link;
Iterator i;
_cleanup_free_ char *temp_path = NULL;
@@ -842,16 +842,20 @@ static int manager_save(Manager *m) {
assert(m->state_file);
/* We add all NTP and DNS server to a set, to filter out duplicates */
- dns = set_new(&string_hash_ops);
+ dns = ordered_set_new(&string_hash_ops);
if (!dns)
return -ENOMEM;
- ntp = set_new(&string_hash_ops);
+ ntp = ordered_set_new(&string_hash_ops);
if (!ntp)
return -ENOMEM;
- domains = set_new(&string_hash_ops);
- if (!domains)
+ search_domains = ordered_set_new(&dns_name_hash_ops);
+ if (!search_domains)
+ return -ENOMEM;
+
+ route_domains = ordered_set_new(&dns_name_hash_ops);
+ if (!route_domains)
return -ENOMEM;
HASHMAP_FOREACH(link, m->links, i) {
@@ -865,15 +869,19 @@ static int manager_save(Manager *m) {
continue;
/* First add the static configured entries */
- r = set_put_strdupv(dns, link->network->dns);
+ r = ordered_set_put_strdupv(dns, link->network->dns);
+ if (r < 0)
+ return r;
+
+ r = ordered_set_put_strdupv(ntp, link->network->ntp);
if (r < 0)
return r;
- r = set_put_strdupv(ntp, link->network->ntp);
+ r = ordered_set_put_strdupv(search_domains, link->network->search_domains);
if (r < 0)
return r;
- r = set_put_strdupv(domains, link->network->domains);
+ r = ordered_set_put_strdupv(route_domains, link->network->route_domains);
if (r < 0)
return r;
@@ -881,36 +889,41 @@ static int manager_save(Manager *m) {
continue;
/* Secondly, add the entries acquired via DHCP */
- if (link->network->dhcp_dns) {
+ if (link->network->dhcp_use_dns) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
- r = set_put_in_addrv(dns, addresses, r);
+ r = ordered_set_put_in_addrv(dns, addresses, r);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
- if (link->network->dhcp_ntp) {
+ if (link->network->dhcp_use_ntp) {
const struct in_addr *addresses;
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
- r = set_put_in_addrv(ntp, addresses, r);
+ r = ordered_set_put_in_addrv(ntp, addresses, r);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
- if (link->network->dhcp_domains) {
+ if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
const char *domainname;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
- r = set_put_strdup(domains, domainname);
+
+ if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES)
+ r = ordered_set_put_strdup(search_domains, domainname);
+ else
+ r = ordered_set_put_strdup(route_domains, domainname);
+
if (r < 0)
return r;
} else if (r != -ENODATA)
@@ -933,7 +946,8 @@ static int manager_save(Manager *m) {
print_string_set(f, "DNS=", dns);
print_string_set(f, "NTP=", ntp);
- print_string_set(f, "DOMAINS=", domains);
+ print_string_set(f, "DOMAINS=", search_domains);
+ print_string_set(f, "ROUTE_DOMAINS=", route_domains);
r = fflush_and_check(f);
if (r < 0)
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index ce9e513ceb..483efd17c3 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -89,7 +89,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr
address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5];
}
address->prefixlen = prefixlen;
- address->flags = IFA_F_NOPREFIXROUTE;
+ address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
address->cinfo.ifa_prefered = lifetime_preferred;
address->cinfo.ifa_valid = lifetime_valid;
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index 385338849f..a2c00161d3 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -56,7 +56,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin
assert(link);
assert(m);
assert(t);
- assert(t->family == AF_INET);
+ assert(t->family == AF_INET || t->family != -1);
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
if (r < 0)
@@ -89,7 +89,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink
assert(link);
assert(m);
assert(t);
- assert(t->family == AF_INET);
+ assert(t->family == AF_INET || t->family != -1);
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
if (r < 0)
@@ -126,7 +126,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink
t = GRETAP(netdev);
assert(t);
- assert(t->family == AF_INET);
+ assert(t->family == AF_INET || t->family != -1);
assert(link);
assert(m);
@@ -358,12 +358,7 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
assert(t);
- if (t->remote.in.s_addr == INADDR_ANY) {
- log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
- return -EINVAL;
- }
-
- if (t->family != AF_INET && t->family != AF_INET6) {
+ if (t->family != AF_INET && t->family != AF_INET6 && t->family != 0) {
log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
return -EINVAL;
}
@@ -397,15 +392,21 @@ int config_parse_tunnel_address(const char *unit,
assert(rvalue);
assert(data);
- r = in_addr_from_string_auto(rvalue, &f, &buffer);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
+ if (streq(rvalue, "any")) {
+ t->family = 0;
return 0;
- }
+ } else {
- if (t->family != AF_UNSPEC && t->family != f) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
- return 0;
+ r = in_addr_from_string_auto(rvalue, &f, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if (t->family != AF_UNSPEC && t->family != f) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
+ return 0;
+ }
}
t->family = f;
@@ -498,6 +499,7 @@ static void ipip_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
+ t->family = -1;
}
static void sit_init(NetDev *n) {
@@ -507,6 +509,7 @@ static void sit_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
+ t->family = -1;
}
static void vti_init(NetDev *n) {
@@ -537,6 +540,7 @@ static void gre_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
+ t->family = -1;
}
static void ip6gre_init(NetDev *n) {
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 2f2a36ccca..409df1709f 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -43,7 +43,7 @@ Network.IPv6Token, config_parse_ipv6token,
Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp)
Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
-Network.Domains, config_parse_domains, 0, offsetof(Network, domains)
+Network.Domains, config_parse_domains, 0, 0
Network.DNS, config_parse_strv, 0, offsetof(Network, dns)
Network.LLMNR, config_parse_resolve_support, 0, offsetof(Network, llmnr)
Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns)
@@ -68,19 +68,19 @@ Route.Metric, config_parse_route_priority,
Route.Scope, config_parse_route_scope, 0, 0
Route.PreferredSource, config_parse_preferred_src, 0, 0
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
-DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
-DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp)
-DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
-DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
-DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains)
-DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes)
-DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost)
-DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname)
+DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
+DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp)
+DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
+DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
+DHCP.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
+DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
+DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
+DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
-DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone)
+DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns)
@@ -101,9 +101,9 @@ BridgeFDB.MACAddress, config_parse_fdb_hwaddr,
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
/* backwards compatibility: do not add new entries to this section */
Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
-DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
-DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
-DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
-DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
-DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
+DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
+DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu)
+DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
+DHCP.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
+DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index c11cb3dcb3..e1a811129d 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -105,11 +105,11 @@ static int network_load_one(Manager *manager, const char *filename) {
*d = '\0';
network->dhcp = ADDRESS_FAMILY_NO;
- network->dhcp_ntp = true;
- network->dhcp_dns = true;
- network->dhcp_hostname = true;
- network->dhcp_routes = true;
- network->dhcp_sendhost = true;
+ network->dhcp_use_ntp = true;
+ network->dhcp_use_dns = true;
+ network->dhcp_use_hostname = true;
+ network->dhcp_use_routes = true;
+ network->dhcp_send_hostname = true;
network->dhcp_route_metric = DHCP_ROUTE_METRIC;
network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
@@ -227,13 +227,14 @@ void network_free(Network *network) {
free(network->description);
free(network->dhcp_vendor_class_identifier);
- free(network->hostname);
+ free(network->dhcp_hostname);
free(network->mac);
strv_free(network->ntp);
strv_free(network->dns);
- strv_free(network->domains);
+ strv_free(network->search_domains);
+ strv_free(network->route_domains);
strv_free(network->bind_carrier);
netdev_unref(network->bridge);
@@ -384,7 +385,10 @@ int network_apply(Manager *manager, Network *network, Link *link) {
route->protocol = RTPROT_STATIC;
}
- if (network->dns || network->ntp || network->domains) {
+ if (!strv_isempty(network->dns) ||
+ !strv_isempty(network->ntp) ||
+ !strv_isempty(network->search_domains) ||
+ !strv_isempty(network->route_domains)) {
manager_dirty(manager);
link_dirty(link);
}
@@ -469,49 +473,85 @@ int config_parse_netdev(const char *unit,
return 0;
}
-int config_parse_domains(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
- Network *network = userdata;
- char ***domains = data;
- char **domain;
+int config_parse_domains(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ const char *p;
+ Network *n = data;
int r;
- r = config_parse_strv(unit, filename, line, section, section_line,
- lvalue, ltype, rvalue, domains, userdata);
- if (r < 0)
- return r;
+ assert(n);
+ assert(lvalue);
+ assert(rvalue);
- strv_uniq(*domains);
- network->wildcard_domain = !!strv_find(*domains, "*");
+ if (isempty(rvalue)) {
+ n->search_domains = strv_free(n->search_domains);
+ n->route_domains = strv_free(n->route_domains);
+ return 0;
+ }
- STRV_FOREACH(domain, *domains) {
- if (is_localhost(*domain))
- log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
- else {
- r = dns_name_is_valid(*domain);
- if (r <= 0 && !streq(*domain, "*")) {
- if (r < 0)
- log_error_errno(r, "Failed to validate domain name: %s: %m", *domain);
- if (r == 0)
- log_warning("Domain name is not valid, ignoring assignment: %s", *domain);
- } else
+ p = rvalue;
+ for (;;) {
+ _cleanup_free_ char *w = NULL, *normalized = NULL;
+ const char *domain;
+ bool is_route;
+
+ r = extract_first_word(&p, &w, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
+ break;
+ }
+ if (r == 0)
+ break;
+
+ is_route = w[0] == '~';
+ domain = is_route ? w + 1 : w;
+
+ if (dns_name_is_root(domain) || streq(domain, "*")) {
+ /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
+ * routing domain, unconditionally. */
+ is_route = true;
+ domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
+
+ } else {
+ r = dns_name_normalize(domain, &normalized);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
+ continue;
+ }
+
+ domain = normalized;
+
+ if (is_localhost(domain)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
continue;
+ }
}
- strv_remove(*domains, *domain);
+ if (is_route) {
+ r = strv_extend(&n->route_domains, domain);
+ if (r < 0)
+ return log_oom();
- /* We removed one entry, make sure we don't skip the next one */
- domain--;
+ } else {
+ r = strv_extend(&n->search_domains, domain);
+ if (r < 0)
+ return log_oom();
+ }
}
+ strv_uniq(n->route_domains);
+ strv_uniq(n->search_domains);
+
return 0;
}
@@ -930,7 +970,7 @@ int config_parse_dnssec_negative_trust_anchors(
Network *n = data;
int r;
- assert(filename);
+ assert(n);
assert(lvalue);
assert(rvalue);
@@ -965,3 +1005,13 @@ int config_parse_dnssec_negative_trust_anchors(
return 0;
}
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
+
+static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
+ [DHCP_USE_DOMAINS_NO] = "no",
+ [DHCP_USE_DOMAINS_ROUTE] = "route",
+ [DHCP_USE_DOMAINS_YES] = "yes",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index b07fa41abc..626dfbd40a 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -52,6 +52,14 @@ typedef enum IPv6PrivacyExtensions {
_IPV6_PRIVACY_EXTENSIONS_INVALID = -1,
} IPv6PrivacyExtensions;
+typedef enum DHCPUseDomains {
+ DHCP_USE_DOMAINS_NO,
+ DHCP_USE_DOMAINS_YES,
+ DHCP_USE_DOMAINS_ROUTE,
+ _DHCP_USE_DOMAINS_MAX,
+ _DHCP_USE_DOMAINS_INVALID = -1,
+} DHCPUseDomains;
+
struct Network {
Manager *manager;
@@ -79,17 +87,17 @@ struct Network {
AddressFamilyBoolean dhcp;
DCHPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
- char *hostname;
- bool dhcp_dns;
- bool dhcp_ntp;
- bool dhcp_mtu;
- bool dhcp_hostname;
- bool dhcp_domains;
- bool dhcp_sendhost;
+ char *dhcp_hostname;
+ bool dhcp_use_dns;
+ bool dhcp_use_ntp;
+ bool dhcp_use_mtu;
+ bool dhcp_use_hostname;
+ DHCPUseDomains dhcp_use_domains;
+ bool dhcp_send_hostname;
bool dhcp_broadcast;
bool dhcp_critical;
- bool dhcp_routes;
- bool dhcp_timezone;
+ bool dhcp_use_routes;
+ bool dhcp_use_timezone;
unsigned dhcp_route_metric;
/* DHCP Server Support */
@@ -141,8 +149,7 @@ struct Network {
Hashmap *routes_by_section;
Hashmap *fdb_entries_by_section;
- bool wildcard_domain;
- char **domains, **dns, **ntp, **bind_carrier;
+ char **search_domains, **route_domains, **dns, **ntp, **bind_carrier;
ResolveSupport llmnr;
ResolveSupport mdns;
@@ -175,6 +182,7 @@ int config_parse_timezone(const char *unit, const char *filename, unsigned line,
int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -188,3 +196,6 @@ int network_object_find(sd_bus *bus, const char *path, const char *interface, vo
const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
+
+const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
+DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;