]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
network: warn about deprecated value in DHCP=
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <ctype.h>
4 #include <net/if.h>
5
6 #include "alloc-util.h"
7 #include "conf-files.h"
8 #include "conf-parser.h"
9 #include "dns-domain.h"
10 #include "fd-util.h"
11 #include "hostname-util.h"
12 #include "in-addr-util.h"
13 #include "missing_network.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 "stat-util.h"
20 #include "string-table.h"
21 #include "string-util.h"
22 #include "strv.h"
23 #include "util.h"
24
25 static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
26 siphash24_compress(c->filename, strlen(c->filename), state);
27 siphash24_compress(&c->line, sizeof(c->line), state);
28 }
29
30 static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
31 int r;
32
33 r = strcmp(x->filename, y->filename);
34 if (r != 0)
35 return r;
36
37 return CMP(x->line, y->line);
38 }
39
40 DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
41
42 int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
43 NetworkConfigSection *cs;
44
45 cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
46 if (!cs)
47 return -ENOMEM;
48
49 strcpy(cs->filename, filename);
50 cs->line = line;
51
52 *s = TAKE_PTR(cs);
53
54 return 0;
55 }
56
57 void network_config_section_free(NetworkConfigSection *cs) {
58 free(cs);
59 }
60
61 /* Set defaults following RFC7844 */
62 void network_apply_anonymize_if_set(Network *network) {
63 if (!network->dhcp_anonymize)
64 return;
65 /* RFC7844 3.7
66 SHOULD NOT send the Host Name option */
67 network->dhcp_send_hostname = false;
68 /* RFC7844 section 3.:
69 MAY contain the Client Identifier option
70 Section 3.5:
71 clients MUST use client identifiers based solely
72 on the link-layer address */
73 /* NOTE: Using MAC, as it does not reveal extra information,
74 * and some servers might not answer if this option is not sent */
75 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
76 /* RFC 7844 3.10:
77 SHOULD NOT use the Vendor Class Identifier option */
78 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
79 /* RFC7844 section 3.6.:
80 The client intending to protect its privacy SHOULD only request a
81 minimal number of options in the PRL and SHOULD also randomly shuffle
82 the ordering of option codes in the PRL. If this random ordering
83 cannot be implemented, the client MAY order the option codes in the
84 PRL by option code number (lowest to highest).
85 */
86 /* NOTE: dhcp_use_mtu is false by default,
87 * though it was not initiallized to any value in network_load_one.
88 * Maybe there should be another var called *send*?
89 * (to use the MTU sent by the server but to do not send
90 * the option in the PRL). */
91 network->dhcp_use_mtu = false;
92 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
93 * but this is needed to use them. */
94 network->dhcp_use_routes = true;
95 /* RFC7844 section 3.6.
96 * same comments as previous option */
97 network->dhcp_use_timezone = false;
98 }
99
100 int network_load_one(Manager *manager, const char *filename) {
101 _cleanup_free_ char *fname = NULL, *name = NULL;
102 _cleanup_(network_freep) Network *network = NULL;
103 _cleanup_fclose_ FILE *file = NULL;
104 const char *dropin_dirname;
105 Address *address;
106 Route *route;
107 char *d;
108 int r;
109
110 assert(manager);
111 assert(filename);
112
113 file = fopen(filename, "re");
114 if (!file) {
115 if (errno == ENOENT)
116 return 0;
117
118 return -errno;
119 }
120
121 if (null_or_empty_fd(fileno(file))) {
122 log_debug("Skipping empty file: %s", filename);
123 return 0;
124 }
125
126 fname = strdup(filename);
127 if (!fname)
128 return log_oom();
129
130 name = strdup(basename(filename));
131 if (!name)
132 return log_oom();
133
134 d = strrchr(name, '.');
135 if (!d)
136 return -EINVAL;
137
138 *d = '\0';
139
140 dropin_dirname = strjoina(name, ".network.d");
141
142 network = new(Network, 1);
143 if (!network)
144 return log_oom();
145
146 *network = (Network) {
147 .manager = manager,
148 .filename = TAKE_PTR(fname),
149 .name = TAKE_PTR(name),
150
151 .required_for_online = true,
152 .dhcp = ADDRESS_FAMILY_NO,
153 .dhcp_use_ntp = true,
154 .dhcp_use_dns = true,
155 .dhcp_use_hostname = true,
156 .dhcp_use_routes = true,
157 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
158 .dhcp_send_hostname = true,
159 /* To enable/disable RFC7844 Anonymity Profiles */
160 .dhcp_anonymize = false,
161 .dhcp_route_metric = DHCP_ROUTE_METRIC,
162 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
163 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
164 .dhcp_route_table = RT_TABLE_MAIN,
165 .dhcp_route_table_set = false,
166 /* NOTE: from man: UseMTU=... Defaults to false*/
167 .dhcp_use_mtu = false,
168 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
169 .dhcp_use_timezone = false,
170 .rapid_commit = true,
171
172 .dhcp_server_emit_dns = true,
173 .dhcp_server_emit_ntp = true,
174 .dhcp_server_emit_router = true,
175 .dhcp_server_emit_timezone = true,
176
177 .router_emit_dns = true,
178 .router_emit_domains = true,
179
180 .use_bpdu = -1,
181 .hairpin = -1,
182 .fast_leave = -1,
183 .allow_port_to_be_root = -1,
184 .unicast_flood = -1,
185 .multicast_to_unicast = -1,
186 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
187
188 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
189
190 .dns_default_route = -1,
191 .llmnr = RESOLVE_SUPPORT_YES,
192 .mdns = RESOLVE_SUPPORT_NO,
193 .dnssec_mode = _DNSSEC_MODE_INVALID,
194 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
195
196 .link_local = ADDRESS_FAMILY_IPV6,
197
198 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
199 .ipv6_accept_ra = -1,
200 .ipv6_dad_transmits = -1,
201 .ipv6_hop_limit = -1,
202 .ipv6_proxy_ndp = -1,
203 .duid.type = _DUID_TYPE_INVALID,
204 .proxy_arp = -1,
205 .arp = -1,
206 .multicast = -1,
207 .allmulticast = -1,
208 .ipv6_accept_ra_use_dns = true,
209 .ipv6_accept_ra_use_autonomous_prefix = true,
210 .ipv6_accept_ra_use_onlink_prefix = true,
211 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
212 .ipv6_accept_ra_route_table_set = false,
213 };
214
215 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
216 "Match\0"
217 "Link\0"
218 "Network\0"
219 "Address\0"
220 "Neighbor\0"
221 "IPv6AddressLabel\0"
222 "RoutingPolicyRule\0"
223 "Route\0"
224 "DHCP\0"
225 "DHCPv4\0" /* compat */
226 "DHCPServer\0"
227 "IPv6AcceptRA\0"
228 "IPv6NDPProxyAddress\0"
229 "Bridge\0"
230 "BridgeFDB\0"
231 "BridgeVLAN\0"
232 "IPv6PrefixDelegation\0"
233 "IPv6Prefix\0"
234 "CAN\0",
235 config_item_perf_lookup, network_network_gperf_lookup,
236 CONFIG_PARSE_WARN, network);
237 if (r < 0) {
238 /* Unset manager here. Otherwise, LIST_REMOVE() in network_free() fails. */
239 network->manager = NULL;
240 return r;
241 }
242
243 network_apply_anonymize_if_set(network);
244
245 /* IPMasquerade=yes implies IPForward=yes */
246 if (network->ip_masquerade)
247 network->ip_forward |= ADDRESS_FAMILY_IPV4;
248
249 if (network->mtu > 0 && network->dhcp_use_mtu) {
250 log_warning("MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set in %s. "
251 "Disabling UseMTU=.", filename);
252 network->dhcp_use_mtu = false;
253 }
254
255 LIST_PREPEND(networks, manager->networks, network);
256
257 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
258 if (r < 0)
259 return r;
260
261 r = hashmap_put(manager->networks_by_name, network->name, network);
262 if (r < 0)
263 return r;
264
265 LIST_FOREACH(routes, route, network->static_routes)
266 if (!route->family) {
267 log_warning("Route section without Gateway field configured in %s. "
268 "Ignoring", filename);
269 return 0;
270 }
271
272 LIST_FOREACH(addresses, address, network->static_addresses)
273 if (!address->family) {
274 log_warning("Address section without Address field configured in %s. "
275 "Ignoring", filename);
276 return 0;
277 }
278
279 network = NULL;
280
281 return 0;
282 }
283
284 int network_load(Manager *manager) {
285 Network *network;
286 _cleanup_strv_free_ char **files = NULL;
287 char **f;
288 int r;
289
290 assert(manager);
291
292 while ((network = manager->networks))
293 network_free(network);
294
295 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
296 if (r < 0)
297 return log_error_errno(r, "Failed to enumerate network files: %m");
298
299 STRV_FOREACH_BACKWARDS(f, files) {
300 r = network_load_one(manager, *f);
301 if (r < 0)
302 return r;
303 }
304
305 return 0;
306 }
307
308 void network_free(Network *network) {
309 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
310 RoutingPolicyRule *rule;
311 FdbEntry *fdb_entry;
312 Neighbor *neighbor;
313 AddressLabel *label;
314 Prefix *prefix;
315 Address *address;
316 Route *route;
317
318 if (!network)
319 return;
320
321 free(network->filename);
322
323 set_free_free(network->match_mac);
324 strv_free(network->match_path);
325 strv_free(network->match_driver);
326 strv_free(network->match_type);
327 strv_free(network->match_name);
328
329 free(network->description);
330 free(network->dhcp_vendor_class_identifier);
331 strv_free(network->dhcp_user_class);
332 free(network->dhcp_hostname);
333
334 free(network->mac);
335
336 strv_free(network->ntp);
337 free(network->dns);
338 strv_free(network->search_domains);
339 strv_free(network->route_domains);
340 strv_free(network->bind_carrier);
341
342 strv_free(network->router_search_domains);
343 free(network->router_dns);
344
345 netdev_unref(network->bridge);
346 netdev_unref(network->bond);
347 netdev_unref(network->vrf);
348
349 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
350
351 while ((route = network->static_routes))
352 route_free(route);
353
354 while ((address = network->static_addresses))
355 address_free(address);
356
357 while ((fdb_entry = network->static_fdb_entries))
358 fdb_entry_free(fdb_entry);
359
360 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
361 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
362
363 while ((neighbor = network->neighbors))
364 neighbor_free(neighbor);
365
366 while ((label = network->address_labels))
367 address_label_free(label);
368
369 while ((prefix = network->static_prefixes))
370 prefix_free(prefix);
371
372 while ((rule = network->rules))
373 routing_policy_rule_free(rule);
374
375 hashmap_free(network->addresses_by_section);
376 hashmap_free(network->routes_by_section);
377 hashmap_free(network->fdb_entries_by_section);
378 hashmap_free(network->neighbors_by_section);
379 hashmap_free(network->address_labels_by_section);
380 hashmap_free(network->prefixes_by_section);
381 hashmap_free(network->rules_by_section);
382
383 if (network->manager) {
384 if (network->manager->networks)
385 LIST_REMOVE(networks, network->manager->networks, network);
386
387 if (network->manager->networks_by_name && network->name)
388 hashmap_remove(network->manager->networks_by_name, network->name);
389
390 if (network->manager->duids_requesting_uuid)
391 set_remove(network->manager->duids_requesting_uuid, &network->duid);
392 }
393
394 free(network->name);
395
396 condition_free_list(network->match_host);
397 condition_free_list(network->match_virt);
398 condition_free_list(network->match_kernel_cmdline);
399 condition_free_list(network->match_kernel_version);
400 condition_free_list(network->match_arch);
401
402 free(network->dhcp_server_timezone);
403 free(network->dhcp_server_dns);
404 free(network->dhcp_server_ntp);
405
406 set_free_free(network->dnssec_negative_trust_anchors);
407
408 free(network);
409 }
410
411 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
412 Network *network;
413
414 assert(manager);
415 assert(name);
416 assert(ret);
417
418 network = hashmap_get(manager->networks_by_name, name);
419 if (!network)
420 return -ENOENT;
421
422 *ret = network;
423
424 return 0;
425 }
426
427 int network_get(Manager *manager, sd_device *device,
428 const char *ifname, const struct ether_addr *address,
429 Network **ret) {
430 const char *path = NULL, *driver = NULL, *devtype = NULL;
431 Network *network;
432
433 assert(manager);
434 assert(ret);
435
436 if (device) {
437 (void) sd_device_get_property_value(device, "ID_PATH", &path);
438
439 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
440
441 (void) sd_device_get_devtype(device, &devtype);
442 }
443
444 LIST_FOREACH(networks, network, manager->networks) {
445 if (net_match_config(network->match_mac, network->match_path,
446 network->match_driver, network->match_type,
447 network->match_name, network->match_host,
448 network->match_virt, network->match_kernel_cmdline,
449 network->match_kernel_version, network->match_arch,
450 address, path, driver, devtype, ifname)) {
451 if (network->match_name && device) {
452 const char *attr;
453 uint8_t name_assign_type = NET_NAME_UNKNOWN;
454
455 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
456 (void) safe_atou8(attr, &name_assign_type);
457
458 if (name_assign_type == NET_NAME_ENUM)
459 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
460 ifname, network->filename);
461 else
462 log_debug("%s: found matching network '%s'", ifname, network->filename);
463 } else
464 log_debug("%s: found matching network '%s'", ifname, network->filename);
465
466 *ret = network;
467 return 0;
468 }
469 }
470
471 *ret = NULL;
472
473 return -ENOENT;
474 }
475
476 int network_apply(Network *network, Link *link) {
477 int r;
478
479 assert(network);
480 assert(link);
481
482 link->network = network;
483
484 if (network->ipv4ll_route) {
485 Route *route;
486
487 r = route_new_static(network, NULL, 0, &route);
488 if (r < 0)
489 return r;
490
491 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
492 if (r == 0)
493 return -EINVAL;
494 if (r < 0)
495 return -errno;
496
497 route->family = AF_INET;
498 route->dst_prefixlen = 16;
499 route->scope = RT_SCOPE_LINK;
500 route->priority = IPV4LL_ROUTE_METRIC;
501 route->protocol = RTPROT_STATIC;
502 }
503
504 if (network->n_dns > 0 ||
505 !strv_isempty(network->ntp) ||
506 !strv_isempty(network->search_domains) ||
507 !strv_isempty(network->route_domains))
508 link_dirty(link);
509
510 return 0;
511 }
512
513 bool network_has_static_ipv6_addresses(Network *network) {
514 Address *address;
515
516 assert(network);
517
518 LIST_FOREACH(addresses, address, network->static_addresses) {
519 if (address->family == AF_INET6)
520 return true;
521 }
522
523 return false;
524 }
525
526 int config_parse_netdev(const char *unit,
527 const char *filename,
528 unsigned line,
529 const char *section,
530 unsigned section_line,
531 const char *lvalue,
532 int ltype,
533 const char *rvalue,
534 void *data,
535 void *userdata) {
536 Network *network = userdata;
537 _cleanup_free_ char *kind_string = NULL;
538 char *p;
539 NetDev *netdev;
540 NetDevKind kind;
541 int r;
542
543 assert(filename);
544 assert(lvalue);
545 assert(rvalue);
546 assert(data);
547
548 kind_string = strdup(lvalue);
549 if (!kind_string)
550 return log_oom();
551
552 /* the keys are CamelCase versions of the kind */
553 for (p = kind_string; *p; p++)
554 *p = tolower(*p);
555
556 kind = netdev_kind_from_string(kind_string);
557 if (kind == _NETDEV_KIND_INVALID) {
558 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
559 return 0;
560 }
561
562 r = netdev_get(network->manager, rvalue, &netdev);
563 if (r < 0) {
564 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
565 return 0;
566 }
567
568 if (netdev->kind != kind) {
569 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
570 return 0;
571 }
572
573 switch (kind) {
574 case NETDEV_KIND_BRIDGE:
575 network->bridge = netdev_unref(network->bridge);
576 network->bridge = netdev;
577
578 break;
579 case NETDEV_KIND_BOND:
580 network->bond = netdev_unref(network->bond);
581 network->bond = netdev;
582
583 break;
584 case NETDEV_KIND_VRF:
585 network->vrf = netdev_unref(network->vrf);
586 network->vrf = netdev;
587
588 break;
589 case NETDEV_KIND_VLAN:
590 case NETDEV_KIND_MACVLAN:
591 case NETDEV_KIND_MACVTAP:
592 case NETDEV_KIND_IPVLAN:
593 case NETDEV_KIND_VXLAN:
594 case NETDEV_KIND_VCAN:
595 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
596 if (r < 0)
597 return log_oom();
598
599 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
600 if (r < 0) {
601 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
602 return 0;
603 }
604
605 break;
606 default:
607 assert_not_reached("Cannot parse NetDev");
608 }
609
610 netdev_ref(netdev);
611
612 return 0;
613 }
614
615 int config_parse_domains(
616 const char *unit,
617 const char *filename,
618 unsigned line,
619 const char *section,
620 unsigned section_line,
621 const char *lvalue,
622 int ltype,
623 const char *rvalue,
624 void *data,
625 void *userdata) {
626
627 const char *p;
628 Network *n = data;
629 int r;
630
631 assert(n);
632 assert(lvalue);
633 assert(rvalue);
634
635 if (isempty(rvalue)) {
636 n->search_domains = strv_free(n->search_domains);
637 n->route_domains = strv_free(n->route_domains);
638 return 0;
639 }
640
641 p = rvalue;
642 for (;;) {
643 _cleanup_free_ char *w = NULL, *normalized = NULL;
644 const char *domain;
645 bool is_route;
646
647 r = extract_first_word(&p, &w, NULL, 0);
648 if (r < 0) {
649 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
650 break;
651 }
652 if (r == 0)
653 break;
654
655 is_route = w[0] == '~';
656 domain = is_route ? w + 1 : w;
657
658 if (dns_name_is_root(domain) || streq(domain, "*")) {
659 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
660 * routing domain, unconditionally. */
661 is_route = true;
662 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
663 } else {
664 r = dns_name_normalize(domain, 0, &normalized);
665 if (r < 0) {
666 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
667 continue;
668 }
669
670 domain = normalized;
671
672 if (is_localhost(domain)) {
673 log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
674 continue;
675 }
676 }
677
678 if (is_route)
679 r = strv_extend(&n->route_domains, domain);
680 else
681 r = strv_extend(&n->search_domains, domain);
682 if (r < 0)
683 return log_oom();
684 }
685
686 strv_uniq(n->route_domains);
687 strv_uniq(n->search_domains);
688
689 return 0;
690 }
691
692 int config_parse_tunnel(const char *unit,
693 const char *filename,
694 unsigned line,
695 const char *section,
696 unsigned section_line,
697 const char *lvalue,
698 int ltype,
699 const char *rvalue,
700 void *data,
701 void *userdata) {
702 Network *network = userdata;
703 NetDev *netdev;
704 int r;
705
706 assert(filename);
707 assert(lvalue);
708 assert(rvalue);
709 assert(data);
710
711 r = netdev_get(network->manager, rvalue, &netdev);
712 if (r < 0) {
713 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
714 return 0;
715 }
716
717 if (!IN_SET(netdev->kind,
718 NETDEV_KIND_IPIP,
719 NETDEV_KIND_SIT,
720 NETDEV_KIND_GRE,
721 NETDEV_KIND_GRETAP,
722 NETDEV_KIND_IP6GRE,
723 NETDEV_KIND_IP6GRETAP,
724 NETDEV_KIND_VTI,
725 NETDEV_KIND_VTI6,
726 NETDEV_KIND_IP6TNL)) {
727 log_syntax(unit, LOG_ERR, filename, line, 0,
728 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
729 return 0;
730 }
731
732 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
733 if (r < 0)
734 return log_oom();
735
736 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
737 if (r < 0) {
738 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
739 return 0;
740 }
741
742 netdev_ref(netdev);
743
744 return 0;
745 }
746
747 int config_parse_ipv4ll(
748 const char* unit,
749 const char *filename,
750 unsigned line,
751 const char *section,
752 unsigned section_line,
753 const char *lvalue,
754 int ltype,
755 const char *rvalue,
756 void *data,
757 void *userdata) {
758
759 AddressFamilyBoolean *link_local = data;
760
761 assert(filename);
762 assert(lvalue);
763 assert(rvalue);
764 assert(data);
765
766 /* Note that this is mostly like
767 * config_parse_address_family_boolean(), except that it
768 * applies only to IPv4 */
769
770 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
771
772 return 0;
773 }
774
775 int config_parse_dhcp(
776 const char* unit,
777 const char *filename,
778 unsigned line,
779 const char *section,
780 unsigned section_line,
781 const char *lvalue,
782 int ltype,
783 const char *rvalue,
784 void *data,
785 void *userdata) {
786
787 AddressFamilyBoolean *dhcp = data, s;
788
789 assert(filename);
790 assert(lvalue);
791 assert(rvalue);
792 assert(data);
793
794 /* Note that this is mostly like
795 * config_parse_address_family_boolean(), except that it
796 * understands some old names for the enum values */
797
798 s = address_family_boolean_from_string(rvalue);
799 if (s < 0) {
800
801 /* Previously, we had a slightly different enum here,
802 * support its values for compatbility. */
803
804 if (streq(rvalue, "none"))
805 s = ADDRESS_FAMILY_NO;
806 else if (streq(rvalue, "v4"))
807 s = ADDRESS_FAMILY_IPV4;
808 else if (streq(rvalue, "v6"))
809 s = ADDRESS_FAMILY_IPV6;
810 else if (streq(rvalue, "both"))
811 s = ADDRESS_FAMILY_YES;
812 else {
813 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
814 return 0;
815 }
816
817 log_syntax(unit, LOG_WARNING, filename, line, 0,
818 "DHCP=%s is deprecated, please use DHCP=%s instead.",
819 rvalue, address_family_boolean_to_string(s));
820 }
821
822 *dhcp = s;
823 return 0;
824 }
825
826 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
827 [DHCP_CLIENT_ID_MAC] = "mac",
828 [DHCP_CLIENT_ID_DUID] = "duid",
829 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
830 };
831
832 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
833 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
834
835 int config_parse_ipv6token(
836 const char* unit,
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
846
847 union in_addr_union buffer;
848 struct in6_addr *token = data;
849 int r;
850
851 assert(filename);
852 assert(lvalue);
853 assert(rvalue);
854 assert(token);
855
856 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
857 if (r < 0) {
858 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
859 return 0;
860 }
861
862 if (in_addr_is_null(AF_INET6, &buffer)) {
863 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
864 return 0;
865 }
866
867 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
868 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
869 return 0;
870 }
871
872 *token = buffer.in6;
873
874 return 0;
875 }
876
877 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
878 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
879 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
880 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
881 };
882
883 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
884
885 int config_parse_ipv6_privacy_extensions(
886 const char* unit,
887 const char *filename,
888 unsigned line,
889 const char *section,
890 unsigned section_line,
891 const char *lvalue,
892 int ltype,
893 const char *rvalue,
894 void *data,
895 void *userdata) {
896
897 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
898 int k;
899
900 assert(filename);
901 assert(lvalue);
902 assert(rvalue);
903 assert(ipv6_privacy_extensions);
904
905 /* Our enum shall be a superset of booleans, hence first try
906 * to parse as boolean, and then as enum */
907
908 k = parse_boolean(rvalue);
909 if (k > 0)
910 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
911 else if (k == 0)
912 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
913 else {
914 IPv6PrivacyExtensions s;
915
916 s = ipv6_privacy_extensions_from_string(rvalue);
917 if (s < 0) {
918
919 if (streq(rvalue, "kernel"))
920 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
921 else {
922 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
923 return 0;
924 }
925 }
926
927 *ipv6_privacy_extensions = s;
928 }
929
930 return 0;
931 }
932
933 int config_parse_hostname(
934 const char *unit,
935 const char *filename,
936 unsigned line,
937 const char *section,
938 unsigned section_line,
939 const char *lvalue,
940 int ltype,
941 const char *rvalue,
942 void *data,
943 void *userdata) {
944
945 _cleanup_free_ char *hn = NULL;
946 char **hostname = data;
947 int r;
948
949 assert(filename);
950 assert(lvalue);
951 assert(rvalue);
952
953 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
954 if (r < 0)
955 return r;
956
957 if (!hostname_is_valid(hn, false)) {
958 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
959 return 0;
960 }
961
962 r = dns_name_is_valid(hn);
963 if (r < 0) {
964 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
965 return 0;
966 }
967 if (r == 0) {
968 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
969 return 0;
970 }
971
972 return free_and_replace(*hostname, hn);
973 }
974
975 int config_parse_timezone(
976 const char *unit,
977 const char *filename,
978 unsigned line,
979 const char *section,
980 unsigned section_line,
981 const char *lvalue,
982 int ltype,
983 const char *rvalue,
984 void *data,
985 void *userdata) {
986
987 _cleanup_free_ char *tz = NULL;
988 char **datap = data;
989 int r;
990
991 assert(filename);
992 assert(lvalue);
993 assert(rvalue);
994
995 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
996 if (r < 0)
997 return r;
998
999 if (!timezone_is_valid(tz, LOG_ERR)) {
1000 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
1001 return 0;
1002 }
1003
1004 return free_and_replace(*datap, tz);
1005 }
1006
1007 int config_parse_dhcp_server_dns(
1008 const char *unit,
1009 const char *filename,
1010 unsigned line,
1011 const char *section,
1012 unsigned section_line,
1013 const char *lvalue,
1014 int ltype,
1015 const char *rvalue,
1016 void *data,
1017 void *userdata) {
1018
1019 Network *n = data;
1020 const char *p = rvalue;
1021 int r;
1022
1023 assert(filename);
1024 assert(lvalue);
1025 assert(rvalue);
1026
1027 for (;;) {
1028 _cleanup_free_ char *w = NULL;
1029 struct in_addr a, *m;
1030
1031 r = extract_first_word(&p, &w, NULL, 0);
1032 if (r == -ENOMEM)
1033 return log_oom();
1034 if (r < 0) {
1035 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1036 return 0;
1037 }
1038 if (r == 0)
1039 break;
1040
1041 if (inet_pton(AF_INET, w, &a) <= 0) {
1042 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1043 continue;
1044 }
1045
1046 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1047 if (!m)
1048 return log_oom();
1049
1050 m[n->n_dhcp_server_dns++] = a;
1051 n->dhcp_server_dns = m;
1052 }
1053
1054 return 0;
1055 }
1056
1057 int config_parse_radv_dns(
1058 const char *unit,
1059 const char *filename,
1060 unsigned line,
1061 const char *section,
1062 unsigned section_line,
1063 const char *lvalue,
1064 int ltype,
1065 const char *rvalue,
1066 void *data,
1067 void *userdata) {
1068
1069 Network *n = data;
1070 const char *p = rvalue;
1071 int r;
1072
1073 assert(filename);
1074 assert(lvalue);
1075 assert(rvalue);
1076
1077 for (;;) {
1078 _cleanup_free_ char *w = NULL;
1079 union in_addr_union a;
1080
1081 r = extract_first_word(&p, &w, NULL, 0);
1082 if (r == -ENOMEM)
1083 return log_oom();
1084 if (r < 0) {
1085 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1086 return 0;
1087 }
1088 if (r == 0)
1089 break;
1090
1091 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1092 struct in6_addr *m;
1093
1094 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1095 if (!m)
1096 return log_oom();
1097
1098 m[n->n_router_dns++] = a.in6;
1099 n->router_dns = m;
1100
1101 } else
1102 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1103
1104 }
1105
1106 return 0;
1107 }
1108
1109 int config_parse_radv_search_domains(
1110 const char *unit,
1111 const char *filename,
1112 unsigned line,
1113 const char *section,
1114 unsigned section_line,
1115 const char *lvalue,
1116 int ltype,
1117 const char *rvalue,
1118 void *data,
1119 void *userdata) {
1120
1121 Network *n = data;
1122 const char *p = rvalue;
1123 int r;
1124
1125 assert(filename);
1126 assert(lvalue);
1127 assert(rvalue);
1128
1129 for (;;) {
1130 _cleanup_free_ char *w = NULL, *idna = NULL;
1131
1132 r = extract_first_word(&p, &w, NULL, 0);
1133 if (r == -ENOMEM)
1134 return log_oom();
1135 if (r < 0) {
1136 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1137 return 0;
1138 }
1139 if (r == 0)
1140 break;
1141
1142 r = dns_name_apply_idna(w, &idna);
1143 if (r < 0) {
1144 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1145 continue;
1146 }
1147 if (r > 0) {
1148 r = strv_push(&n->router_search_domains, idna);
1149 if (r >= 0)
1150 idna = NULL;
1151 } else {
1152 r = strv_push(&n->router_search_domains, w);
1153 if (r >= 0)
1154 w = NULL;
1155 }
1156 }
1157
1158 return 0;
1159 }
1160
1161 int config_parse_dhcp_server_ntp(
1162 const char *unit,
1163 const char *filename,
1164 unsigned line,
1165 const char *section,
1166 unsigned section_line,
1167 const char *lvalue,
1168 int ltype,
1169 const char *rvalue,
1170 void *data,
1171 void *userdata) {
1172
1173 Network *n = data;
1174 const char *p = rvalue;
1175 int r;
1176
1177 assert(filename);
1178 assert(lvalue);
1179 assert(rvalue);
1180
1181 for (;;) {
1182 _cleanup_free_ char *w = NULL;
1183 struct in_addr a, *m;
1184
1185 r = extract_first_word(&p, &w, NULL, 0);
1186 if (r == -ENOMEM)
1187 return log_oom();
1188 if (r < 0) {
1189 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1190 return 0;
1191 }
1192 if (r == 0)
1193 return 0;
1194
1195 if (inet_pton(AF_INET, w, &a) <= 0) {
1196 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1197 continue;
1198 }
1199
1200 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1201 if (!m)
1202 return log_oom();
1203
1204 m[n->n_dhcp_server_ntp++] = a;
1205 n->dhcp_server_ntp = m;
1206 }
1207 }
1208
1209 int config_parse_dns(
1210 const char *unit,
1211 const char *filename,
1212 unsigned line,
1213 const char *section,
1214 unsigned section_line,
1215 const char *lvalue,
1216 int ltype,
1217 const char *rvalue,
1218 void *data,
1219 void *userdata) {
1220
1221 Network *n = userdata;
1222 int r;
1223
1224 assert(filename);
1225 assert(lvalue);
1226 assert(rvalue);
1227
1228 for (;;) {
1229 _cleanup_free_ char *w = NULL;
1230 union in_addr_union a;
1231 struct in_addr_data *m;
1232 int family;
1233
1234 r = extract_first_word(&rvalue, &w, NULL, 0);
1235 if (r == -ENOMEM)
1236 return log_oom();
1237 if (r < 0) {
1238 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
1239 break;
1240 }
1241 if (r == 0)
1242 break;
1243
1244 r = in_addr_from_string_auto(w, &family, &a);
1245 if (r < 0) {
1246 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
1247 continue;
1248 }
1249
1250 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1251 if (!m)
1252 return log_oom();
1253
1254 m[n->n_dns++] = (struct in_addr_data) {
1255 .family = family,
1256 .address = a,
1257 };
1258
1259 n->dns = m;
1260 }
1261
1262 return 0;
1263 }
1264
1265 int config_parse_dnssec_negative_trust_anchors(
1266 const char *unit,
1267 const char *filename,
1268 unsigned line,
1269 const char *section,
1270 unsigned section_line,
1271 const char *lvalue,
1272 int ltype,
1273 const char *rvalue,
1274 void *data,
1275 void *userdata) {
1276
1277 const char *p = rvalue;
1278 Network *n = data;
1279 int r;
1280
1281 assert(n);
1282 assert(lvalue);
1283 assert(rvalue);
1284
1285 if (isempty(rvalue)) {
1286 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1287 return 0;
1288 }
1289
1290 for (;;) {
1291 _cleanup_free_ char *w = NULL;
1292
1293 r = extract_first_word(&p, &w, NULL, 0);
1294 if (r < 0) {
1295 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1296 break;
1297 }
1298 if (r == 0)
1299 break;
1300
1301 r = dns_name_is_valid(w);
1302 if (r <= 0) {
1303 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1304 continue;
1305 }
1306
1307 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1308 if (r < 0)
1309 return log_oom();
1310
1311 r = set_put(n->dnssec_negative_trust_anchors, w);
1312 if (r < 0)
1313 return log_oom();
1314 if (r > 0)
1315 w = NULL;
1316 }
1317
1318 return 0;
1319 }
1320
1321 int config_parse_ntp(
1322 const char *unit,
1323 const char *filename,
1324 unsigned line,
1325 const char *section,
1326 unsigned section_line,
1327 const char *lvalue,
1328 int ltype,
1329 const char *rvalue,
1330 void *data,
1331 void *userdata) {
1332
1333 char ***l = data;
1334 int r;
1335
1336 assert(l);
1337 assert(lvalue);
1338 assert(rvalue);
1339
1340 if (isempty(rvalue)) {
1341 *l = strv_free(*l);
1342 return 0;
1343 }
1344
1345 for (;;) {
1346 _cleanup_free_ char *w = NULL;
1347
1348 r = extract_first_word(&rvalue, &w, NULL, 0);
1349 if (r == -ENOMEM)
1350 return log_oom();
1351 if (r < 0) {
1352 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
1353 break;
1354 }
1355 if (r == 0)
1356 break;
1357
1358 r = dns_name_is_valid_or_address(w);
1359 if (r <= 0) {
1360 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
1361 continue;
1362 }
1363
1364 r = strv_push(l, w);
1365 if (r < 0)
1366 return log_oom();
1367
1368 w = NULL;
1369 }
1370
1371 return 0;
1372 }
1373
1374 int config_parse_dhcp_user_class(
1375 const char *unit,
1376 const char *filename,
1377 unsigned line,
1378 const char *section,
1379 unsigned section_line,
1380 const char *lvalue,
1381 int ltype,
1382 const char *rvalue,
1383 void *data,
1384 void *userdata) {
1385
1386 char ***l = data;
1387 int r;
1388
1389 assert(l);
1390 assert(lvalue);
1391 assert(rvalue);
1392
1393 if (isempty(rvalue)) {
1394 *l = strv_free(*l);
1395 return 0;
1396 }
1397
1398 for (;;) {
1399 _cleanup_free_ char *w = NULL;
1400
1401 r = extract_first_word(&rvalue, &w, NULL, 0);
1402 if (r == -ENOMEM)
1403 return log_oom();
1404 if (r < 0) {
1405 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
1406 break;
1407 }
1408 if (r == 0)
1409 break;
1410
1411 if (strlen(w) > 255) {
1412 log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
1413 continue;
1414 }
1415
1416 r = strv_push(l, w);
1417 if (r < 0)
1418 return log_oom();
1419
1420 w = NULL;
1421 }
1422
1423 return 0;
1424 }
1425
1426 int config_parse_section_route_table(
1427 const char *unit,
1428 const char *filename,
1429 unsigned line,
1430 const char *section,
1431 unsigned section_line,
1432 const char *lvalue,
1433 int ltype,
1434 const char *rvalue,
1435 void *data,
1436 void *userdata) {
1437
1438 Network *network = data;
1439 uint32_t rt;
1440 int r;
1441
1442 assert(filename);
1443 assert(lvalue);
1444 assert(rvalue);
1445 assert(data);
1446
1447 r = safe_atou32(rvalue, &rt);
1448 if (r < 0) {
1449 log_syntax(unit, LOG_ERR, filename, line, r,
1450 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
1451 return 0;
1452 }
1453
1454 if (streq_ptr(section, "DHCP")) {
1455 network->dhcp_route_table = rt;
1456 network->dhcp_route_table_set = true;
1457 } else { /* section is IPv6AcceptRA */
1458 network->ipv6_accept_ra_route_table = rt;
1459 network->ipv6_accept_ra_route_table_set = true;
1460 }
1461
1462 return 0;
1463 }
1464
1465 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1466
1467 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1468 [DHCP_USE_DOMAINS_NO] = "no",
1469 [DHCP_USE_DOMAINS_ROUTE] = "route",
1470 [DHCP_USE_DOMAINS_YES] = "yes",
1471 };
1472
1473 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1474
1475 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1476
1477 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1478 [LLDP_MODE_NO] = "no",
1479 [LLDP_MODE_YES] = "yes",
1480 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1481 };
1482
1483 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
1484
1485 int config_parse_iaid(const char *unit,
1486 const char *filename,
1487 unsigned line,
1488 const char *section,
1489 unsigned section_line,
1490 const char *lvalue,
1491 int ltype,
1492 const char *rvalue,
1493 void *data,
1494 void *userdata) {
1495 Network *network = data;
1496 uint32_t iaid;
1497 int r;
1498
1499 assert(filename);
1500 assert(lvalue);
1501 assert(rvalue);
1502 assert(network);
1503
1504 r = safe_atou32(rvalue, &iaid);
1505 if (r < 0) {
1506 log_syntax(unit, LOG_ERR, filename, line, r,
1507 "Unable to read IAID, ignoring assignment: %s", rvalue);
1508 return 0;
1509 }
1510
1511 network->iaid = iaid;
1512 network->iaid_set = true;
1513
1514 return 0;
1515 }