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