]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
Merge pull request #3914 from keszybz/fix-man-links
[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) ||
398 !strv_isempty(network->route_domains)) {
84de38c5
TG
399 manager_dirty(manager);
400 link_dirty(link);
3bef724f
TG
401 }
402
f579559b
TG
403 return 0;
404}
02b59d57 405
439689c6
SS
406bool network_has_static_ipv6_addresses(Network *network) {
407 Address *address;
408
409 assert(network);
410
411 LIST_FOREACH(addresses, address, network->static_addresses) {
412 if (address->family == AF_INET6)
413 return true;
414 }
415
416 return false;
417}
418
69a93e7d 419int config_parse_netdev(const char *unit,
02b59d57
TG
420 const char *filename,
421 unsigned line,
422 const char *section,
423 unsigned section_line,
424 const char *lvalue,
425 int ltype,
426 const char *rvalue,
427 void *data,
428 void *userdata) {
429 Network *network = userdata;
31d0ac36
TG
430 _cleanup_free_ char *kind_string = NULL;
431 char *p;
1a436809 432 NetDev *netdev;
69a93e7d 433 NetDevKind kind;
02b59d57
TG
434 int r;
435
436 assert(filename);
437 assert(lvalue);
438 assert(rvalue);
439 assert(data);
440
69a93e7d
TG
441 kind_string = strdup(lvalue);
442 if (!kind_string)
443 return log_oom();
52433f6b 444
69a93e7d
TG
445 /* the keys are CamelCase versions of the kind */
446 for (p = kind_string; *p; p++)
447 *p = tolower(*p);
52433f6b 448
69a93e7d
TG
449 kind = netdev_kind_from_string(kind_string);
450 if (kind == _NETDEV_KIND_INVALID) {
12ca818f 451 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
452 return 0;
453 }
454
54abf461
TG
455 r = netdev_get(network->manager, rvalue, &netdev);
456 if (r < 0) {
12ca818f 457 log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
458 return 0;
459 }
460
69a93e7d 461 if (netdev->kind != kind) {
12ca818f 462 log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
463 return 0;
464 }
465
69a93e7d
TG
466 switch (kind) {
467 case NETDEV_KIND_BRIDGE:
468 network->bridge = netdev;
54abf461 469
69a93e7d
TG
470 break;
471 case NETDEV_KIND_BOND:
472 network->bond = netdev;
fe6b2d55 473
6cb955c6
AR
474 break;
475 case NETDEV_KIND_VRF:
476 network->vrf = netdev;
477
69a93e7d
TG
478 break;
479 case NETDEV_KIND_VLAN:
69a93e7d 480 case NETDEV_KIND_MACVLAN:
f33ff02b 481 case NETDEV_KIND_MACVTAP:
c4a5ddc9 482 case NETDEV_KIND_IPVLAN:
326cb406 483 case NETDEV_KIND_VXLAN:
6a0a2f86 484 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406 485 if (r < 0) {
12ca818f 486 log_syntax(unit, LOG_ERR, filename, line, r, "Can not add VLAN '%s' to network: %m", rvalue);
326cb406
SS
487 return 0;
488 }
489
69a93e7d
TG
490 break;
491 default:
492 assert_not_reached("Can not parse NetDev");
fe6b2d55
TG
493 }
494
47e2dc31
TG
495 netdev_ref(netdev);
496
fe6b2d55
TG
497 return 0;
498}
7951dea2 499
3df9bec5
LP
500int config_parse_domains(
501 const char *unit,
502 const char *filename,
503 unsigned line,
504 const char *section,
505 unsigned section_line,
506 const char *lvalue,
507 int ltype,
508 const char *rvalue,
509 void *data,
510 void *userdata) {
511
512 const char *p;
513 Network *n = data;
6192b846
TG
514 int r;
515
3df9bec5
LP
516 assert(n);
517 assert(lvalue);
518 assert(rvalue);
6192b846 519
3df9bec5
LP
520 if (isempty(rvalue)) {
521 n->search_domains = strv_free(n->search_domains);
522 n->route_domains = strv_free(n->route_domains);
523 return 0;
524 }
67272d15 525
3df9bec5
LP
526 p = rvalue;
527 for (;;) {
528 _cleanup_free_ char *w = NULL, *normalized = NULL;
529 const char *domain;
530 bool is_route;
531
532 r = extract_first_word(&p, &w, NULL, 0);
533 if (r < 0) {
534 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue);
535 break;
536 }
537 if (r == 0)
538 break;
539
540 is_route = w[0] == '~';
541 domain = is_route ? w + 1 : w;
542
543 if (dns_name_is_root(domain) || streq(domain, "*")) {
544 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
545 * routing domain, unconditionally. */
546 is_route = true;
547 domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
548
549 } else {
550 r = dns_name_normalize(domain, &normalized);
551 if (r < 0) {
552 log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
553 continue;
554 }
555
556 domain = normalized;
557
558 if (is_localhost(domain)) {
559 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 560 continue;
3df9bec5 561 }
37de2509 562 }
40274ed6 563
3df9bec5
LP
564 if (is_route) {
565 r = strv_extend(&n->route_domains, domain);
566 if (r < 0)
567 return log_oom();
40274ed6 568
3df9bec5
LP
569 } else {
570 r = strv_extend(&n->search_domains, domain);
571 if (r < 0)
572 return log_oom();
573 }
40274ed6 574 }
f15b6e5a 575
3df9bec5
LP
576 strv_uniq(n->route_domains);
577 strv_uniq(n->search_domains);
578
6192b846
TG
579 return 0;
580}
581
7951dea2
SS
582int config_parse_tunnel(const char *unit,
583 const char *filename,
584 unsigned line,
585 const char *section,
586 unsigned section_line,
587 const char *lvalue,
588 int ltype,
589 const char *rvalue,
590 void *data,
591 void *userdata) {
592 Network *network = userdata;
593 NetDev *netdev;
594 int r;
595
596 assert(filename);
597 assert(lvalue);
598 assert(rvalue);
599 assert(data);
600
601 r = netdev_get(network->manager, rvalue, &netdev);
602 if (r < 0) {
6a7a4e4d 603 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
604 return 0;
605 }
606
607 if (netdev->kind != NETDEV_KIND_IPIP &&
608 netdev->kind != NETDEV_KIND_SIT &&
a613382b 609 netdev->kind != NETDEV_KIND_GRE &&
1af2536a 610 netdev->kind != NETDEV_KIND_GRETAP &&
b16492f8
SS
611 netdev->kind != NETDEV_KIND_IP6GRE &&
612 netdev->kind != NETDEV_KIND_IP6GRETAP &&
855ee1a1 613 netdev->kind != NETDEV_KIND_VTI &&
9011ce77 614 netdev->kind != NETDEV_KIND_VTI6 &&
855ee1a1
SS
615 netdev->kind != NETDEV_KIND_IP6TNL
616 ) {
12ca818f 617 log_syntax(unit, LOG_ERR, filename, line, 0,
7951dea2
SS
618 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
619 return 0;
620 }
621
6a0a2f86
TG
622 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
623 if (r < 0) {
6a7a4e4d 624 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
625 return 0;
626 }
627
628 netdev_ref(netdev);
7951dea2
SS
629
630 return 0;
631}
bd8f6538 632
d0d6a4cd
TG
633int config_parse_ipv4ll(
634 const char* unit,
635 const char *filename,
636 unsigned line,
637 const char *section,
638 unsigned section_line,
639 const char *lvalue,
640 int ltype,
641 const char *rvalue,
642 void *data,
643 void *userdata) {
644
645 AddressFamilyBoolean *link_local = data;
646
647 assert(filename);
648 assert(lvalue);
649 assert(rvalue);
650 assert(data);
651
652 /* Note that this is mostly like
653 * config_parse_address_family_boolean(), except that it
654 * applies only to IPv4 */
655
5883ff60 656 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
d0d6a4cd
TG
657
658 return 0;
659}
660
bd8f6538
TG
661int config_parse_dhcp(
662 const char* unit,
663 const char *filename,
664 unsigned line,
665 const char *section,
666 unsigned section_line,
667 const char *lvalue,
668 int ltype,
669 const char *rvalue,
670 void *data,
671 void *userdata) {
672
cb9fc36a 673 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
674
675 assert(filename);
676 assert(lvalue);
677 assert(rvalue);
678 assert(data);
679
769d324c
LP
680 /* Note that this is mostly like
681 * config_parse_address_family_boolean(), except that it
682 * understands some old names for the enum values */
683
cb9fc36a
LP
684 s = address_family_boolean_from_string(rvalue);
685 if (s < 0) {
686
687 /* Previously, we had a slightly different enum here,
688 * support its values for compatbility. */
689
690 if (streq(rvalue, "none"))
691 s = ADDRESS_FAMILY_NO;
692 else if (streq(rvalue, "v4"))
693 s = ADDRESS_FAMILY_IPV4;
694 else if (streq(rvalue, "v6"))
695 s = ADDRESS_FAMILY_IPV6;
696 else if (streq(rvalue, "both"))
697 s = ADDRESS_FAMILY_YES;
698 else {
12ca818f 699 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
700 return 0;
701 }
bd8f6538
TG
702 }
703
cb9fc36a 704 *dhcp = s;
bd8f6538
TG
705 return 0;
706}
707
3e43b2cd
JJ
708static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
709 [DHCP_CLIENT_ID_MAC] = "mac",
710 [DHCP_CLIENT_ID_DUID] = "duid"
711};
712
713DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
714DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
715
60c35566 716int config_parse_ipv6token(
7f77697a
TG
717 const char* unit,
718 const char *filename,
719 unsigned line,
720 const char *section,
721 unsigned section_line,
722 const char *lvalue,
723 int ltype,
724 const char *rvalue,
725 void *data,
726 void *userdata) {
727
728 union in_addr_union buffer;
729 struct in6_addr *token = data;
730 int r;
731
732 assert(filename);
733 assert(lvalue);
734 assert(rvalue);
735 assert(token);
736
737 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
738 if (r < 0) {
6a7a4e4d 739 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
740 return 0;
741 }
742
743 r = in_addr_is_null(AF_INET6, &buffer);
12ca818f 744 if (r != 0) {
6a7a4e4d 745 log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
746 return 0;
747 }
748
749 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
12ca818f 750 log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
751 return 0;
752 }
753
754 *token = buffer.in6;
755
756 return 0;
757}
8add5f79 758
49092e22 759static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
760 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
761 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
762 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
763};
764
765DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
766
767int config_parse_ipv6_privacy_extensions(
768 const char* unit,
769 const char *filename,
770 unsigned line,
771 const char *section,
772 unsigned section_line,
773 const char *lvalue,
774 int ltype,
775 const char *rvalue,
776 void *data,
777 void *userdata) {
778
779 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
780 int k;
781
782 assert(filename);
783 assert(lvalue);
784 assert(rvalue);
785 assert(ipv6_privacy_extensions);
786
787 /* Our enum shall be a superset of booleans, hence first try
788 * to parse as boolean, and then as enum */
789
790 k = parse_boolean(rvalue);
791 if (k > 0)
1f0d9695 792 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 793 else if (k == 0)
1f0d9695 794 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 795 else {
1f0d9695 796 IPv6PrivacyExtensions s;
49092e22
SS
797
798 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
799 if (s < 0) {
800
801 if (streq(rvalue, "kernel"))
802 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
803 else {
12ca818f 804 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
805 return 0;
806 }
49092e22
SS
807 }
808
809 *ipv6_privacy_extensions = s;
810 }
811
812 return 0;
813}
a7d0ef44 814
1ac608c9
LP
815int config_parse_hostname(
816 const char *unit,
817 const char *filename,
818 unsigned line,
819 const char *section,
820 unsigned section_line,
821 const char *lvalue,
822 int ltype,
823 const char *rvalue,
824 void *data,
825 void *userdata) {
826
827 char **hostname = data, *hn = NULL;
a7d0ef44
SS
828 int r;
829
830 assert(filename);
831 assert(lvalue);
832 assert(rvalue);
833
1ac608c9 834 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
835 if (r < 0)
836 return r;
837
1ac608c9 838 if (!hostname_is_valid(hn, false)) {
12ca818f 839 log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
840 free(hn);
841 return 0;
842 }
843
1ac608c9 844 free(*hostname);
ae691c1d 845 *hostname = hostname_cleanup(hn);
a7d0ef44
SS
846 return 0;
847}
8eb9058d
LP
848
849int config_parse_timezone(
850 const char *unit,
851 const char *filename,
852 unsigned line,
853 const char *section,
854 unsigned section_line,
855 const char *lvalue,
856 int ltype,
857 const char *rvalue,
858 void *data,
859 void *userdata) {
860
64d6c229 861 char **datap = data, *tz = NULL;
8eb9058d
LP
862 int r;
863
864 assert(filename);
865 assert(lvalue);
866 assert(rvalue);
867
868 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
869 if (r < 0)
870 return r;
871
872 if (!timezone_is_valid(tz)) {
12ca818f 873 log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
874 free(tz);
875 return 0;
876 }
877
64d6c229
TA
878 free(*datap);
879 *datap = tz;
8eb9058d
LP
880
881 return 0;
882}
1a04db0f
LP
883
884int config_parse_dhcp_server_dns(
885 const char *unit,
886 const char *filename,
887 unsigned line,
888 const char *section,
889 unsigned section_line,
890 const char *lvalue,
891 int ltype,
892 const char *rvalue,
893 void *data,
894 void *userdata) {
895
896 Network *n = data;
897 const char *p = rvalue;
898 int r;
899
900 assert(filename);
901 assert(lvalue);
902 assert(rvalue);
903
904 for (;;) {
905 _cleanup_free_ char *w = NULL;
906 struct in_addr a, *m;
907
908 r = extract_first_word(&p, &w, NULL, 0);
909 if (r < 0) {
910 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
911 return 0;
912 }
913
914 if (r == 0)
915 return 0;
916
917 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 918 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
919 continue;
920 }
921
922 m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr));
923 if (!m)
924 return log_oom();
925
926 m[n->n_dhcp_server_dns++] = a;
927 n->dhcp_server_dns = m;
928 }
929}
930
931int config_parse_dhcp_server_ntp(
932 const char *unit,
933 const char *filename,
934 unsigned line,
935 const char *section,
936 unsigned section_line,
937 const char *lvalue,
938 int ltype,
939 const char *rvalue,
940 void *data,
941 void *userdata) {
942
943 Network *n = data;
944 const char *p = rvalue;
945 int r;
946
947 assert(filename);
948 assert(lvalue);
949 assert(rvalue);
950
951 for (;;) {
952 _cleanup_free_ char *w = NULL;
953 struct in_addr a, *m;
954
955 r = extract_first_word(&p, &w, NULL, 0);
956 if (r < 0) {
12ca818f 957 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
958 return 0;
959 }
960
961 if (r == 0)
962 return 0;
963
964 if (inet_pton(AF_INET, w, &a) <= 0) {
12ca818f 965 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
966 continue;
967 }
968
969 m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr));
970 if (!m)
971 return log_oom();
972
973 m[n->n_dhcp_server_ntp++] = a;
974 n->dhcp_server_ntp = m;
975 }
976}
8a516214
LP
977
978int config_parse_dnssec_negative_trust_anchors(
979 const char *unit,
980 const char *filename,
981 unsigned line,
982 const char *section,
983 unsigned section_line,
984 const char *lvalue,
985 int ltype,
986 const char *rvalue,
987 void *data,
988 void *userdata) {
989
990 const char *p = rvalue;
991 Network *n = data;
992 int r;
993
3df9bec5 994 assert(n);
8a516214
LP
995 assert(lvalue);
996 assert(rvalue);
997
998 if (isempty(rvalue)) {
999 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1000 return 0;
1001 }
1002
1003 for (;;) {
1004 _cleanup_free_ char *w = NULL;
1005
1006 r = extract_first_word(&p, &w, NULL, 0);
1007 if (r < 0) {
1008 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1009 break;
1010 }
1011 if (r == 0)
1012 break;
1013
1014 r = dns_name_is_valid(w);
1015 if (r <= 0) {
1016 log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w);
1017 continue;
1018 }
1019
cbbf38ae
LP
1020 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1021 if (r < 0)
1022 return log_oom();
1023
8a516214
LP
1024 r = set_put(n->dnssec_negative_trust_anchors, w);
1025 if (r < 0)
1026 return log_oom();
1027 if (r > 0)
1028 w = NULL;
1029 }
1030
1031 return 0;
1032}
b2a81c0b
LP
1033
1034DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
1035
1036static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1037 [DHCP_USE_DOMAINS_NO] = "no",
1038 [DHCP_USE_DOMAINS_ROUTE] = "route",
1039 [DHCP_USE_DOMAINS_YES] = "yes",
1040};
1041
1042DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1043
1044DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1045
1046static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1047 [LLDP_MODE_NO] = "no",
1048 [LLDP_MODE_YES] = "yes",
1049 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1050};
1051
1052DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);