Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <net/if.h>
4 : : #include <netinet/in.h>
5 : : #include <linux/netdevice.h>
6 : :
7 : : #include "alloc-util.h"
8 : : #include "conf-files.h"
9 : : #include "conf-parser.h"
10 : : #include "dns-domain.h"
11 : : #include "fd-util.h"
12 : : #include "hostname-util.h"
13 : : #include "in-addr-util.h"
14 : : #include "network-internal.h"
15 : : #include "networkd-manager.h"
16 : : #include "networkd-network.h"
17 : : #include "parse-util.h"
18 : : #include "set.h"
19 : : #include "socket-util.h"
20 : : #include "stat-util.h"
21 : : #include "string-table.h"
22 : : #include "string-util.h"
23 : : #include "strv.h"
24 : : #include "util.h"
25 : :
26 : : /* Let's assume that anything above this number is a user misconfiguration. */
27 : : #define MAX_NTP_SERVERS 128
28 : :
29 : : /* Set defaults following RFC7844 */
30 : 12 : void network_apply_anonymize_if_set(Network *network) {
31 [ + - ]: 12 : if (!network->dhcp_anonymize)
32 : 12 : return;
33 : : /* RFC7844 3.7
34 : : SHOULD NOT send the Host Name option */
35 : 0 : network->dhcp_send_hostname = false;
36 : : /* RFC7844 section 3.:
37 : : MAY contain the Client Identifier option
38 : : Section 3.5:
39 : : clients MUST use client identifiers based solely
40 : : on the link-layer address */
41 : : /* NOTE: Using MAC, as it does not reveal extra information,
42 : : * and some servers might not answer if this option is not sent */
43 : 0 : network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
44 : : /* RFC 7844 3.10:
45 : : SHOULD NOT use the Vendor Class Identifier option */
46 : 0 : network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
47 : : /* RFC7844 section 3.6.:
48 : : The client intending to protect its privacy SHOULD only request a
49 : : minimal number of options in the PRL and SHOULD also randomly shuffle
50 : : the ordering of option codes in the PRL. If this random ordering
51 : : cannot be implemented, the client MAY order the option codes in the
52 : : PRL by option code number (lowest to highest).
53 : : */
54 : : /* NOTE: dhcp_use_mtu is false by default,
55 : : * though it was not initiallized to any value in network_load_one.
56 : : * Maybe there should be another var called *send*?
57 : : * (to use the MTU sent by the server but to do not send
58 : : * the option in the PRL). */
59 : 0 : network->dhcp_use_mtu = false;
60 : : /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
61 : : * but this is needed to use them. */
62 : 0 : network->dhcp_use_routes = true;
63 : : /* RFC7844 section 3.6.
64 : : * same comments as previous option */
65 : 0 : network->dhcp_use_timezone = false;
66 : : }
67 : :
68 : 300 : static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
69 : : const char *kind_string;
70 : : NetDev *netdev;
71 : : int r;
72 : :
73 : : /* For test-networkd-conf, the check must be earlier than the assertions. */
74 [ + - ]: 300 : if (!name)
75 : 300 : return 0;
76 : :
77 [ # # ]: 0 : assert(network);
78 [ # # ]: 0 : assert(network->manager);
79 [ # # ]: 0 : assert(network->filename);
80 [ # # ]: 0 : assert(ret_netdev);
81 : :
82 [ # # ]: 0 : if (kind == _NETDEV_KIND_TUNNEL)
83 : 0 : kind_string = "tunnel";
84 : : else {
85 : 0 : kind_string = netdev_kind_to_string(kind);
86 [ # # ]: 0 : if (!kind_string)
87 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
88 : : "%s: Invalid NetDev kind of %s, ignoring assignment.",
89 : : network->filename, name);
90 : : }
91 : :
92 : 0 : r = netdev_get(network->manager, name, &netdev);
93 [ # # ]: 0 : if (r < 0)
94 [ # # ]: 0 : return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
95 : : network->filename, name);
96 : :
97 [ # # # # ]: 0 : if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
98 [ # # # # ]: 0 : IN_SET(netdev->kind,
99 : : NETDEV_KIND_IPIP,
100 : : NETDEV_KIND_SIT,
101 : : NETDEV_KIND_GRE,
102 : : NETDEV_KIND_GRETAP,
103 : : NETDEV_KIND_IP6GRE,
104 : : NETDEV_KIND_IP6GRETAP,
105 : : NETDEV_KIND_VTI,
106 : : NETDEV_KIND_VTI6,
107 : : NETDEV_KIND_IP6TNL,
108 : : NETDEV_KIND_ERSPAN)))
109 [ # # ]: 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
110 : : "%s: NetDev %s is not a %s, ignoring assignment",
111 : : network->filename, name, kind_string);
112 : :
113 : 0 : *ret_netdev = netdev_ref(netdev);
114 : 0 : return 1;
115 : : }
116 : :
117 : 100 : static int network_resolve_stacked_netdevs(Network *network) {
118 : : void *name, *kind;
119 : : Iterator i;
120 : : int r;
121 : :
122 [ - + ]: 100 : assert(network);
123 : :
124 [ - + ]: 100 : HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) {
125 [ # # # ]: 0 : _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
126 : :
127 : 0 : r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
128 [ # # ]: 0 : if (r <= 0)
129 : 0 : continue;
130 : :
131 : 0 : r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
132 [ # # ]: 0 : if (r < 0)
133 : 0 : return log_oom();
134 : :
135 : 0 : r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
136 [ # # ]: 0 : if (r < 0)
137 [ # # ]: 0 : return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
138 : : network->filename, (const char *) name);
139 : :
140 : 0 : netdev = NULL;
141 : : }
142 : :
143 : 100 : return 0;
144 : : }
145 : :
146 : 104 : int network_verify(Network *network) {
147 : : Address *address, *address_next;
148 : : Route *route, *route_next;
149 : : FdbEntry *fdb, *fdb_next;
150 : : Neighbor *neighbor, *neighbor_next;
151 : : AddressLabel *label, *label_next;
152 : : Prefix *prefix, *prefix_next;
153 : : RoutingPolicyRule *rule, *rule_next;
154 : :
155 [ - + ]: 104 : assert(network);
156 [ - + ]: 104 : assert(network->filename);
157 : :
158 [ + - + - : 208 : if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
+ + ]
159 [ + - - + ]: 296 : strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
160 [ # # ]: 96 : strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
161 [ # # ]: 0 : !network->conditions)
162 [ # # ]: 0 : log_warning("%s: No valid settings found in the [Match] section. "
163 : : "The file will match all interfaces. "
164 : : "If that is intended, please add Name=* in the [Match] section.",
165 : : network->filename);
166 : :
167 : : /* skip out early if configuration does not match the environment */
168 [ + + ]: 104 : if (!condition_test_list(network->conditions, NULL, NULL, NULL))
169 [ - + ]: 4 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
170 : : "%s: Conditions in the file do not match the system environment, skipping.",
171 : : network->filename);
172 : :
173 : 100 : (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
174 : 100 : (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
175 : 100 : (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
176 : 100 : (void) network_resolve_stacked_netdevs(network);
177 : :
178 : : /* Free unnecessary entries. */
179 : 100 : network->bond_name = mfree(network->bond_name);
180 : 100 : network->bridge_name = mfree(network->bridge_name);
181 : 100 : network->vrf_name = mfree(network->vrf_name);
182 : 100 : network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
183 : :
184 [ - + ]: 100 : if (network->bond) {
185 : : /* Bonding slave does not support addressing. */
186 [ # # ]: 0 : if (network->ipv6_accept_ra > 0) {
187 [ # # ]: 0 : log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
188 : : network->filename);
189 : 0 : network->ipv6_accept_ra = 0;
190 : : }
191 [ # # # # ]: 0 : if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
192 [ # # ]: 0 : log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
193 : : network->filename);
194 : 0 : network->link_local = ADDRESS_FAMILY_NO;
195 : : }
196 [ # # ]: 0 : if (network->dhcp != ADDRESS_FAMILY_NO) {
197 [ # # ]: 0 : log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
198 : : network->filename);
199 : 0 : network->dhcp = ADDRESS_FAMILY_NO;
200 : : }
201 [ # # ]: 0 : if (network->dhcp_server) {
202 [ # # ]: 0 : log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
203 : : network->filename);
204 : 0 : network->dhcp_server = false;
205 : : }
206 [ # # ]: 0 : if (network->n_static_addresses > 0) {
207 [ # # ]: 0 : log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
208 : : network->filename);
209 [ # # ]: 0 : while ((address = network->static_addresses))
210 : 0 : address_free(address);
211 : : }
212 [ # # ]: 0 : if (network->n_static_routes > 0) {
213 [ # # ]: 0 : log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
214 : : network->filename);
215 [ # # ]: 0 : while ((route = network->static_routes))
216 : 0 : route_free(route);
217 : : }
218 : : }
219 : :
220 [ - + ]: 100 : if (network->link_local < 0)
221 [ # # ]: 0 : network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
222 : :
223 [ - + ]: 100 : if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
224 [ # # ]: 0 : !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
225 [ # # ]: 0 : log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
226 : : "Disabling the fallback assignment.", network->filename);
227 : 0 : SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
228 : : }
229 : :
230 [ + + - + ]: 100 : if (network->ipv6_accept_ra < 0 && network->bridge)
231 : 0 : network->ipv6_accept_ra = false;
232 : :
233 : : /* IPMasquerade=yes implies IPForward=yes */
234 [ + + ]: 100 : if (network->ip_masquerade)
235 : 8 : network->ip_forward |= ADDRESS_FAMILY_IPV4;
236 : :
237 [ - + # # ]: 100 : if (network->mtu > 0 && network->dhcp_use_mtu) {
238 [ # # ]: 0 : log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
239 : : "Disabling UseMTU=.", network->filename);
240 : 0 : network->dhcp_use_mtu = false;
241 : : }
242 : :
243 [ + + ]: 100 : if (network->dhcp_critical >= 0) {
244 [ + - ]: 92 : if (network->keep_configuration >= 0)
245 [ + - ]: 92 : log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
246 : : "Ignoring CriticalConnection=.", network->filename);
247 [ # # ]: 0 : else if (network->dhcp_critical)
248 : : /* CriticalConnection=yes also preserve foreign static configurations. */
249 : 0 : network->keep_configuration = KEEP_CONFIGURATION_YES;
250 : : else
251 : : /* For backward compatibility, we do not release DHCP addresses on manager stop. */
252 : 0 : network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
253 : : }
254 : :
255 [ + + ]: 100 : if (network->keep_configuration < 0)
256 : : /* For backward compatibility, we do not release DHCP addresses on manager stop. */
257 : 8 : network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
258 : :
259 [ + + ]: 200 : LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
260 [ + + ]: 100 : if (address_section_verify(address) < 0)
261 : 40 : address_free(address);
262 : :
263 [ - + ]: 100 : LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
264 [ # # ]: 0 : if (route_section_verify(route, network) < 0)
265 : 0 : route_free(route);
266 : :
267 [ - + ]: 100 : LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
268 [ # # ]: 0 : if (section_is_invalid(fdb->section))
269 : 0 : fdb_entry_free(fdb);
270 : :
271 [ - + ]: 100 : LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
272 [ # # ]: 0 : if (neighbor_section_verify(neighbor) < 0)
273 : 0 : neighbor_free(neighbor);
274 : :
275 [ - + ]: 100 : LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
276 [ # # ]: 0 : if (section_is_invalid(label->section))
277 : 0 : address_label_free(label);
278 : :
279 [ - + ]: 100 : LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
280 [ # # ]: 0 : if (section_is_invalid(prefix->section))
281 : 0 : prefix_free(prefix);
282 : :
283 [ - + ]: 100 : LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
284 [ # # ]: 0 : if (routing_policy_rule_section_verify(rule) < 0)
285 : 0 : routing_policy_rule_free(rule);
286 : :
287 : 100 : return 0;
288 : : }
289 : :
290 : 12 : int network_load_one(Manager *manager, const char *filename) {
291 : 12 : _cleanup_free_ char *fname = NULL, *name = NULL;
292 : 12 : _cleanup_(network_unrefp) Network *network = NULL;
293 : 12 : _cleanup_fclose_ FILE *file = NULL;
294 : : const char *dropin_dirname;
295 : : char *d;
296 : : int r;
297 : :
298 [ - + ]: 12 : assert(manager);
299 [ - + ]: 12 : assert(filename);
300 : :
301 : 12 : file = fopen(filename, "re");
302 [ - + ]: 12 : if (!file) {
303 [ # # ]: 0 : if (errno == ENOENT)
304 : 0 : return 0;
305 : :
306 : 0 : return -errno;
307 : : }
308 : :
309 [ - + ]: 12 : if (null_or_empty_fd(fileno(file))) {
310 [ # # ]: 0 : log_debug("Skipping empty file: %s", filename);
311 : 0 : return 0;
312 : : }
313 : :
314 : 12 : fname = strdup(filename);
315 [ - + ]: 12 : if (!fname)
316 : 0 : return log_oom();
317 : :
318 : 12 : name = strdup(basename(filename));
319 [ - + ]: 12 : if (!name)
320 : 0 : return log_oom();
321 : :
322 : 12 : d = strrchr(name, '.');
323 [ - + ]: 12 : if (!d)
324 : 0 : return -EINVAL;
325 : :
326 : 12 : *d = '\0';
327 : :
328 [ + + + - : 60 : dropin_dirname = strjoina(name, ".network.d");
- + - + +
+ + - ]
329 : :
330 : 12 : network = new(Network, 1);
331 [ - + ]: 12 : if (!network)
332 : 0 : return log_oom();
333 : :
334 : 24 : *network = (Network) {
335 : 12 : .filename = TAKE_PTR(fname),
336 : 12 : .name = TAKE_PTR(name),
337 : :
338 : : .manager = manager,
339 : : .n_ref = 1,
340 : :
341 : : .required_for_online = true,
342 : : .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
343 : : .dhcp = ADDRESS_FAMILY_NO,
344 : : .dhcp_critical = -1,
345 : : .dhcp_use_ntp = true,
346 : : .dhcp_use_dns = true,
347 : : .dhcp_use_hostname = true,
348 : : .dhcp_use_routes = true,
349 : : /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
350 : : .dhcp_send_hostname = true,
351 : : /* To enable/disable RFC7844 Anonymity Profiles */
352 : : .dhcp_anonymize = false,
353 : : .dhcp_route_metric = DHCP_ROUTE_METRIC,
354 : : /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
355 : : .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
356 : : .dhcp_route_table = RT_TABLE_MAIN,
357 : : .dhcp_route_table_set = false,
358 : : /* NOTE: from man: UseMTU=... Defaults to false*/
359 : : .dhcp_use_mtu = false,
360 : : /* NOTE: from man: UseTimezone=... Defaults to "no".*/
361 : : .dhcp_use_timezone = false,
362 : : .rapid_commit = true,
363 : :
364 : : .dhcp6_use_ntp = true,
365 : : .dhcp6_use_dns = true,
366 : :
367 : : .dhcp_server_emit_dns = true,
368 : : .dhcp_server_emit_ntp = true,
369 : : .dhcp_server_emit_router = true,
370 : : .dhcp_server_emit_timezone = true,
371 : :
372 : : .router_emit_dns = true,
373 : : .router_emit_domains = true,
374 : :
375 : : .use_bpdu = -1,
376 : : .hairpin = -1,
377 : : .fast_leave = -1,
378 : : .allow_port_to_be_root = -1,
379 : : .unicast_flood = -1,
380 : : .multicast_flood = -1,
381 : : .multicast_to_unicast = -1,
382 : : .neighbor_suppression = -1,
383 : : .learning = -1,
384 : : .bridge_proxy_arp = -1,
385 : : .bridge_proxy_arp_wifi = -1,
386 : : .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
387 : : .multicast_router = _MULTICAST_ROUTER_INVALID,
388 : :
389 : : .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
390 : :
391 : : .dns_default_route = -1,
392 : : .llmnr = RESOLVE_SUPPORT_YES,
393 : : .mdns = RESOLVE_SUPPORT_NO,
394 : : .dnssec_mode = _DNSSEC_MODE_INVALID,
395 : : .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
396 : :
397 : : /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
398 : : .link_local = _ADDRESS_FAMILY_INVALID,
399 : :
400 : : .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
401 : : .ipv6_accept_ra = -1,
402 : : .ipv6_dad_transmits = -1,
403 : : .ipv6_hop_limit = -1,
404 : : .ipv6_proxy_ndp = -1,
405 : : .duid.type = _DUID_TYPE_INVALID,
406 : : .proxy_arp = -1,
407 : : .arp = -1,
408 : : .multicast = -1,
409 : : .allmulticast = -1,
410 : : .ipv6_accept_ra_use_dns = true,
411 : : .ipv6_accept_ra_use_autonomous_prefix = true,
412 : : .ipv6_accept_ra_use_onlink_prefix = true,
413 : : .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
414 : : .ipv6_accept_ra_route_table_set = false,
415 : :
416 : : .keep_configuration = _KEEP_CONFIGURATION_INVALID,
417 : :
418 : : .can_triple_sampling = -1,
419 : : };
420 : :
421 : 12 : r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
422 : : "Match\0"
423 : : "Link\0"
424 : : "Network\0"
425 : : "Address\0"
426 : : "Neighbor\0"
427 : : "IPv6AddressLabel\0"
428 : : "RoutingPolicyRule\0"
429 : : "Route\0"
430 : : "DHCP\0"
431 : : "DHCPv4\0" /* compat */
432 : : "DHCPv6\0"
433 : : "DHCPServer\0"
434 : : "IPv6AcceptRA\0"
435 : : "IPv6NDPProxyAddress\0"
436 : : "Bridge\0"
437 : : "BridgeFDB\0"
438 : : "BridgeVLAN\0"
439 : : "IPv6PrefixDelegation\0"
440 : : "IPv6Prefix\0"
441 : : "CAN\0",
442 : : config_item_perf_lookup, network_network_gperf_lookup,
443 : : CONFIG_PARSE_WARN, network);
444 [ - + ]: 12 : if (r < 0)
445 : 0 : return r;
446 : :
447 : 12 : network_apply_anonymize_if_set(network);
448 : :
449 : 12 : r = network_add_ipv4ll_route(network);
450 [ - + ]: 12 : if (r < 0)
451 [ # # ]: 0 : log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
452 : :
453 : 12 : r = network_add_default_route_on_device(network);
454 [ - + ]: 12 : if (r < 0)
455 [ # # ]: 0 : log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
456 : : network->filename);
457 : :
458 : 12 : r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
459 [ - + ]: 12 : if (r < 0)
460 : 0 : return r;
461 : :
462 : 12 : r = ordered_hashmap_put(manager->networks, network->name, network);
463 [ - + ]: 12 : if (r < 0)
464 : 0 : return r;
465 : :
466 [ + + ]: 12 : if (network_verify(network) < 0)
467 : 4 : return 0;
468 : :
469 : 8 : network = NULL;
470 : 8 : return 0;
471 : : }
472 : :
473 : 4 : int network_load(Manager *manager) {
474 : 4 : _cleanup_strv_free_ char **files = NULL;
475 : : char **f;
476 : : int r;
477 : :
478 [ - + ]: 4 : assert(manager);
479 : :
480 [ - + ]: 4 : ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
481 : :
482 : 4 : r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
483 [ - + ]: 4 : if (r < 0)
484 [ # # ]: 0 : return log_error_errno(r, "Failed to enumerate network files: %m");
485 : :
486 [ + - + + ]: 16 : STRV_FOREACH(f, files) {
487 : 12 : r = network_load_one(manager, *f);
488 [ - + ]: 12 : if (r < 0)
489 : 0 : return r;
490 : : }
491 : :
492 : 4 : return 0;
493 : : }
494 : :
495 : 104 : static Network *network_free(Network *network) {
496 : : IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
497 : : RoutingPolicyRule *rule;
498 : : FdbEntry *fdb_entry;
499 : : Neighbor *neighbor;
500 : : AddressLabel *label;
501 : : Prefix *prefix;
502 : : Address *address;
503 : : Route *route;
504 : :
505 [ - + ]: 104 : if (!network)
506 : 0 : return NULL;
507 : :
508 : 104 : free(network->filename);
509 : :
510 : 104 : set_free_free(network->match_mac);
511 : 104 : strv_free(network->match_path);
512 : 104 : strv_free(network->match_driver);
513 : 104 : strv_free(network->match_type);
514 : 104 : strv_free(network->match_name);
515 : 104 : strv_free(network->match_property);
516 : 104 : condition_free_list(network->conditions);
517 : :
518 : 104 : free(network->description);
519 : 104 : free(network->dhcp_vendor_class_identifier);
520 : 104 : strv_free(network->dhcp_user_class);
521 : 104 : free(network->dhcp_hostname);
522 : 104 : set_free(network->dhcp_black_listed_ip);
523 : 104 : free(network->mac);
524 : :
525 : 104 : strv_free(network->ntp);
526 : 104 : free(network->dns);
527 : 104 : ordered_set_free_free(network->search_domains);
528 : 104 : ordered_set_free_free(network->route_domains);
529 : 104 : strv_free(network->bind_carrier);
530 : :
531 : 104 : ordered_set_free_free(network->router_search_domains);
532 : 104 : free(network->router_dns);
533 : 104 : set_free_free(network->ndisc_black_listed_prefix);
534 : :
535 : 104 : free(network->bridge_name);
536 : 104 : free(network->bond_name);
537 : 104 : free(network->vrf_name);
538 : 104 : hashmap_free_free_key(network->stacked_netdev_names);
539 : 104 : netdev_unref(network->bridge);
540 : 104 : netdev_unref(network->bond);
541 : 104 : netdev_unref(network->vrf);
542 [ - + ]: 104 : hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
543 : :
544 [ - + ]: 104 : while ((route = network->static_routes))
545 : 0 : route_free(route);
546 : :
547 [ + + ]: 164 : while ((address = network->static_addresses))
548 : 60 : address_free(address);
549 : :
550 [ - + ]: 104 : while ((fdb_entry = network->static_fdb_entries))
551 : 0 : fdb_entry_free(fdb_entry);
552 : :
553 [ - + ]: 104 : while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
554 : 0 : ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
555 : :
556 [ - + ]: 104 : while ((neighbor = network->neighbors))
557 : 0 : neighbor_free(neighbor);
558 : :
559 [ - + ]: 104 : while ((label = network->address_labels))
560 : 0 : address_label_free(label);
561 : :
562 [ - + ]: 104 : while ((prefix = network->static_prefixes))
563 : 0 : prefix_free(prefix);
564 : :
565 [ - + ]: 104 : while ((rule = network->rules))
566 : 0 : routing_policy_rule_free(rule);
567 : :
568 : 104 : hashmap_free(network->addresses_by_section);
569 : 104 : hashmap_free(network->routes_by_section);
570 : 104 : hashmap_free(network->fdb_entries_by_section);
571 : 104 : hashmap_free(network->neighbors_by_section);
572 : 104 : hashmap_free(network->address_labels_by_section);
573 : 104 : hashmap_free(network->prefixes_by_section);
574 : 104 : hashmap_free(network->rules_by_section);
575 : :
576 [ + + ]: 104 : if (network->manager) {
577 [ + - + - ]: 12 : if (network->manager->networks && network->name)
578 : 12 : ordered_hashmap_remove(network->manager->networks, network->name);
579 : :
580 [ - + ]: 12 : if (network->manager->duids_requesting_uuid)
581 : 0 : set_remove(network->manager->duids_requesting_uuid, &network->duid);
582 : : }
583 : :
584 : 104 : free(network->name);
585 : :
586 : 104 : free(network->dhcp_server_timezone);
587 : 104 : free(network->dhcp_server_dns);
588 : 104 : free(network->dhcp_server_ntp);
589 : :
590 : 104 : set_free_free(network->dnssec_negative_trust_anchors);
591 : :
592 : 104 : return mfree(network);
593 : : }
594 : :
595 [ + + - + : 132 : DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
- + ]
596 : :
597 : 0 : int network_get_by_name(Manager *manager, const char *name, Network **ret) {
598 : : Network *network;
599 : :
600 [ # # ]: 0 : assert(manager);
601 [ # # ]: 0 : assert(name);
602 [ # # ]: 0 : assert(ret);
603 : :
604 : 0 : network = ordered_hashmap_get(manager->networks, name);
605 [ # # ]: 0 : if (!network)
606 : 0 : return -ENOENT;
607 : :
608 : 0 : *ret = network;
609 : :
610 : 0 : return 0;
611 : : }
612 : :
613 : 4 : int network_get(Manager *manager, sd_device *device,
614 : : const char *ifname, const struct ether_addr *address,
615 : : Network **ret) {
616 : : Network *network;
617 : : Iterator i;
618 : :
619 [ - + ]: 4 : assert(manager);
620 [ - + ]: 4 : assert(ret);
621 : :
622 [ + + ]: 12 : ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
623 [ - + ]: 8 : if (net_match_config(network->match_mac, network->match_path, network->match_driver,
624 : 8 : network->match_type, network->match_name, network->match_property,
625 : : device, address, ifname)) {
626 [ # # # # ]: 0 : if (network->match_name && device) {
627 : : const char *attr;
628 : 0 : uint8_t name_assign_type = NET_NAME_UNKNOWN;
629 : :
630 [ # # ]: 0 : if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
631 : 0 : (void) safe_atou8(attr, &name_assign_type);
632 : :
633 [ # # ]: 0 : if (name_assign_type == NET_NAME_ENUM)
634 [ # # ]: 0 : log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
635 : : ifname, network->filename);
636 : : else
637 [ # # ]: 0 : log_debug("%s: found matching network '%s'", ifname, network->filename);
638 : : } else
639 [ # # ]: 0 : log_debug("%s: found matching network '%s'", ifname, network->filename);
640 : :
641 : 0 : *ret = network;
642 : 0 : return 0;
643 : : }
644 : :
645 : 4 : *ret = NULL;
646 : :
647 : 4 : return -ENOENT;
648 : : }
649 : :
650 : 0 : int network_apply(Network *network, Link *link) {
651 [ # # ]: 0 : assert(network);
652 [ # # ]: 0 : assert(link);
653 : :
654 : 0 : link->network = network_ref(network);
655 : :
656 [ # # ]: 0 : if (network->n_dns > 0 ||
657 [ # # ]: 0 : !strv_isempty(network->ntp) ||
658 [ # # ]: 0 : !ordered_set_isempty(network->search_domains) ||
659 [ # # ]: 0 : !ordered_set_isempty(network->route_domains))
660 : 0 : link_dirty(link);
661 : :
662 : 0 : return 0;
663 : : }
664 : :
665 : 0 : bool network_has_static_ipv6_addresses(Network *network) {
666 : : Address *address;
667 : :
668 [ # # ]: 0 : assert(network);
669 : :
670 [ # # ]: 0 : LIST_FOREACH(addresses, address, network->static_addresses) {
671 [ # # ]: 0 : if (address->family == AF_INET6)
672 : 0 : return true;
673 : : }
674 : :
675 : 0 : return false;
676 : : }
677 : :
678 : 0 : int config_parse_stacked_netdev(const char *unit,
679 : : const char *filename,
680 : : unsigned line,
681 : : const char *section,
682 : : unsigned section_line,
683 : : const char *lvalue,
684 : : int ltype,
685 : : const char *rvalue,
686 : : void *data,
687 : : void *userdata) {
688 : 0 : _cleanup_free_ char *name = NULL;
689 : 0 : NetDevKind kind = ltype;
690 : 0 : Hashmap **h = data;
691 : : int r;
692 : :
693 [ # # ]: 0 : assert(filename);
694 [ # # ]: 0 : assert(lvalue);
695 [ # # ]: 0 : assert(rvalue);
696 [ # # ]: 0 : assert(data);
697 [ # # # # ]: 0 : assert(IN_SET(kind,
698 : : NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
699 : : NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
700 : : NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL,
701 : : NETDEV_KIND_XFRM));
702 : :
703 [ # # ]: 0 : if (!ifname_valid(rvalue)) {
704 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
705 : : "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
706 : 0 : return 0;
707 : : }
708 : :
709 : 0 : name = strdup(rvalue);
710 [ # # ]: 0 : if (!name)
711 : 0 : return log_oom();
712 : :
713 : 0 : r = hashmap_ensure_allocated(h, &string_hash_ops);
714 [ # # ]: 0 : if (r < 0)
715 : 0 : return log_oom();
716 : :
717 : 0 : r = hashmap_put(*h, name, INT_TO_PTR(kind));
718 [ # # ]: 0 : if (r < 0)
719 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
720 : : "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
721 [ # # ]: 0 : else if (r == 0)
722 [ # # ]: 0 : log_syntax(unit, LOG_DEBUG, filename, line, r,
723 : : "NetDev '%s' specified twice, ignoring.", name);
724 : : else
725 : 0 : name = NULL;
726 : :
727 : 0 : return 0;
728 : : }
729 : :
730 : 0 : int config_parse_domains(
731 : : const char *unit,
732 : : const char *filename,
733 : : unsigned line,
734 : : const char *section,
735 : : unsigned section_line,
736 : : const char *lvalue,
737 : : int ltype,
738 : : const char *rvalue,
739 : : void *data,
740 : : void *userdata) {
741 : :
742 : : const char *p;
743 : 0 : Network *n = data;
744 : : int r;
745 : :
746 [ # # ]: 0 : assert(n);
747 [ # # ]: 0 : assert(lvalue);
748 [ # # ]: 0 : assert(rvalue);
749 : :
750 [ # # ]: 0 : if (isempty(rvalue)) {
751 : 0 : n->search_domains = ordered_set_free_free(n->search_domains);
752 : 0 : n->route_domains = ordered_set_free_free(n->route_domains);
753 : 0 : return 0;
754 : : }
755 : :
756 : 0 : p = rvalue;
757 : 0 : for (;;) {
758 [ # # # # : 0 : _cleanup_free_ char *w = NULL, *normalized = NULL;
# # # # ]
759 : : const char *domain;
760 : : bool is_route;
761 : :
762 : 0 : r = extract_first_word(&p, &w, NULL, 0);
763 [ # # ]: 0 : if (r < 0) {
764 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
765 : : "Failed to extract search or route domain, ignoring: %s", rvalue);
766 : 0 : break;
767 : : }
768 [ # # ]: 0 : if (r == 0)
769 : 0 : break;
770 : :
771 : 0 : is_route = w[0] == '~';
772 [ # # ]: 0 : domain = is_route ? w + 1 : w;
773 : :
774 [ # # # # ]: 0 : if (dns_name_is_root(domain) || streq(domain, "*")) {
775 : : /* If the root domain appears as is, or the special token "*" is found, we'll
776 : : * consider this as routing domain, unconditionally. */
777 : 0 : is_route = true;
778 : 0 : domain = "."; /* make sure we don't allow empty strings, thus write the root
779 : : * domain as "." */
780 : : } else {
781 : 0 : r = dns_name_normalize(domain, 0, &normalized);
782 [ # # ]: 0 : if (r < 0) {
783 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
784 : : "'%s' is not a valid domain name, ignoring.", domain);
785 : 0 : continue;
786 : : }
787 : :
788 : 0 : domain = normalized;
789 : :
790 [ # # ]: 0 : if (is_localhost(domain)) {
791 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
792 : : "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
793 : : domain);
794 : 0 : continue;
795 : : }
796 : : }
797 : :
798 [ # # ]: 0 : OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
799 : 0 : r = ordered_set_ensure_allocated(set, &string_hash_ops);
800 [ # # ]: 0 : if (r < 0)
801 : 0 : return r;
802 : :
803 : 0 : r = ordered_set_put_strdup(*set, domain);
804 [ # # ]: 0 : if (r < 0)
805 : 0 : return log_oom();
806 : : }
807 : :
808 : 0 : return 0;
809 : : }
810 : :
811 : 0 : int config_parse_ipv6token(
812 : : const char* unit,
813 : : const char *filename,
814 : : unsigned line,
815 : : const char *section,
816 : : unsigned section_line,
817 : : const char *lvalue,
818 : : int ltype,
819 : : const char *rvalue,
820 : : void *data,
821 : : void *userdata) {
822 : :
823 : : union in_addr_union buffer;
824 : 0 : struct in6_addr *token = data;
825 : : int r;
826 : :
827 [ # # ]: 0 : assert(filename);
828 [ # # ]: 0 : assert(lvalue);
829 [ # # ]: 0 : assert(rvalue);
830 [ # # ]: 0 : assert(token);
831 : :
832 : 0 : r = in_addr_from_string(AF_INET6, rvalue, &buffer);
833 [ # # ]: 0 : if (r < 0) {
834 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
835 : : "Failed to parse IPv6 token, ignoring: %s", rvalue);
836 : 0 : return 0;
837 : : }
838 : :
839 [ # # ]: 0 : if (in_addr_is_null(AF_INET6, &buffer)) {
840 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
841 : : "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
842 : 0 : return 0;
843 : : }
844 : :
845 [ # # ]: 0 : if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
846 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
847 : : "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
848 : 0 : return 0;
849 : : }
850 : :
851 : 0 : *token = buffer.in6;
852 : :
853 : 0 : return 0;
854 : : }
855 : :
856 : : static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
857 : : [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
858 : : [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
859 : : [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
860 : : };
861 : :
862 [ + + + + ]: 40 : DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
863 : :
864 : 0 : int config_parse_ipv6_privacy_extensions(
865 : : const char* unit,
866 : : const char *filename,
867 : : unsigned line,
868 : : const char *section,
869 : : unsigned section_line,
870 : : const char *lvalue,
871 : : int ltype,
872 : : const char *rvalue,
873 : : void *data,
874 : : void *userdata) {
875 : :
876 : 0 : IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
877 : : int k;
878 : :
879 [ # # ]: 0 : assert(filename);
880 [ # # ]: 0 : assert(lvalue);
881 [ # # ]: 0 : assert(rvalue);
882 [ # # ]: 0 : assert(ipv6_privacy_extensions);
883 : :
884 : : /* Our enum shall be a superset of booleans, hence first try
885 : : * to parse as boolean, and then as enum */
886 : :
887 : 0 : k = parse_boolean(rvalue);
888 [ # # ]: 0 : if (k > 0)
889 : 0 : *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
890 [ # # ]: 0 : else if (k == 0)
891 : 0 : *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
892 : : else {
893 : : IPv6PrivacyExtensions s;
894 : :
895 : 0 : s = ipv6_privacy_extensions_from_string(rvalue);
896 [ # # ]: 0 : if (s < 0) {
897 : :
898 [ # # ]: 0 : if (streq(rvalue, "kernel"))
899 : 0 : s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
900 : : else {
901 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
902 : : "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
903 : 0 : return 0;
904 : : }
905 : : }
906 : :
907 : 0 : *ipv6_privacy_extensions = s;
908 : : }
909 : :
910 : 0 : return 0;
911 : : }
912 : :
913 : 0 : int config_parse_hostname(
914 : : const char *unit,
915 : : const char *filename,
916 : : unsigned line,
917 : : const char *section,
918 : : unsigned section_line,
919 : : const char *lvalue,
920 : : int ltype,
921 : : const char *rvalue,
922 : : void *data,
923 : : void *userdata) {
924 : :
925 : 0 : _cleanup_free_ char *hn = NULL;
926 : 0 : char **hostname = data;
927 : : int r;
928 : :
929 [ # # ]: 0 : assert(filename);
930 [ # # ]: 0 : assert(lvalue);
931 [ # # ]: 0 : assert(rvalue);
932 : :
933 : 0 : r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
934 [ # # ]: 0 : if (r < 0)
935 : 0 : return r;
936 : :
937 [ # # ]: 0 : if (!hostname_is_valid(hn, false)) {
938 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
939 : : "Hostname is not valid, ignoring assignment: %s", rvalue);
940 : 0 : return 0;
941 : : }
942 : :
943 : 0 : r = dns_name_is_valid(hn);
944 [ # # ]: 0 : if (r < 0) {
945 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
946 : : "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
947 : 0 : return 0;
948 : : }
949 [ # # ]: 0 : if (r == 0) {
950 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
951 : : "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
952 : 0 : return 0;
953 : : }
954 : :
955 : 0 : return free_and_replace(*hostname, hn);
956 : : }
957 : :
958 : 0 : int config_parse_timezone(
959 : : const char *unit,
960 : : const char *filename,
961 : : unsigned line,
962 : : const char *section,
963 : : unsigned section_line,
964 : : const char *lvalue,
965 : : int ltype,
966 : : const char *rvalue,
967 : : void *data,
968 : : void *userdata) {
969 : :
970 : 0 : _cleanup_free_ char *tz = NULL;
971 : 0 : char **datap = data;
972 : : int r;
973 : :
974 [ # # ]: 0 : assert(filename);
975 [ # # ]: 0 : assert(lvalue);
976 [ # # ]: 0 : assert(rvalue);
977 : :
978 : 0 : r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
979 [ # # ]: 0 : if (r < 0)
980 : 0 : return r;
981 : :
982 [ # # ]: 0 : if (!timezone_is_valid(tz, LOG_ERR)) {
983 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
984 : : "Timezone is not valid, ignoring assignment: %s", rvalue);
985 : 0 : return 0;
986 : : }
987 : :
988 : 0 : return free_and_replace(*datap, tz);
989 : : }
990 : :
991 : 0 : int config_parse_dns(
992 : : const char *unit,
993 : : const char *filename,
994 : : unsigned line,
995 : : const char *section,
996 : : unsigned section_line,
997 : : const char *lvalue,
998 : : int ltype,
999 : : const char *rvalue,
1000 : : void *data,
1001 : : void *userdata) {
1002 : :
1003 : 0 : Network *n = userdata;
1004 : : int r;
1005 : :
1006 [ # # ]: 0 : assert(filename);
1007 [ # # ]: 0 : assert(lvalue);
1008 [ # # ]: 0 : assert(rvalue);
1009 : :
1010 : 0 : for (;;) {
1011 [ # # # # ]: 0 : _cleanup_free_ char *w = NULL;
1012 : : union in_addr_union a;
1013 : : struct in_addr_data *m;
1014 : : int family;
1015 : :
1016 : 0 : r = extract_first_word(&rvalue, &w, NULL, 0);
1017 [ # # ]: 0 : if (r == -ENOMEM)
1018 : 0 : return log_oom();
1019 [ # # ]: 0 : if (r < 0) {
1020 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1021 : : "Invalid syntax, ignoring: %s", rvalue);
1022 : 0 : break;
1023 : : }
1024 [ # # ]: 0 : if (r == 0)
1025 : 0 : break;
1026 : :
1027 : 0 : r = in_addr_from_string_auto(w, &family, &a);
1028 [ # # ]: 0 : if (r < 0) {
1029 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1030 : : "Failed to parse dns server address, ignoring: %s", w);
1031 : 0 : continue;
1032 : : }
1033 : :
1034 : 0 : m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1035 [ # # ]: 0 : if (!m)
1036 : 0 : return log_oom();
1037 : :
1038 : 0 : m[n->n_dns++] = (struct in_addr_data) {
1039 : : .family = family,
1040 : : .address = a,
1041 : : };
1042 : :
1043 : 0 : n->dns = m;
1044 : : }
1045 : :
1046 : 0 : return 0;
1047 : : }
1048 : :
1049 : 0 : int config_parse_dnssec_negative_trust_anchors(
1050 : : const char *unit,
1051 : : const char *filename,
1052 : : unsigned line,
1053 : : const char *section,
1054 : : unsigned section_line,
1055 : : const char *lvalue,
1056 : : int ltype,
1057 : : const char *rvalue,
1058 : : void *data,
1059 : : void *userdata) {
1060 : :
1061 : 0 : const char *p = rvalue;
1062 : 0 : Network *n = data;
1063 : : int r;
1064 : :
1065 [ # # ]: 0 : assert(n);
1066 [ # # ]: 0 : assert(lvalue);
1067 [ # # ]: 0 : assert(rvalue);
1068 : :
1069 [ # # ]: 0 : if (isempty(rvalue)) {
1070 : 0 : n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1071 : 0 : return 0;
1072 : : }
1073 : :
1074 : 0 : for (;;) {
1075 [ # # # # ]: 0 : _cleanup_free_ char *w = NULL;
1076 : :
1077 : 0 : r = extract_first_word(&p, &w, NULL, 0);
1078 [ # # ]: 0 : if (r < 0) {
1079 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1080 : : "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1081 : 0 : break;
1082 : : }
1083 [ # # ]: 0 : if (r == 0)
1084 : 0 : break;
1085 : :
1086 : 0 : r = dns_name_is_valid(w);
1087 [ # # ]: 0 : if (r <= 0) {
1088 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1089 : : "%s is not a valid domain name, ignoring.", w);
1090 : 0 : continue;
1091 : : }
1092 : :
1093 : 0 : r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1094 [ # # ]: 0 : if (r < 0)
1095 : 0 : return log_oom();
1096 : :
1097 : 0 : r = set_put(n->dnssec_negative_trust_anchors, w);
1098 [ # # ]: 0 : if (r < 0)
1099 : 0 : return log_oom();
1100 [ # # ]: 0 : if (r > 0)
1101 : 0 : w = NULL;
1102 : : }
1103 : :
1104 : 0 : return 0;
1105 : : }
1106 : :
1107 : 0 : int config_parse_ntp(
1108 : : const char *unit,
1109 : : const char *filename,
1110 : : unsigned line,
1111 : : const char *section,
1112 : : unsigned section_line,
1113 : : const char *lvalue,
1114 : : int ltype,
1115 : : const char *rvalue,
1116 : : void *data,
1117 : : void *userdata) {
1118 : :
1119 : 0 : char ***l = data;
1120 : : int r;
1121 : :
1122 [ # # ]: 0 : assert(l);
1123 [ # # ]: 0 : assert(lvalue);
1124 [ # # ]: 0 : assert(rvalue);
1125 : :
1126 [ # # ]: 0 : if (isempty(rvalue)) {
1127 : 0 : *l = strv_free(*l);
1128 : 0 : return 0;
1129 : : }
1130 : :
1131 : 0 : for (;;) {
1132 [ # # # # ]: 0 : _cleanup_free_ char *w = NULL;
1133 : :
1134 : 0 : r = extract_first_word(&rvalue, &w, NULL, 0);
1135 [ # # ]: 0 : if (r == -ENOMEM)
1136 : 0 : return log_oom();
1137 [ # # ]: 0 : if (r < 0) {
1138 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1139 : : "Failed to extract NTP server name, ignoring: %s", rvalue);
1140 : 0 : break;
1141 : : }
1142 [ # # ]: 0 : if (r == 0)
1143 : 0 : break;
1144 : :
1145 : 0 : r = dns_name_is_valid_or_address(w);
1146 [ # # ]: 0 : if (r <= 0) {
1147 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1148 : : "%s is not a valid domain name or IP address, ignoring.", w);
1149 : 0 : continue;
1150 : : }
1151 : :
1152 [ # # ]: 0 : if (strv_length(*l) > MAX_NTP_SERVERS) {
1153 [ # # ]: 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
1154 : : "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1155 : : MAX_NTP_SERVERS, w);
1156 : 0 : break;
1157 : : }
1158 : :
1159 : 0 : r = strv_consume(l, TAKE_PTR(w));
1160 [ # # ]: 0 : if (r < 0)
1161 : 0 : return log_oom();
1162 : : }
1163 : :
1164 : 0 : return 0;
1165 : : }
1166 : :
1167 : 0 : int config_parse_required_for_online(
1168 : : const char *unit,
1169 : : const char *filename,
1170 : : unsigned line,
1171 : : const char *section,
1172 : : unsigned section_line,
1173 : : const char *lvalue,
1174 : : int ltype,
1175 : : const char *rvalue,
1176 : : void *data,
1177 : : void *userdata) {
1178 : :
1179 : 0 : Network *network = data;
1180 : : LinkOperationalState s;
1181 : 0 : bool required = true;
1182 : : int r;
1183 : :
1184 [ # # ]: 0 : if (isempty(rvalue)) {
1185 : 0 : network->required_for_online = true;
1186 : 0 : network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1187 : 0 : return 0;
1188 : : }
1189 : :
1190 : 0 : s = link_operstate_from_string(rvalue);
1191 [ # # ]: 0 : if (s < 0) {
1192 : 0 : r = parse_boolean(rvalue);
1193 [ # # ]: 0 : if (r < 0) {
1194 [ # # ]: 0 : log_syntax(unit, LOG_ERR, filename, line, r,
1195 : : "Failed to parse %s= setting, ignoring assignment: %s",
1196 : : lvalue, rvalue);
1197 : 0 : return 0;
1198 : : }
1199 : :
1200 : 0 : required = r;
1201 : 0 : s = LINK_OPERSTATE_DEGRADED;
1202 : : }
1203 : :
1204 : 0 : network->required_for_online = required;
1205 : 0 : network->required_operstate_for_online = s;
1206 : :
1207 : 0 : return 0;
1208 : : }
1209 : :
1210 [ # # # # : 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
# # # # #
# # # ]
1211 : : "Failed to parse KeepConfiguration= setting");
1212 : :
1213 : : static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1214 : : [KEEP_CONFIGURATION_NO] = "no",
1215 : : [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1216 : : [KEEP_CONFIGURATION_DHCP] = "dhcp",
1217 : : [KEEP_CONFIGURATION_STATIC] = "static",
1218 : : [KEEP_CONFIGURATION_YES] = "yes",
1219 : : };
1220 : :
1221 [ # # # # : 0 : DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);
# # ]
|