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