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