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