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