]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-network.c
Merge pull request #3394 from poettering/triple-tstamp
[thirdparty/systemd.git] / src / network / networkd-network.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <ctype.h>
21 #include <net/if.h>
22
23 #include "alloc-util.h"
24 #include "conf-files.h"
25 #include "conf-parser.h"
26 #include "dns-domain.h"
27 #include "fd-util.h"
28 #include "hostname-util.h"
29 #include "network-internal.h"
30 #include "networkd-network.h"
31 #include "networkd.h"
32 #include "parse-util.h"
33 #include "set.h"
34 #include "stat-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
37 #include "util.h"
38
39 static int network_load_one(Manager *manager, const char *filename) {
40 _cleanup_network_free_ Network *network = NULL;
41 _cleanup_fclose_ FILE *file = NULL;
42 char *d;
43 Route *route;
44 Address *address;
45 int r;
46
47 assert(manager);
48 assert(filename);
49
50 file = fopen(filename, "re");
51 if (!file) {
52 if (errno == ENOENT)
53 return 0;
54
55 return -errno;
56 }
57
58 if (null_or_empty_fd(fileno(file))) {
59 log_debug("Skipping empty file: %s", filename);
60 return 0;
61 }
62
63 network = new0(Network, 1);
64 if (!network)
65 return log_oom();
66
67 network->manager = manager;
68
69 LIST_HEAD_INIT(network->static_addresses);
70 LIST_HEAD_INIT(network->static_routes);
71 LIST_HEAD_INIT(network->static_fdb_entries);
72
73 network->stacked_netdevs = hashmap_new(&string_hash_ops);
74 if (!network->stacked_netdevs)
75 return log_oom();
76
77 network->addresses_by_section = hashmap_new(NULL);
78 if (!network->addresses_by_section)
79 return log_oom();
80
81 network->routes_by_section = hashmap_new(NULL);
82 if (!network->routes_by_section)
83 return log_oom();
84
85 network->fdb_entries_by_section = hashmap_new(NULL);
86 if (!network->fdb_entries_by_section)
87 return log_oom();
88
89 network->filename = strdup(filename);
90 if (!network->filename)
91 return log_oom();
92
93 network->name = strdup(basename(filename));
94 if (!network->name)
95 return log_oom();
96
97 d = strrchr(network->name, '.');
98 if (!d)
99 return -EINVAL;
100
101 assert(streq(d, ".network"));
102
103 *d = '\0';
104
105 network->dhcp = ADDRESS_FAMILY_NO;
106 network->dhcp_use_ntp = true;
107 network->dhcp_use_dns = true;
108 network->dhcp_use_hostname = true;
109 network->dhcp_use_routes = true;
110 network->dhcp_send_hostname = true;
111 network->dhcp_route_metric = DHCP_ROUTE_METRIC;
112 network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
113
114 network->dhcp_server_emit_dns = true;
115 network->dhcp_server_emit_ntp = true;
116 network->dhcp_server_emit_router = true;
117 network->dhcp_server_emit_timezone = true;
118
119 network->use_bpdu = true;
120 network->allow_port_to_be_root = true;
121 network->unicast_flood = true;
122
123 network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
124
125 network->llmnr = RESOLVE_SUPPORT_YES;
126 network->mdns = RESOLVE_SUPPORT_NO;
127 network->dnssec_mode = _DNSSEC_MODE_INVALID;
128
129 network->link_local = ADDRESS_FAMILY_IPV6;
130
131 network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
132 network->ipv6_accept_ra = -1;
133 network->ipv6_dad_transmits = -1;
134 network->ipv6_hop_limit = -1;
135 network->duid.type = _DUID_TYPE_INVALID;
136 network->proxy_arp = -1;
137 network->ipv6_accept_ra_use_dns = true;
138
139 r = config_parse(NULL, filename, file,
140 "Match\0"
141 "Link\0"
142 "Network\0"
143 "Address\0"
144 "Route\0"
145 "DHCP\0"
146 "DHCPv4\0" /* compat */
147 "DHCPServer\0"
148 "Bridge\0"
149 "BridgeFDB\0",
150 config_item_perf_lookup, network_network_gperf_lookup,
151 false, false, true, network);
152 if (r < 0)
153 return r;
154
155 /* IPMasquerade=yes implies IPForward=yes */
156 if (network->ip_masquerade)
157 network->ip_forward |= ADDRESS_FAMILY_IPV4;
158
159 LIST_PREPEND(networks, manager->networks, network);
160
161 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
162 if (r < 0)
163 return r;
164
165 r = hashmap_put(manager->networks_by_name, network->name, network);
166 if (r < 0)
167 return r;
168
169 LIST_FOREACH(routes, route, network->static_routes) {
170 if (!route->family) {
171 log_warning("Route section without Gateway field configured in %s. "
172 "Ignoring", filename);
173 return 0;
174 }
175 }
176
177 LIST_FOREACH(addresses, address, network->static_addresses) {
178 if (!address->family) {
179 log_warning("Address section without Address field configured in %s. "
180 "Ignoring", filename);
181 return 0;
182 }
183 }
184
185 network = NULL;
186
187 return 0;
188 }
189
190 int network_load(Manager *manager) {
191 Network *network;
192 _cleanup_strv_free_ char **files = NULL;
193 char **f;
194 int r;
195
196 assert(manager);
197
198 while ((network = manager->networks))
199 network_free(network);
200
201 r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
202 if (r < 0)
203 return log_error_errno(r, "Failed to enumerate network files: %m");
204
205 STRV_FOREACH_BACKWARDS(f, files) {
206 r = network_load_one(manager, *f);
207 if (r < 0)
208 return r;
209 }
210
211 return 0;
212 }
213
214 void network_free(Network *network) {
215 NetDev *netdev;
216 Route *route;
217 Address *address;
218 FdbEntry *fdb_entry;
219 Iterator i;
220
221 if (!network)
222 return;
223
224 free(network->filename);
225
226 free(network->match_mac);
227 strv_free(network->match_path);
228 strv_free(network->match_driver);
229 strv_free(network->match_type);
230 strv_free(network->match_name);
231
232 free(network->description);
233 free(network->dhcp_vendor_class_identifier);
234 free(network->dhcp_hostname);
235
236 free(network->mac);
237
238 strv_free(network->ntp);
239 strv_free(network->dns);
240 strv_free(network->search_domains);
241 strv_free(network->route_domains);
242 strv_free(network->bind_carrier);
243
244 netdev_unref(network->bridge);
245
246 netdev_unref(network->bond);
247
248 HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) {
249 hashmap_remove(network->stacked_netdevs, netdev->ifname);
250 netdev_unref(netdev);
251 }
252 hashmap_free(network->stacked_netdevs);
253
254 while ((route = network->static_routes))
255 route_free(route);
256
257 while ((address = network->static_addresses))
258 address_free(address);
259
260 while ((fdb_entry = network->static_fdb_entries))
261 fdb_entry_free(fdb_entry);
262
263 hashmap_free(network->addresses_by_section);
264 hashmap_free(network->routes_by_section);
265 hashmap_free(network->fdb_entries_by_section);
266
267 if (network->manager) {
268 if (network->manager->networks)
269 LIST_REMOVE(networks, network->manager->networks, network);
270
271 if (network->manager->networks_by_name)
272 hashmap_remove(network->manager->networks_by_name, network->name);
273 }
274
275 free(network->name);
276
277 condition_free_list(network->match_host);
278 condition_free_list(network->match_virt);
279 condition_free_list(network->match_kernel);
280 condition_free_list(network->match_arch);
281
282 free(network->dhcp_server_timezone);
283 free(network->dhcp_server_dns);
284 free(network->dhcp_server_ntp);
285
286 set_free_free(network->dnssec_negative_trust_anchors);
287
288 free(network);
289 }
290
291 int network_get_by_name(Manager *manager, const char *name, Network **ret) {
292 Network *network;
293
294 assert(manager);
295 assert(name);
296 assert(ret);
297
298 network = hashmap_get(manager->networks_by_name, name);
299 if (!network)
300 return -ENOENT;
301
302 *ret = network;
303
304 return 0;
305 }
306
307 int network_get(Manager *manager, struct udev_device *device,
308 const char *ifname, const struct ether_addr *address,
309 Network **ret) {
310 Network *network;
311 struct udev_device *parent;
312 const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
313
314 assert(manager);
315 assert(ret);
316
317 if (device) {
318 path = udev_device_get_property_value(device, "ID_PATH");
319
320 parent = udev_device_get_parent(device);
321 if (parent)
322 parent_driver = udev_device_get_driver(parent);
323
324 driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
325
326 devtype = udev_device_get_devtype(device);
327 }
328
329 LIST_FOREACH(networks, network, manager->networks) {
330 if (net_match_config(network->match_mac, network->match_path,
331 network->match_driver, network->match_type,
332 network->match_name, network->match_host,
333 network->match_virt, network->match_kernel,
334 network->match_arch,
335 address, path, parent_driver, driver,
336 devtype, ifname)) {
337 if (network->match_name && device) {
338 const char *attr;
339 uint8_t name_assign_type = NET_NAME_UNKNOWN;
340
341 attr = udev_device_get_sysattr_value(device, "name_assign_type");
342 if (attr)
343 (void) safe_atou8(attr, &name_assign_type);
344
345 if (name_assign_type == NET_NAME_ENUM)
346 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
347 ifname, network->filename);
348 else
349 log_debug("%s: found matching network '%s'", ifname, network->filename);
350 } else
351 log_debug("%s: found matching network '%s'", ifname, network->filename);
352
353 *ret = network;
354 return 0;
355 }
356 }
357
358 *ret = NULL;
359
360 return -ENOENT;
361 }
362
363 int network_apply(Manager *manager, Network *network, Link *link) {
364 int r;
365
366 assert(manager);
367 assert(network);
368 assert(link);
369
370 link->network = network;
371
372 if (network->ipv4ll_route) {
373 Route *route;
374
375 r = route_new_static(network, 0, &route);
376 if (r < 0)
377 return r;
378
379 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
380 if (r == 0)
381 return -EINVAL;
382 if (r < 0)
383 return -errno;
384
385 route->family = AF_INET;
386 route->dst_prefixlen = 16;
387 route->scope = RT_SCOPE_LINK;
388 route->priority = IPV4LL_ROUTE_METRIC;
389 route->protocol = RTPROT_STATIC;
390 }
391
392 if (!strv_isempty(network->dns) ||
393 !strv_isempty(network->ntp) ||
394 !strv_isempty(network->search_domains) ||
395 !strv_isempty(network->route_domains)) {
396 manager_dirty(manager);
397 link_dirty(link);
398 }
399
400 return 0;
401 }
402
403 bool network_has_static_ipv6_addresses(Network *network) {
404 Address *address;
405
406 assert(network);
407
408 LIST_FOREACH(addresses, address, network->static_addresses) {
409 if (address->family == AF_INET6)
410 return true;
411 }
412
413 return false;
414 }
415
416 int config_parse_netdev(const char *unit,
417 const char *filename,
418 unsigned line,
419 const char *section,
420 unsigned section_line,
421 const char *lvalue,
422 int ltype,
423 const char *rvalue,
424 void *data,
425 void *userdata) {
426 Network *network = userdata;
427 _cleanup_free_ char *kind_string = NULL;
428 char *p;
429 NetDev *netdev;
430 NetDevKind kind;
431 int r;
432
433 assert(filename);
434 assert(lvalue);
435 assert(rvalue);
436 assert(data);
437
438 kind_string = strdup(lvalue);
439 if (!kind_string)
440 return log_oom();
441
442 /* the keys are CamelCase versions of the kind */
443 for (p = kind_string; *p; p++)
444 *p = tolower(*p);
445
446 kind = netdev_kind_from_string(kind_string);
447 if (kind == _NETDEV_KIND_INVALID) {
448 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
449 return 0;
450 }
451
452 r = netdev_get(network->manager, rvalue, &netdev);
453 if (r < 0) {
454 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
455 return 0;
456 }
457
458 if (netdev->kind != kind) {
459 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
460 return 0;
461 }
462
463 switch (kind) {
464 case NETDEV_KIND_BRIDGE:
465 network->bridge = netdev;
466
467 break;
468 case NETDEV_KIND_BOND:
469 network->bond = netdev;
470
471 break;
472 case NETDEV_KIND_VLAN:
473 case NETDEV_KIND_MACVLAN:
474 case NETDEV_KIND_MACVTAP:
475 case NETDEV_KIND_IPVLAN:
476 case NETDEV_KIND_VXLAN:
477 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
478 if (r < 0) {
479 log_syntax(unit, LOG_ERR, filename, line, r, "Can not add VLAN '%s' to network: %m", rvalue);
480 return 0;
481 }
482
483 break;
484 default:
485 assert_not_reached("Can not parse NetDev");
486 }
487
488 netdev_ref(netdev);
489
490 return 0;
491 }
492
493 int config_parse_domains(
494 const char *unit,
495 const char *filename,
496 unsigned line,
497 const char *section,
498 unsigned section_line,
499 const char *lvalue,
500 int ltype,
501 const char *rvalue,
502 void *data,
503 void *userdata) {
504
505 const char *p;
506 Network *n = data;
507 int r;
508
509 assert(n);
510 assert(lvalue);
511 assert(rvalue);
512
513 if (isempty(rvalue)) {
514 n->search_domains = strv_free(n->search_domains);
515 n->route_domains = strv_free(n->route_domains);
516 return 0;
517 }
518
519 p = rvalue;
520 for (;;) {
521 _cleanup_free_ char *w = NULL, *normalized = NULL;
522 const char *domain;
523 bool is_route;
524
525 r = extract_first_word(&p, &w, NULL, 0);
526 if (r < 0) {
527 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
528 break;
529 }
530 if (r == 0)
531 break;
532
533 is_route = w[0] == '~';
534 domain = is_route ? w + 1 : w;
535
536 if (dns_name_is_root(domain) || streq(domain, "*")) {
537 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
538 * routing domain, unconditionally. */
539 is_route = true;
540 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
541
542 } else {
543 r = dns_name_normalize(domain, &normalized);
544 if (r < 0) {
545 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
546 continue;
547 }
548
549 domain = normalized;
550
551 if (is_localhost(domain)) {
552 log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain);
553 continue;
554 }
555 }
556
557 if (is_route) {
558 r = strv_extend(&n->route_domains, domain);
559 if (r < 0)
560 return log_oom();
561
562 } else {
563 r = strv_extend(&n->search_domains, domain);
564 if (r < 0)
565 return log_oom();
566 }
567 }
568
569 strv_uniq(n->route_domains);
570 strv_uniq(n->search_domains);
571
572 return 0;
573 }
574
575 int config_parse_tunnel(const char *unit,
576 const char *filename,
577 unsigned line,
578 const char *section,
579 unsigned section_line,
580 const char *lvalue,
581 int ltype,
582 const char *rvalue,
583 void *data,
584 void *userdata) {
585 Network *network = userdata;
586 NetDev *netdev;
587 int r;
588
589 assert(filename);
590 assert(lvalue);
591 assert(rvalue);
592 assert(data);
593
594 r = netdev_get(network->manager, rvalue, &netdev);
595 if (r < 0) {
596 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
597 return 0;
598 }
599
600 if (netdev->kind != NETDEV_KIND_IPIP &&
601 netdev->kind != NETDEV_KIND_SIT &&
602 netdev->kind != NETDEV_KIND_GRE &&
603 netdev->kind != NETDEV_KIND_GRETAP &&
604 netdev->kind != NETDEV_KIND_IP6GRE &&
605 netdev->kind != NETDEV_KIND_IP6GRETAP &&
606 netdev->kind != NETDEV_KIND_VTI &&
607 netdev->kind != NETDEV_KIND_VTI6 &&
608 netdev->kind != NETDEV_KIND_IP6TNL
609 ) {
610 log_syntax(unit, LOG_ERR, filename, line, 0,
611 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
612 return 0;
613 }
614
615 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
616 if (r < 0) {
617 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
618 return 0;
619 }
620
621 netdev_ref(netdev);
622
623 return 0;
624 }
625
626 int config_parse_ipv4ll(
627 const char* unit,
628 const char *filename,
629 unsigned line,
630 const char *section,
631 unsigned section_line,
632 const char *lvalue,
633 int ltype,
634 const char *rvalue,
635 void *data,
636 void *userdata) {
637
638 AddressFamilyBoolean *link_local = data;
639
640 assert(filename);
641 assert(lvalue);
642 assert(rvalue);
643 assert(data);
644
645 /* Note that this is mostly like
646 * config_parse_address_family_boolean(), except that it
647 * applies only to IPv4 */
648
649 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
650
651 return 0;
652 }
653
654 int config_parse_dhcp(
655 const char* unit,
656 const char *filename,
657 unsigned line,
658 const char *section,
659 unsigned section_line,
660 const char *lvalue,
661 int ltype,
662 const char *rvalue,
663 void *data,
664 void *userdata) {
665
666 AddressFamilyBoolean *dhcp = data, s;
667
668 assert(filename);
669 assert(lvalue);
670 assert(rvalue);
671 assert(data);
672
673 /* Note that this is mostly like
674 * config_parse_address_family_boolean(), except that it
675 * understands some old names for the enum values */
676
677 s = address_family_boolean_from_string(rvalue);
678 if (s < 0) {
679
680 /* Previously, we had a slightly different enum here,
681 * support its values for compatbility. */
682
683 if (streq(rvalue, "none"))
684 s = ADDRESS_FAMILY_NO;
685 else if (streq(rvalue, "v4"))
686 s = ADDRESS_FAMILY_IPV4;
687 else if (streq(rvalue, "v6"))
688 s = ADDRESS_FAMILY_IPV6;
689 else if (streq(rvalue, "both"))
690 s = ADDRESS_FAMILY_YES;
691 else {
692 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
693 return 0;
694 }
695 }
696
697 *dhcp = s;
698 return 0;
699 }
700
701 static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
702 [DHCP_CLIENT_ID_MAC] = "mac",
703 [DHCP_CLIENT_ID_DUID] = "duid"
704 };
705
706 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
707 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
708
709 int config_parse_ipv6token(
710 const char* unit,
711 const char *filename,
712 unsigned line,
713 const char *section,
714 unsigned section_line,
715 const char *lvalue,
716 int ltype,
717 const char *rvalue,
718 void *data,
719 void *userdata) {
720
721 union in_addr_union buffer;
722 struct in6_addr *token = data;
723 int r;
724
725 assert(filename);
726 assert(lvalue);
727 assert(rvalue);
728 assert(token);
729
730 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
731 if (r < 0) {
732 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
733 return 0;
734 }
735
736 r = in_addr_is_null(AF_INET6, &buffer);
737 if (r != 0) {
738 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
739 return 0;
740 }
741
742 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
743 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
744 return 0;
745 }
746
747 *token = buffer.in6;
748
749 return 0;
750 }
751
752 static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
753 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
754 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
755 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
756 };
757
758 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
759
760 int config_parse_ipv6_privacy_extensions(
761 const char* unit,
762 const char *filename,
763 unsigned line,
764 const char *section,
765 unsigned section_line,
766 const char *lvalue,
767 int ltype,
768 const char *rvalue,
769 void *data,
770 void *userdata) {
771
772 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
773 int k;
774
775 assert(filename);
776 assert(lvalue);
777 assert(rvalue);
778 assert(ipv6_privacy_extensions);
779
780 /* Our enum shall be a superset of booleans, hence first try
781 * to parse as boolean, and then as enum */
782
783 k = parse_boolean(rvalue);
784 if (k > 0)
785 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
786 else if (k == 0)
787 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
788 else {
789 IPv6PrivacyExtensions s;
790
791 s = ipv6_privacy_extensions_from_string(rvalue);
792 if (s < 0) {
793
794 if (streq(rvalue, "kernel"))
795 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
796 else {
797 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
798 return 0;
799 }
800 }
801
802 *ipv6_privacy_extensions = s;
803 }
804
805 return 0;
806 }
807
808 int config_parse_hostname(
809 const char *unit,
810 const char *filename,
811 unsigned line,
812 const char *section,
813 unsigned section_line,
814 const char *lvalue,
815 int ltype,
816 const char *rvalue,
817 void *data,
818 void *userdata) {
819
820 char **hostname = data, *hn = NULL;
821 int r;
822
823 assert(filename);
824 assert(lvalue);
825 assert(rvalue);
826
827 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
828 if (r < 0)
829 return r;
830
831 if (!hostname_is_valid(hn, false)) {
832 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
833 free(hn);
834 return 0;
835 }
836
837 free(*hostname);
838 *hostname = hostname_cleanup(hn);
839 return 0;
840 }
841
842 int config_parse_timezone(
843 const char *unit,
844 const char *filename,
845 unsigned line,
846 const char *section,
847 unsigned section_line,
848 const char *lvalue,
849 int ltype,
850 const char *rvalue,
851 void *data,
852 void *userdata) {
853
854 char **datap = data, *tz = NULL;
855 int r;
856
857 assert(filename);
858 assert(lvalue);
859 assert(rvalue);
860
861 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
862 if (r < 0)
863 return r;
864
865 if (!timezone_is_valid(tz)) {
866 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
867 free(tz);
868 return 0;
869 }
870
871 free(*datap);
872 *datap = tz;
873
874 return 0;
875 }
876
877 int config_parse_dhcp_server_dns(
878 const char *unit,
879 const char *filename,
880 unsigned line,
881 const char *section,
882 unsigned section_line,
883 const char *lvalue,
884 int ltype,
885 const char *rvalue,
886 void *data,
887 void *userdata) {
888
889 Network *n = data;
890 const char *p = rvalue;
891 int r;
892
893 assert(filename);
894 assert(lvalue);
895 assert(rvalue);
896
897 for (;;) {
898 _cleanup_free_ char *w = NULL;
899 struct in_addr a, *m;
900
901 r = extract_first_word(&p, &w, NULL, 0);
902 if (r < 0) {
903 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
904 return 0;
905 }
906
907 if (r == 0)
908 return 0;
909
910 if (inet_pton(AF_INET, w, &a) <= 0) {
911 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
912 continue;
913 }
914
915 m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr));
916 if (!m)
917 return log_oom();
918
919 m[n->n_dhcp_server_dns++] = a;
920 n->dhcp_server_dns = m;
921 }
922 }
923
924 int config_parse_dhcp_server_ntp(
925 const char *unit,
926 const char *filename,
927 unsigned line,
928 const char *section,
929 unsigned section_line,
930 const char *lvalue,
931 int ltype,
932 const char *rvalue,
933 void *data,
934 void *userdata) {
935
936 Network *n = data;
937 const char *p = rvalue;
938 int r;
939
940 assert(filename);
941 assert(lvalue);
942 assert(rvalue);
943
944 for (;;) {
945 _cleanup_free_ char *w = NULL;
946 struct in_addr a, *m;
947
948 r = extract_first_word(&p, &w, NULL, 0);
949 if (r < 0) {
950 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
951 return 0;
952 }
953
954 if (r == 0)
955 return 0;
956
957 if (inet_pton(AF_INET, w, &a) <= 0) {
958 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
959 continue;
960 }
961
962 m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr));
963 if (!m)
964 return log_oom();
965
966 m[n->n_dhcp_server_ntp++] = a;
967 n->dhcp_server_ntp = m;
968 }
969 }
970
971 int config_parse_dnssec_negative_trust_anchors(
972 const char *unit,
973 const char *filename,
974 unsigned line,
975 const char *section,
976 unsigned section_line,
977 const char *lvalue,
978 int ltype,
979 const char *rvalue,
980 void *data,
981 void *userdata) {
982
983 const char *p = rvalue;
984 Network *n = data;
985 int r;
986
987 assert(n);
988 assert(lvalue);
989 assert(rvalue);
990
991 if (isempty(rvalue)) {
992 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
993 return 0;
994 }
995
996 for (;;) {
997 _cleanup_free_ char *w = NULL;
998
999 r = extract_first_word(&p, &w, NULL, 0);
1000 if (r < 0) {
1001 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1002 break;
1003 }
1004 if (r == 0)
1005 break;
1006
1007 r = dns_name_is_valid(w);
1008 if (r <= 0) {
1009 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1010 continue;
1011 }
1012
1013 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1014 if (r < 0)
1015 return log_oom();
1016
1017 r = set_put(n->dnssec_negative_trust_anchors, w);
1018 if (r < 0)
1019 return log_oom();
1020 if (r > 0)
1021 w = NULL;
1022 }
1023
1024 return 0;
1025 }
1026
1027 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1028
1029 static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1030 [DHCP_USE_DOMAINS_NO] = "no",
1031 [DHCP_USE_DOMAINS_ROUTE] = "route",
1032 [DHCP_USE_DOMAINS_YES] = "yes",
1033 };
1034
1035 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1036
1037 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1038
1039 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1040 [LLDP_MODE_NO] = "no",
1041 [LLDP_MODE_YES] = "yes",
1042 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1043 };
1044
1045 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);