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