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