]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-network.c
network: do not disable dynamic addressing for bridge slaves
[thirdparty/systemd.git] / src / network / networkd-network.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f579559b 2
69a93e7d 3#include <ctype.h>
987efa17 4#include <net/if.h>
69a93e7d 5
b5efdb8a 6#include "alloc-util.h"
f579559b
TG
7#include "conf-files.h"
8#include "conf-parser.h"
37de2509 9#include "dns-domain.h"
3ffd4af2 10#include "fd-util.h"
07630cea 11#include "hostname-util.h"
88295a05 12#include "in-addr-util.h"
36dd5ffd 13#include "missing_network.h"
fc2f9534 14#include "network-internal.h"
23f53b99 15#include "networkd-manager.h"
3ffd4af2 16#include "networkd-network.h"
6bedfcbb 17#include "parse-util.h"
8a516214 18#include "set.h"
8fcde012 19#include "stat-util.h"
8b43440b 20#include "string-table.h"
07630cea 21#include "string-util.h"
700f1186 22#include "strv.h"
07630cea 23#include "util.h"
f579559b 24
7a08d314 25static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
f4859fc7
SS
26 siphash24_compress(c->filename, strlen(c->filename), state);
27 siphash24_compress(&c->line, sizeof(c->line), state);
28}
29
7a08d314 30static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
f4859fc7
SS
31 int r;
32
33 r = strcmp(x->filename, y->filename);
34 if (r != 0)
35 return r;
36
26cdf3e5 37 return CMP(x->line, y->line);
f4859fc7
SS
38}
39
7a08d314 40DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
f4859fc7
SS
41
42int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
43 NetworkConfigSection *cs;
44
45 cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
46 if (!cs)
47 return -ENOMEM;
48
49 strcpy(cs->filename, filename);
50 cs->line = line;
51
ae2a15bc 52 *s = TAKE_PTR(cs);
f4859fc7
SS
53
54 return 0;
55}
56
57void network_config_section_free(NetworkConfigSection *cs) {
bce67bbe 58 free(cs);
f4859fc7
SS
59}
60
add8d07d 61/* Set defaults following RFC7844 */
62void network_apply_anonymize_if_set(Network *network) {
63 if (!network->dhcp_anonymize)
64 return;
65 /* RFC7844 3.7
66 SHOULD NOT send the Host Name option */
67 network->dhcp_send_hostname = false;
68 /* RFC7844 section 3.:
69 MAY contain the Client Identifier option
70 Section 3.5:
71 clients MUST use client identifiers based solely
72 on the link-layer address */
73 /* NOTE: Using MAC, as it does not reveal extra information,
74 * and some servers might not answer if this option is not sent */
75 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
76 /* RFC 7844 3.10:
77 SHOULD NOT use the Vendor Class Identifier option */
727ba17f 78 network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
add8d07d 79 /* RFC7844 section 3.6.:
80 The client intending to protect its privacy SHOULD only request a
81 minimal number of options in the PRL and SHOULD also randomly shuffle
82 the ordering of option codes in the PRL. If this random ordering
83 cannot be implemented, the client MAY order the option codes in the
84 PRL by option code number (lowest to highest).
85 */
86 /* NOTE: dhcp_use_mtu is false by default,
87 * though it was not initiallized to any value in network_load_one.
88 * Maybe there should be another var called *send*?
89 * (to use the MTU sent by the server but to do not send
90 * the option in the PRL). */
91 network->dhcp_use_mtu = false;
28522b0d 92 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
93 * but this is needed to use them. */
94 network->dhcp_use_routes = true;
add8d07d 95 /* RFC7844 section 3.6.
96 * same comments as previous option */
97 network->dhcp_use_timezone = false;
98}
99
0321cea7
YW
100static int network_verify(Network *network) {
101 Address *address;
102 Route *route;
103
104 assert(network);
105 assert(network->filename);
106
107 if (network->bond) {
108 /* Bonding slave does not support addressing. */
109 if (network->ipv6_accept_ra > 0) {
ab24039f
ZJS
110 log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
111 network->filename);
0321cea7
YW
112 network->ipv6_accept_ra = 0;
113 }
114 if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
115 log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
116 network->filename);
0321cea7
YW
117 network->link_local = ADDRESS_FAMILY_NO;
118 }
119 if (network->dhcp != ADDRESS_FAMILY_NO) {
ab24039f
ZJS
120 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
121 network->filename);
0321cea7
YW
122 network->dhcp = ADDRESS_FAMILY_NO;
123 }
124 if (network->dhcp_server) {
ab24039f
ZJS
125 log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
126 network->filename);
0321cea7
YW
127 network->dhcp_server = false;
128 }
129 if (network->n_static_addresses > 0) {
ab24039f
ZJS
130 log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
131 network->filename);
0321cea7
YW
132 while ((address = network->static_addresses))
133 address_free(address);
134 }
135 if (network->n_static_routes > 0) {
ab24039f
ZJS
136 log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
137 network->filename);
0321cea7
YW
138 while ((route = network->static_routes))
139 route_free(route);
140 }
141 }
142
143 if (network->link_local < 0)
144 network->link_local = ADDRESS_FAMILY_IPV6;
145
146 /* IPMasquerade=yes implies IPForward=yes */
147 if (network->ip_masquerade)
148 network->ip_forward |= ADDRESS_FAMILY_IPV4;
149
150 if (network->mtu > 0 && network->dhcp_use_mtu) {
151 log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
152 "Disabling UseMTU=.", network->filename);
153 network->dhcp_use_mtu = false;
154 }
155
156 LIST_FOREACH(routes, route, network->static_routes)
157 if (!route->family)
158 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
159 "%s: Route section without Gateway field configured. "
160 "Ignoring %s.",
161 network->filename, network->filename);
162
163 LIST_FOREACH(addresses, address, network->static_addresses)
164 if (!address->family)
165 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
166 "%s: Address section without Address field configured. "
167 "Ignoring %s.",
168 network->filename, network->filename);
169
170 return 0;
171}
172
212bd73c 173int network_load_one(Manager *manager, const char *filename) {
838b2f7a 174 _cleanup_free_ char *fname = NULL, *name = NULL;
8e766630 175 _cleanup_(network_freep) Network *network = NULL;
f579559b 176 _cleanup_fclose_ FILE *file = NULL;
047a0dac 177 const char *dropin_dirname;
838b2f7a 178 char *d;
f579559b
TG
179 int r;
180
bf1bc670
TA
181 assert(manager);
182 assert(filename);
183
f579559b
TG
184 file = fopen(filename, "re");
185 if (!file) {
186 if (errno == ENOENT)
187 return 0;
1e7a0e21
LP
188
189 return -errno;
f579559b
TG
190 }
191
ed88bcfb
ZJS
192 if (null_or_empty_fd(fileno(file))) {
193 log_debug("Skipping empty file: %s", filename);
6916ec29
TG
194 return 0;
195 }
196
838b2f7a
YW
197 fname = strdup(filename);
198 if (!fname)
199 return log_oom();
200
201 name = strdup(basename(filename));
202 if (!name)
203 return log_oom();
204
205 d = strrchr(name, '.');
206 if (!d)
207 return -EINVAL;
208
209 *d = '\0';
210
211 dropin_dirname = strjoina(name, ".network.d");
212
17f9c355 213 network = new(Network, 1);
f579559b
TG
214 if (!network)
215 return log_oom();
216
17f9c355
YW
217 *network = (Network) {
218 .manager = manager,
838b2f7a
YW
219 .filename = TAKE_PTR(fname),
220 .name = TAKE_PTR(name),
17f9c355
YW
221
222 .required_for_online = true,
223 .dhcp = ADDRESS_FAMILY_NO,
224 .dhcp_use_ntp = true,
225 .dhcp_use_dns = true,
226 .dhcp_use_hostname = true,
227 .dhcp_use_routes = true,
228 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
229 .dhcp_send_hostname = true,
230 /* To enable/disable RFC7844 Anonymity Profiles */
231 .dhcp_anonymize = false,
232 .dhcp_route_metric = DHCP_ROUTE_METRIC,
233 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
234 .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
235 .dhcp_route_table = RT_TABLE_MAIN,
236 .dhcp_route_table_set = false,
237 /* NOTE: from man: UseMTU=... Defaults to false*/
238 .dhcp_use_mtu = false,
239 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
240 .dhcp_use_timezone = false,
241 .rapid_commit = true,
242
243 .dhcp_server_emit_dns = true,
244 .dhcp_server_emit_ntp = true,
245 .dhcp_server_emit_router = true,
246 .dhcp_server_emit_timezone = true,
247
248 .router_emit_dns = true,
249 .router_emit_domains = true,
250
251 .use_bpdu = -1,
252 .hairpin = -1,
253 .fast_leave = -1,
254 .allow_port_to_be_root = -1,
255 .unicast_flood = -1,
d3aa8b49 256 .multicast_to_unicast = -1,
17f9c355
YW
257 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
258
259 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
260
7ece6f58 261 .dns_default_route = -1,
17f9c355
YW
262 .llmnr = RESOLVE_SUPPORT_YES,
263 .mdns = RESOLVE_SUPPORT_NO,
264 .dnssec_mode = _DNSSEC_MODE_INVALID,
265 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
266
0321cea7
YW
267 /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
268 .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
17f9c355
YW
269
270 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
271 .ipv6_accept_ra = -1,
272 .ipv6_dad_transmits = -1,
273 .ipv6_hop_limit = -1,
274 .ipv6_proxy_ndp = -1,
275 .duid.type = _DUID_TYPE_INVALID,
276 .proxy_arp = -1,
277 .arp = -1,
278 .multicast = -1,
279 .allmulticast = -1,
280 .ipv6_accept_ra_use_dns = true,
062c2eea
SS
281 .ipv6_accept_ra_use_autonomous_prefix = true,
282 .ipv6_accept_ra_use_onlink_prefix = true,
17f9c355 283 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
d5fa3339 284 .ipv6_accept_ra_route_table_set = false,
17f9c355 285 };
f579559b 286
dc0d4078 287 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
23bb31aa
ZJS
288 "Match\0"
289 "Link\0"
290 "Network\0"
291 "Address\0"
e4a71bf3 292 "Neighbor\0"
95b74ef6 293 "IPv6AddressLabel\0"
bce67bbe 294 "RoutingPolicyRule\0"
23bb31aa
ZJS
295 "Route\0"
296 "DHCP\0"
297 "DHCPv4\0" /* compat */
298 "DHCPServer\0"
299 "IPv6AcceptRA\0"
a0e5c15d 300 "IPv6NDPProxyAddress\0"
23bb31aa
ZJS
301 "Bridge\0"
302 "BridgeFDB\0"
9d5d0090 303 "BridgeVLAN\0"
7d5cac19 304 "IPv6PrefixDelegation\0"
06828bb6
HP
305 "IPv6Prefix\0"
306 "CAN\0",
23bb31aa 307 config_item_perf_lookup, network_network_gperf_lookup,
bcde742e 308 CONFIG_PARSE_WARN, network);
838b2f7a
YW
309 if (r < 0) {
310 /* Unset manager here. Otherwise, LIST_REMOVE() in network_free() fails. */
311 network->manager = NULL;
f579559b 312 return r;
838b2f7a 313 }
f579559b 314
add8d07d 315 network_apply_anonymize_if_set(network);
316
f579559b 317 LIST_PREPEND(networks, manager->networks, network);
b3070dc0 318
dbffab87
TG
319 r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
320 if (r < 0)
321 return r;
322
323 r = hashmap_put(manager->networks_by_name, network->name, network);
324 if (r < 0)
325 return r;
326
0321cea7
YW
327 if (network_verify(network) < 0)
328 return 0;
b3070dc0 329
f579559b 330 network = NULL;
f579559b
TG
331 return 0;
332}
333
334int network_load(Manager *manager) {
335 Network *network;
477e73b5
ZJS
336 _cleanup_strv_free_ char **files = NULL;
337 char **f;
f579559b
TG
338 int r;
339
340 assert(manager);
341
342 while ((network = manager->networks))
343 network_free(network);
344
dc0d4078 345 r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
f647962d
MS
346 if (r < 0)
347 return log_error_errno(r, "Failed to enumerate network files: %m");
f579559b
TG
348
349 STRV_FOREACH_BACKWARDS(f, files) {
350 r = network_load_one(manager, *f);
351 if (r < 0)
352 return r;
353 }
354
f579559b
TG
355 return 0;
356}
357
f579559b 358void network_free(Network *network) {
a0e5c15d 359 IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
bce67bbe
SS
360 RoutingPolicyRule *rule;
361 FdbEntry *fdb_entry;
e4a71bf3 362 Neighbor *neighbor;
95b74ef6 363 AddressLabel *label;
057abfd8 364 Prefix *prefix;
bce67bbe 365 Address *address;
bce67bbe 366 Route *route;
f579559b
TG
367
368 if (!network)
369 return;
370
371 free(network->filename);
372
e90d0374 373 set_free_free(network->match_mac);
5256e00e
TG
374 strv_free(network->match_path);
375 strv_free(network->match_driver);
376 strv_free(network->match_type);
377 strv_free(network->match_name);
f579559b
TG
378
379 free(network->description);
edb85f0d 380 free(network->dhcp_vendor_class_identifier);
af1c0de0 381 strv_free(network->dhcp_user_class);
27cb34f5 382 free(network->dhcp_hostname);
f579559b 383
c106cc36
TG
384 free(network->mac);
385
b0e39c82 386 strv_free(network->ntp);
5512a963 387 free(network->dns);
5e2a51d5
ZJS
388 ordered_set_free_free(network->search_domains);
389 ordered_set_free_free(network->route_domains);
0d4ad91d 390 strv_free(network->bind_carrier);
cdd7812b 391
5e2a51d5 392 ordered_set_free_free(network->router_search_domains);
cdd7812b 393 free(network->router_dns);
3bef724f 394
47e2dc31 395 netdev_unref(network->bridge);
47e2dc31 396 netdev_unref(network->bond);
6cb955c6 397 netdev_unref(network->vrf);
47e2dc31 398
fa6f1e54 399 hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
326cb406 400
f048a16b 401 while ((route = network->static_routes))
f579559b
TG
402 route_free(route);
403
f048a16b 404 while ((address = network->static_addresses))
f579559b
TG
405 address_free(address);
406
b98b483b
AR
407 while ((fdb_entry = network->static_fdb_entries))
408 fdb_entry_free(fdb_entry);
409
a0e5c15d
FK
410 while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
411 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
412
e4a71bf3
WKI
413 while ((neighbor = network->neighbors))
414 neighbor_free(neighbor);
415
95b74ef6
SS
416 while ((label = network->address_labels))
417 address_label_free(label);
418
057abfd8
PF
419 while ((prefix = network->static_prefixes))
420 prefix_free(prefix);
421
bce67bbe
SS
422 while ((rule = network->rules))
423 routing_policy_rule_free(rule);
424
6ae115c1
TG
425 hashmap_free(network->addresses_by_section);
426 hashmap_free(network->routes_by_section);
b98b483b 427 hashmap_free(network->fdb_entries_by_section);
e4a71bf3 428 hashmap_free(network->neighbors_by_section);
95b74ef6 429 hashmap_free(network->address_labels_by_section);
057abfd8 430 hashmap_free(network->prefixes_by_section);
bce67bbe 431 hashmap_free(network->rules_by_section);
6ae115c1 432
dbffab87
TG
433 if (network->manager) {
434 if (network->manager->networks)
435 LIST_REMOVE(networks, network->manager->networks, network);
436
e512c6c1 437 if (network->manager->networks_by_name && network->name)
dbffab87 438 hashmap_remove(network->manager->networks_by_name, network->name);
27dfc982
YW
439
440 if (network->manager->duids_requesting_uuid)
441 set_remove(network->manager->duids_requesting_uuid, &network->duid);
dbffab87
TG
442 }
443
444 free(network->name);
f579559b 445
79e16ce3
LP
446 condition_free_list(network->match_host);
447 condition_free_list(network->match_virt);
5022f08a
LP
448 condition_free_list(network->match_kernel_cmdline);
449 condition_free_list(network->match_kernel_version);
79e16ce3
LP
450 condition_free_list(network->match_arch);
451
8eb9058d 452 free(network->dhcp_server_timezone);
1a04db0f
LP
453 free(network->dhcp_server_dns);
454 free(network->dhcp_server_ntp);
8eb9058d 455
8a516214
LP
456 set_free_free(network->dnssec_negative_trust_anchors);
457
f579559b
TG
458 free(network);
459}
460
dbffab87
TG
461int network_get_by_name(Manager *manager, const char *name, Network **ret) {
462 Network *network;
463
464 assert(manager);
465 assert(name);
466 assert(ret);
467
468 network = hashmap_get(manager->networks_by_name, name);
469 if (!network)
470 return -ENOENT;
471
472 *ret = network;
473
474 return 0;
475}
476
51517f9e 477int network_get(Manager *manager, sd_device *device,
505f8da7
TG
478 const char *ifname, const struct ether_addr *address,
479 Network **ret) {
4f4daf41 480 const char *path = NULL, *driver = NULL, *devtype = NULL;
51517f9e 481 Network *network;
f579559b
TG
482
483 assert(manager);
f579559b 484 assert(ret);
af3aa302 485
24c083df 486 if (device) {
51517f9e 487 (void) sd_device_get_property_value(device, "ID_PATH", &path);
af3aa302 488
51517f9e 489 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
af3aa302 490
51517f9e 491 (void) sd_device_get_devtype(device, &devtype);
24c083df 492 }
f579559b 493
f579559b
TG
494 LIST_FOREACH(networks, network, manager->networks) {
495 if (net_match_config(network->match_mac, network->match_path,
505f8da7
TG
496 network->match_driver, network->match_type,
497 network->match_name, network->match_host,
5022f08a
LP
498 network->match_virt, network->match_kernel_cmdline,
499 network->match_kernel_version, network->match_arch,
4f4daf41 500 address, path, driver, devtype, ifname)) {
24c083df 501 if (network->match_name && device) {
ca6038b8
TG
502 const char *attr;
503 uint8_t name_assign_type = NET_NAME_UNKNOWN;
504
51517f9e 505 if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
dc751688 506 (void) safe_atou8(attr, &name_assign_type);
32bc8adc
TG
507
508 if (name_assign_type == NET_NAME_ENUM)
a2fae7bb
TG
509 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
510 ifname, network->filename);
32bc8adc 511 else
a2fae7bb 512 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 513 } else
a2fae7bb 514 log_debug("%s: found matching network '%s'", ifname, network->filename);
32bc8adc 515
f579559b
TG
516 *ret = network;
517 return 0;
518 }
519 }
520
521 *ret = NULL;
522
523 return -ENOENT;
524}
525
7d342c03 526int network_apply(Network *network, Link *link) {
f579559b
TG
527 int r;
528
c4a03a56
TG
529 assert(network);
530 assert(link);
531
f579559b
TG
532 link->network = network;
533
bfa695b5
TG
534 if (network->ipv4ll_route) {
535 Route *route;
536
0b180d75 537 r = route_new_static(network, NULL, 0, &route);
bfa695b5
TG
538 if (r < 0)
539 return r;
540
2ce40956 541 r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
bfa695b5
TG
542 if (r == 0)
543 return -EINVAL;
544 if (r < 0)
545 return -errno;
546
547 route->family = AF_INET;
548 route->dst_prefixlen = 16;
549 route->scope = RT_SCOPE_LINK;
86655331 550 route->priority = IPV4LL_ROUTE_METRIC;
bfa695b5
TG
551 route->protocol = RTPROT_STATIC;
552 }
553
5512a963 554 if (network->n_dns > 0 ||
3df9bec5 555 !strv_isempty(network->ntp) ||
5e2a51d5
ZJS
556 !ordered_set_isempty(network->search_domains) ||
557 !ordered_set_isempty(network->route_domains))
84de38c5 558 link_dirty(link);
3bef724f 559
f579559b
TG
560 return 0;
561}
02b59d57 562
439689c6
SS
563bool network_has_static_ipv6_addresses(Network *network) {
564 Address *address;
565
566 assert(network);
567
568 LIST_FOREACH(addresses, address, network->static_addresses) {
569 if (address->family == AF_INET6)
570 return true;
571 }
572
573 return false;
574}
575
69a93e7d 576int config_parse_netdev(const char *unit,
02b59d57
TG
577 const char *filename,
578 unsigned line,
579 const char *section,
580 unsigned section_line,
581 const char *lvalue,
582 int ltype,
583 const char *rvalue,
584 void *data,
585 void *userdata) {
586 Network *network = userdata;
31d0ac36
TG
587 _cleanup_free_ char *kind_string = NULL;
588 char *p;
1a436809 589 NetDev *netdev;
69a93e7d 590 NetDevKind kind;
02b59d57
TG
591 int r;
592
593 assert(filename);
594 assert(lvalue);
595 assert(rvalue);
596 assert(data);
597
69a93e7d
TG
598 kind_string = strdup(lvalue);
599 if (!kind_string)
600 return log_oom();
52433f6b 601
69a93e7d
TG
602 /* the keys are CamelCase versions of the kind */
603 for (p = kind_string; *p; p++)
604 *p = tolower(*p);
52433f6b 605
69a93e7d
TG
606 kind = netdev_kind_from_string(kind_string);
607 if (kind == _NETDEV_KIND_INVALID) {
ab24039f
ZJS
608 log_syntax(unit, LOG_ERR, filename, line, 0,
609 "Invalid NetDev kind: %s", lvalue);
52433f6b
TG
610 return 0;
611 }
612
54abf461
TG
613 r = netdev_get(network->manager, rvalue, &netdev);
614 if (r < 0) {
ab24039f
ZJS
615 log_syntax(unit, LOG_ERR, filename, line, r,
616 "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
617 return 0;
618 }
619
69a93e7d 620 if (netdev->kind != kind) {
ab24039f
ZJS
621 log_syntax(unit, LOG_ERR, filename, line, 0,
622 "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
54abf461
TG
623 return 0;
624 }
625
69a93e7d
TG
626 switch (kind) {
627 case NETDEV_KIND_BRIDGE:
25ed70f7 628 network->bridge = netdev_unref(network->bridge);
69a93e7d 629 network->bridge = netdev;
54abf461 630
69a93e7d
TG
631 break;
632 case NETDEV_KIND_BOND:
25ed70f7 633 network->bond = netdev_unref(network->bond);
69a93e7d 634 network->bond = netdev;
fe6b2d55 635
6cb955c6
AR
636 break;
637 case NETDEV_KIND_VRF:
25ed70f7 638 network->vrf = netdev_unref(network->vrf);
6cb955c6
AR
639 network->vrf = netdev;
640
69a93e7d
TG
641 break;
642 case NETDEV_KIND_VLAN:
69a93e7d 643 case NETDEV_KIND_MACVLAN:
f33ff02b 644 case NETDEV_KIND_MACVTAP:
c4a5ddc9 645 case NETDEV_KIND_IPVLAN:
326cb406 646 case NETDEV_KIND_VXLAN:
92c918b0 647 case NETDEV_KIND_VCAN:
3e570042
YW
648 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
649 if (r < 0)
650 return log_oom();
651
6a0a2f86 652 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
326cb406 653 if (r < 0) {
87ac8d99 654 log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
326cb406
SS
655 return 0;
656 }
657
69a93e7d
TG
658 break;
659 default:
87ac8d99 660 assert_not_reached("Cannot parse NetDev");
fe6b2d55
TG
661 }
662
47e2dc31
TG
663 netdev_ref(netdev);
664
fe6b2d55
TG
665 return 0;
666}
7951dea2 667
3df9bec5
LP
668int config_parse_domains(
669 const char *unit,
670 const char *filename,
671 unsigned line,
672 const char *section,
673 unsigned section_line,
674 const char *lvalue,
675 int ltype,
676 const char *rvalue,
677 void *data,
678 void *userdata) {
679
680 const char *p;
681 Network *n = data;
6192b846
TG
682 int r;
683
3df9bec5
LP
684 assert(n);
685 assert(lvalue);
686 assert(rvalue);
6192b846 687
3df9bec5 688 if (isempty(rvalue)) {
5e2a51d5
ZJS
689 n->search_domains = ordered_set_free_free(n->search_domains);
690 n->route_domains = ordered_set_free_free(n->route_domains);
3df9bec5
LP
691 return 0;
692 }
67272d15 693
3df9bec5
LP
694 p = rvalue;
695 for (;;) {
696 _cleanup_free_ char *w = NULL, *normalized = NULL;
697 const char *domain;
698 bool is_route;
699
700 r = extract_first_word(&p, &w, NULL, 0);
701 if (r < 0) {
ab24039f
ZJS
702 log_syntax(unit, LOG_ERR, filename, line, r,
703 "Failed to extract search or route domain, ignoring: %s", rvalue);
3df9bec5
LP
704 break;
705 }
706 if (r == 0)
707 break;
708
709 is_route = w[0] == '~';
710 domain = is_route ? w + 1 : w;
711
712 if (dns_name_is_root(domain) || streq(domain, "*")) {
ab24039f
ZJS
713 /* If the root domain appears as is, or the special token "*" is found, we'll
714 * consider this as routing domain, unconditionally. */
3df9bec5 715 is_route = true;
ab24039f
ZJS
716 domain = "."; /* make sure we don't allow empty strings, thus write the root
717 * domain as "." */
3df9bec5 718 } else {
7470cc4c 719 r = dns_name_normalize(domain, 0, &normalized);
3df9bec5 720 if (r < 0) {
ab24039f
ZJS
721 log_syntax(unit, LOG_ERR, filename, line, r,
722 "'%s' is not a valid domain name, ignoring.", domain);
3df9bec5
LP
723 continue;
724 }
725
726 domain = normalized;
727
728 if (is_localhost(domain)) {
ab24039f
ZJS
729 log_syntax(unit, LOG_ERR, filename, line, 0,
730 "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
731 domain);
37de2509 732 continue;
3df9bec5 733 }
37de2509 734 }
40274ed6 735
5e2a51d5
ZJS
736 OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
737 r = ordered_set_ensure_allocated(set, &string_hash_ops);
738 if (r < 0)
739 return r;
740
741 r = ordered_set_put_strdup(*set, domain);
09451975
LP
742 if (r < 0)
743 return log_oom();
40274ed6 744 }
f15b6e5a 745
6192b846
TG
746 return 0;
747}
748
7951dea2
SS
749int config_parse_tunnel(const char *unit,
750 const char *filename,
751 unsigned line,
752 const char *section,
753 unsigned section_line,
754 const char *lvalue,
755 int ltype,
756 const char *rvalue,
757 void *data,
758 void *userdata) {
759 Network *network = userdata;
760 NetDev *netdev;
761 int r;
762
763 assert(filename);
764 assert(lvalue);
765 assert(rvalue);
766 assert(data);
767
768 r = netdev_get(network->manager, rvalue, &netdev);
769 if (r < 0) {
ab24039f
ZJS
770 log_syntax(unit, LOG_ERR, filename, line, r,
771 "Tunnel is invalid, ignoring assignment: %s", rvalue);
7951dea2
SS
772 return 0;
773 }
774
d29ad81e
ZJS
775 if (!IN_SET(netdev->kind,
776 NETDEV_KIND_IPIP,
777 NETDEV_KIND_SIT,
778 NETDEV_KIND_GRE,
779 NETDEV_KIND_GRETAP,
780 NETDEV_KIND_IP6GRE,
781 NETDEV_KIND_IP6GRETAP,
782 NETDEV_KIND_VTI,
783 NETDEV_KIND_VTI6,
784 NETDEV_KIND_IP6TNL)) {
12ca818f 785 log_syntax(unit, LOG_ERR, filename, line, 0,
7951dea2
SS
786 "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
787 return 0;
788 }
789
3e570042
YW
790 r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
791 if (r < 0)
792 return log_oom();
793
6a0a2f86
TG
794 r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
795 if (r < 0) {
ab24039f
ZJS
796 log_syntax(unit, LOG_ERR, filename, line, r,
797 "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
6a0a2f86
TG
798 return 0;
799 }
800
801 netdev_ref(netdev);
7951dea2
SS
802
803 return 0;
804}
bd8f6538 805
d0d6a4cd
TG
806int config_parse_ipv4ll(
807 const char* unit,
808 const char *filename,
809 unsigned line,
810 const char *section,
811 unsigned section_line,
812 const char *lvalue,
813 int ltype,
814 const char *rvalue,
815 void *data,
816 void *userdata) {
817
818 AddressFamilyBoolean *link_local = data;
819
820 assert(filename);
821 assert(lvalue);
822 assert(rvalue);
823 assert(data);
824
825 /* Note that this is mostly like
826 * config_parse_address_family_boolean(), except that it
827 * applies only to IPv4 */
828
5883ff60 829 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
d0d6a4cd
TG
830
831 return 0;
832}
833
bd8f6538
TG
834int config_parse_dhcp(
835 const char* unit,
836 const char *filename,
837 unsigned line,
838 const char *section,
839 unsigned section_line,
840 const char *lvalue,
841 int ltype,
842 const char *rvalue,
843 void *data,
844 void *userdata) {
845
cb9fc36a 846 AddressFamilyBoolean *dhcp = data, s;
bd8f6538
TG
847
848 assert(filename);
849 assert(lvalue);
850 assert(rvalue);
851 assert(data);
852
769d324c
LP
853 /* Note that this is mostly like
854 * config_parse_address_family_boolean(), except that it
855 * understands some old names for the enum values */
856
cb9fc36a
LP
857 s = address_family_boolean_from_string(rvalue);
858 if (s < 0) {
859
860 /* Previously, we had a slightly different enum here,
861 * support its values for compatbility. */
862
863 if (streq(rvalue, "none"))
864 s = ADDRESS_FAMILY_NO;
865 else if (streq(rvalue, "v4"))
866 s = ADDRESS_FAMILY_IPV4;
867 else if (streq(rvalue, "v6"))
868 s = ADDRESS_FAMILY_IPV6;
869 else if (streq(rvalue, "both"))
870 s = ADDRESS_FAMILY_YES;
871 else {
ab24039f
ZJS
872 log_syntax(unit, LOG_ERR, filename, line, 0,
873 "Failed to parse DHCP option, ignoring: %s", rvalue);
bd8f6538
TG
874 return 0;
875 }
41f62acc
YW
876
877 log_syntax(unit, LOG_WARNING, filename, line, 0,
878 "DHCP=%s is deprecated, please use DHCP=%s instead.",
879 rvalue, address_family_boolean_to_string(s));
bd8f6538
TG
880 }
881
cb9fc36a 882 *dhcp = s;
bd8f6538
TG
883 return 0;
884}
885
3e43b2cd
JJ
886static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
887 [DHCP_CLIENT_ID_MAC] = "mac",
dace710c
YW
888 [DHCP_CLIENT_ID_DUID] = "duid",
889 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
3e43b2cd
JJ
890};
891
499d555a 892DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
ab24039f
ZJS
893DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
894 "Failed to parse client identifier type");
3e43b2cd 895
60c35566 896int config_parse_ipv6token(
7f77697a
TG
897 const char* unit,
898 const char *filename,
899 unsigned line,
900 const char *section,
901 unsigned section_line,
902 const char *lvalue,
903 int ltype,
904 const char *rvalue,
905 void *data,
906 void *userdata) {
907
908 union in_addr_union buffer;
909 struct in6_addr *token = data;
910 int r;
911
912 assert(filename);
913 assert(lvalue);
914 assert(rvalue);
915 assert(token);
916
917 r = in_addr_from_string(AF_INET6, rvalue, &buffer);
918 if (r < 0) {
ab24039f
ZJS
919 log_syntax(unit, LOG_ERR, filename, line, r,
920 "Failed to parse IPv6 token, ignoring: %s", rvalue);
7f77697a
TG
921 return 0;
922 }
923
c606db69 924 if (in_addr_is_null(AF_INET6, &buffer)) {
ab24039f
ZJS
925 log_syntax(unit, LOG_ERR, filename, line, 0,
926 "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
7f77697a
TG
927 return 0;
928 }
929
930 if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
ab24039f
ZJS
931 log_syntax(unit, LOG_ERR, filename, line, 0,
932 "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
7f77697a
TG
933 return 0;
934 }
935
936 *token = buffer.in6;
937
938 return 0;
939}
8add5f79 940
49092e22 941static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
1f0d9695
LP
942 [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
943 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
944 [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
49092e22
SS
945};
946
947DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
948
949int config_parse_ipv6_privacy_extensions(
950 const char* unit,
951 const char *filename,
952 unsigned line,
953 const char *section,
954 unsigned section_line,
955 const char *lvalue,
956 int ltype,
957 const char *rvalue,
958 void *data,
959 void *userdata) {
960
961 IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
962 int k;
963
964 assert(filename);
965 assert(lvalue);
966 assert(rvalue);
967 assert(ipv6_privacy_extensions);
968
969 /* Our enum shall be a superset of booleans, hence first try
970 * to parse as boolean, and then as enum */
971
972 k = parse_boolean(rvalue);
973 if (k > 0)
1f0d9695 974 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
49092e22 975 else if (k == 0)
1f0d9695 976 *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
49092e22 977 else {
1f0d9695 978 IPv6PrivacyExtensions s;
49092e22
SS
979
980 s = ipv6_privacy_extensions_from_string(rvalue);
1f0d9695
LP
981 if (s < 0) {
982
983 if (streq(rvalue, "kernel"))
984 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
985 else {
ab24039f
ZJS
986 log_syntax(unit, LOG_ERR, filename, line, 0,
987 "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1f0d9695
LP
988 return 0;
989 }
49092e22
SS
990 }
991
992 *ipv6_privacy_extensions = s;
993 }
994
995 return 0;
996}
a7d0ef44 997
1ac608c9
LP
998int config_parse_hostname(
999 const char *unit,
1000 const char *filename,
1001 unsigned line,
1002 const char *section,
1003 unsigned section_line,
1004 const char *lvalue,
1005 int ltype,
1006 const char *rvalue,
1007 void *data,
1008 void *userdata) {
1009
6528693a
YW
1010 _cleanup_free_ char *hn = NULL;
1011 char **hostname = data;
a7d0ef44
SS
1012 int r;
1013
1014 assert(filename);
1015 assert(lvalue);
1016 assert(rvalue);
1017
1ac608c9 1018 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
a7d0ef44
SS
1019 if (r < 0)
1020 return r;
1021
1ac608c9 1022 if (!hostname_is_valid(hn, false)) {
ab24039f
ZJS
1023 log_syntax(unit, LOG_ERR, filename, line, 0,
1024 "Hostname is not valid, ignoring assignment: %s", rvalue);
a7d0ef44
SS
1025 return 0;
1026 }
1027
6528693a
YW
1028 r = dns_name_is_valid(hn);
1029 if (r < 0) {
ab24039f
ZJS
1030 log_syntax(unit, LOG_ERR, filename, line, r,
1031 "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
6528693a
YW
1032 return 0;
1033 }
1034 if (r == 0) {
ab24039f
ZJS
1035 log_syntax(unit, LOG_ERR, filename, line, 0,
1036 "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
6528693a
YW
1037 return 0;
1038 }
1039
1040 return free_and_replace(*hostname, hn);
a7d0ef44 1041}
8eb9058d
LP
1042
1043int config_parse_timezone(
1044 const char *unit,
1045 const char *filename,
1046 unsigned line,
1047 const char *section,
1048 unsigned section_line,
1049 const char *lvalue,
1050 int ltype,
1051 const char *rvalue,
1052 void *data,
1053 void *userdata) {
1054
19f9e4e2
YW
1055 _cleanup_free_ char *tz = NULL;
1056 char **datap = data;
8eb9058d
LP
1057 int r;
1058
1059 assert(filename);
1060 assert(lvalue);
1061 assert(rvalue);
1062
1063 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1064 if (r < 0)
1065 return r;
1066
089fb865 1067 if (!timezone_is_valid(tz, LOG_ERR)) {
ab24039f
ZJS
1068 log_syntax(unit, LOG_ERR, filename, line, 0,
1069 "Timezone is not valid, ignoring assignment: %s", rvalue);
8eb9058d
LP
1070 return 0;
1071 }
1072
19f9e4e2 1073 return free_and_replace(*datap, tz);
8eb9058d 1074}
1a04db0f
LP
1075
1076int config_parse_dhcp_server_dns(
1077 const char *unit,
1078 const char *filename,
1079 unsigned line,
1080 const char *section,
1081 unsigned section_line,
1082 const char *lvalue,
1083 int ltype,
1084 const char *rvalue,
1085 void *data,
1086 void *userdata) {
1087
1088 Network *n = data;
1089 const char *p = rvalue;
1090 int r;
1091
1092 assert(filename);
1093 assert(lvalue);
1094 assert(rvalue);
1095
1096 for (;;) {
1097 _cleanup_free_ char *w = NULL;
1098 struct in_addr a, *m;
1099
1100 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1101 if (r == -ENOMEM)
1102 return log_oom();
1a04db0f 1103 if (r < 0) {
ab24039f
ZJS
1104 log_syntax(unit, LOG_ERR, filename, line, r,
1105 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1106 return 0;
1107 }
1a04db0f 1108 if (r == 0)
fa105ce6 1109 break;
1a04db0f
LP
1110
1111 if (inet_pton(AF_INET, w, &a) <= 0) {
ab24039f
ZJS
1112 log_syntax(unit, LOG_ERR, filename, line, 0,
1113 "Failed to parse DNS server address, ignoring: %s", w);
1a04db0f
LP
1114 continue;
1115 }
1116
62d74c78 1117 m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1a04db0f
LP
1118 if (!m)
1119 return log_oom();
1120
1121 m[n->n_dhcp_server_dns++] = a;
1122 n->dhcp_server_dns = m;
1123 }
fa105ce6 1124
88295a05
PF
1125 return 0;
1126}
1127
1128int config_parse_radv_dns(
1129 const char *unit,
1130 const char *filename,
1131 unsigned line,
1132 const char *section,
1133 unsigned section_line,
1134 const char *lvalue,
1135 int ltype,
1136 const char *rvalue,
1137 void *data,
1138 void *userdata) {
1139
1140 Network *n = data;
1141 const char *p = rvalue;
1142 int r;
1143
1144 assert(filename);
1145 assert(lvalue);
1146 assert(rvalue);
1147
1148 for (;;) {
1149 _cleanup_free_ char *w = NULL;
1150 union in_addr_union a;
1151
1152 r = extract_first_word(&p, &w, NULL, 0);
1153 if (r == -ENOMEM)
1154 return log_oom();
1155 if (r < 0) {
ab24039f
ZJS
1156 log_syntax(unit, LOG_ERR, filename, line, r,
1157 "Failed to extract word, ignoring: %s", rvalue);
88295a05
PF
1158 return 0;
1159 }
1160 if (r == 0)
1161 break;
1162
1163 if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1164 struct in6_addr *m;
1165
62d74c78 1166 m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
88295a05
PF
1167 if (!m)
1168 return log_oom();
1169
1170 m[n->n_router_dns++] = a.in6;
1171 n->router_dns = m;
1172
1173 } else
ab24039f
ZJS
1174 log_syntax(unit, LOG_ERR, filename, line, 0,
1175 "Failed to parse DNS server address, ignoring: %s", w);
88295a05
PF
1176 }
1177
700f1186
PF
1178 return 0;
1179}
1180
1181int config_parse_radv_search_domains(
1182 const char *unit,
1183 const char *filename,
1184 unsigned line,
1185 const char *section,
1186 unsigned section_line,
1187 const char *lvalue,
1188 int ltype,
1189 const char *rvalue,
1190 void *data,
1191 void *userdata) {
1192
1193 Network *n = data;
1194 const char *p = rvalue;
1195 int r;
1196
1197 assert(filename);
1198 assert(lvalue);
1199 assert(rvalue);
1200
1201 for (;;) {
7a99f98b 1202 _cleanup_free_ char *w = NULL, *idna = NULL;
700f1186
PF
1203
1204 r = extract_first_word(&p, &w, NULL, 0);
1205 if (r == -ENOMEM)
1206 return log_oom();
1207 if (r < 0) {
ab24039f
ZJS
1208 log_syntax(unit, LOG_ERR, filename, line, r,
1209 "Failed to extract word, ignoring: %s", rvalue);
700f1186
PF
1210 return 0;
1211 }
1212 if (r == 0)
1213 break;
1214
1215 r = dns_name_apply_idna(w, &idna);
7a99f98b 1216 if (r < 0) {
ab24039f
ZJS
1217 log_syntax(unit, LOG_ERR, filename, line, r,
1218 "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
7a99f98b 1219 continue;
5e2a51d5
ZJS
1220 } else if (r == 0)
1221 /* transfer ownership to simplify subsequent operations */
1222 idna = TAKE_PTR(w);
1223
1224 r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
1225 if (r < 0)
1226 return r;
1227
1228 r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1229 if (r < 0)
1230 return r;
700f1186
PF
1231 }
1232
fa105ce6 1233 return 0;
1a04db0f
LP
1234}
1235
1236int config_parse_dhcp_server_ntp(
1237 const char *unit,
1238 const char *filename,
1239 unsigned line,
1240 const char *section,
1241 unsigned section_line,
1242 const char *lvalue,
1243 int ltype,
1244 const char *rvalue,
1245 void *data,
1246 void *userdata) {
1247
1248 Network *n = data;
1249 const char *p = rvalue;
1250 int r;
1251
1252 assert(filename);
1253 assert(lvalue);
1254 assert(rvalue);
1255
1256 for (;;) {
1257 _cleanup_free_ char *w = NULL;
1258 struct in_addr a, *m;
1259
1260 r = extract_first_word(&p, &w, NULL, 0);
fa105ce6
LP
1261 if (r == -ENOMEM)
1262 return log_oom();
1a04db0f 1263 if (r < 0) {
ab24039f
ZJS
1264 log_syntax(unit, LOG_ERR, filename, line, r,
1265 "Failed to extract word, ignoring: %s", rvalue);
1a04db0f
LP
1266 return 0;
1267 }
1a04db0f
LP
1268 if (r == 0)
1269 return 0;
1270
1271 if (inet_pton(AF_INET, w, &a) <= 0) {
ab24039f
ZJS
1272 log_syntax(unit, LOG_ERR, filename, line, 0,
1273 "Failed to parse NTP server address, ignoring: %s", w);
1a04db0f
LP
1274 continue;
1275 }
1276
62d74c78 1277 m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1a04db0f
LP
1278 if (!m)
1279 return log_oom();
1280
1281 m[n->n_dhcp_server_ntp++] = a;
1282 n->dhcp_server_ntp = m;
1283 }
1284}
8a516214 1285
53253824
SS
1286int config_parse_dns(
1287 const char *unit,
1288 const char *filename,
1289 unsigned line,
1290 const char *section,
1291 unsigned section_line,
1292 const char *lvalue,
1293 int ltype,
1294 const char *rvalue,
1295 void *data,
1296 void *userdata) {
1297
1298 Network *n = userdata;
1299 int r;
1300
1301 assert(filename);
1302 assert(lvalue);
1303 assert(rvalue);
1304
1305 for (;;) {
1306 _cleanup_free_ char *w = NULL;
1307 union in_addr_union a;
5512a963 1308 struct in_addr_data *m;
53253824
SS
1309 int family;
1310
5512a963 1311 r = extract_first_word(&rvalue, &w, NULL, 0);
53253824
SS
1312 if (r == -ENOMEM)
1313 return log_oom();
1314 if (r < 0) {
ab24039f
ZJS
1315 log_syntax(unit, LOG_ERR, filename, line, r,
1316 "Invalid syntax, ignoring: %s", rvalue);
53253824
SS
1317 break;
1318 }
5512a963
LP
1319 if (r == 0)
1320 break;
53253824
SS
1321
1322 r = in_addr_from_string_auto(w, &family, &a);
1323 if (r < 0) {
ab24039f
ZJS
1324 log_syntax(unit, LOG_ERR, filename, line, r,
1325 "Failed to parse dns server address, ignoring: %s", w);
53253824
SS
1326 continue;
1327 }
1328
62d74c78 1329 m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
5512a963 1330 if (!m)
53253824
SS
1331 return log_oom();
1332
5512a963
LP
1333 m[n->n_dns++] = (struct in_addr_data) {
1334 .family = family,
1335 .address = a,
1336 };
1337
1338 n->dns = m;
53253824
SS
1339 }
1340
1341 return 0;
1342}
1343
8a516214
LP
1344int config_parse_dnssec_negative_trust_anchors(
1345 const char *unit,
1346 const char *filename,
1347 unsigned line,
1348 const char *section,
1349 unsigned section_line,
1350 const char *lvalue,
1351 int ltype,
1352 const char *rvalue,
1353 void *data,
1354 void *userdata) {
1355
1356 const char *p = rvalue;
1357 Network *n = data;
1358 int r;
1359
3df9bec5 1360 assert(n);
8a516214
LP
1361 assert(lvalue);
1362 assert(rvalue);
1363
1364 if (isempty(rvalue)) {
1365 n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1366 return 0;
1367 }
1368
1369 for (;;) {
1370 _cleanup_free_ char *w = NULL;
1371
1372 r = extract_first_word(&p, &w, NULL, 0);
1373 if (r < 0) {
ab24039f
ZJS
1374 log_syntax(unit, LOG_ERR, filename, line, r,
1375 "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
8a516214
LP
1376 break;
1377 }
1378 if (r == 0)
1379 break;
1380
1381 r = dns_name_is_valid(w);
1382 if (r <= 0) {
ab24039f
ZJS
1383 log_syntax(unit, LOG_ERR, filename, line, r,
1384 "%s is not a valid domain name, ignoring.", w);
8a516214
LP
1385 continue;
1386 }
1387
cbbf38ae
LP
1388 r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1389 if (r < 0)
1390 return log_oom();
1391
8a516214
LP
1392 r = set_put(n->dnssec_negative_trust_anchors, w);
1393 if (r < 0)
1394 return log_oom();
1395 if (r > 0)
1396 w = NULL;
1397 }
1398
1399 return 0;
1400}
b2a81c0b 1401
26575990
LP
1402int config_parse_ntp(
1403 const char *unit,
1404 const char *filename,
1405 unsigned line,
1406 const char *section,
1407 unsigned section_line,
1408 const char *lvalue,
1409 int ltype,
1410 const char *rvalue,
1411 void *data,
1412 void *userdata) {
1413
1414 char ***l = data;
1415 int r;
1416
1417 assert(l);
1418 assert(lvalue);
1419 assert(rvalue);
1420
1421 if (isempty(rvalue)) {
1422 *l = strv_free(*l);
1423 return 0;
1424 }
1425
1426 for (;;) {
1427 _cleanup_free_ char *w = NULL;
1428
1429 r = extract_first_word(&rvalue, &w, NULL, 0);
1430 if (r == -ENOMEM)
1431 return log_oom();
1432 if (r < 0) {
ab24039f
ZJS
1433 log_syntax(unit, LOG_ERR, filename, line, r,
1434 "Failed to extract NTP server name, ignoring: %s", rvalue);
26575990
LP
1435 break;
1436 }
1437 if (r == 0)
1438 break;
1439
1440 r = dns_name_is_valid_or_address(w);
1441 if (r <= 0) {
ab24039f
ZJS
1442 log_syntax(unit, LOG_ERR, filename, line, r,
1443 "%s is not a valid domain name or IP address, ignoring.", w);
26575990 1444 continue;
af1c0de0
SS
1445 }
1446
1447 r = strv_push(l, w);
1448 if (r < 0)
1449 return log_oom();
1450
1451 w = NULL;
1452 }
1453
1454 return 0;
1455}
1456
1457int config_parse_dhcp_user_class(
1458 const char *unit,
1459 const char *filename,
1460 unsigned line,
1461 const char *section,
1462 unsigned section_line,
1463 const char *lvalue,
1464 int ltype,
1465 const char *rvalue,
1466 void *data,
1467 void *userdata) {
1468
1469 char ***l = data;
1470 int r;
1471
1472 assert(l);
1473 assert(lvalue);
1474 assert(rvalue);
1475
1476 if (isempty(rvalue)) {
1477 *l = strv_free(*l);
1478 return 0;
1479 }
1480
1481 for (;;) {
1482 _cleanup_free_ char *w = NULL;
1483
1484 r = extract_first_word(&rvalue, &w, NULL, 0);
1485 if (r == -ENOMEM)
1486 return log_oom();
1487 if (r < 0) {
ab24039f
ZJS
1488 log_syntax(unit, LOG_ERR, filename, line, r,
1489 "Failed to split user classes option, ignoring: %s", rvalue);
af1c0de0
SS
1490 break;
1491 }
1492 if (r == 0)
1493 break;
1494
1495 if (strlen(w) > 255) {
ab24039f
ZJS
1496 log_syntax(unit, LOG_ERR, filename, line, r,
1497 "%s length is not in the range 1-255, ignoring.", w);
af1c0de0 1498 continue;
26575990
LP
1499 }
1500
1501 r = strv_push(l, w);
1502 if (r < 0)
1503 return log_oom();
1504
1505 w = NULL;
1506 }
1507
1508 return 0;
1509}
1510
d5fa3339
YW
1511int config_parse_section_route_table(
1512 const char *unit,
1513 const char *filename,
1514 unsigned line,
1515 const char *section,
1516 unsigned section_line,
1517 const char *lvalue,
1518 int ltype,
1519 const char *rvalue,
1520 void *data,
1521 void *userdata) {
1522
fc1ba79d 1523 Network *network = data;
f594276b
JK
1524 uint32_t rt;
1525 int r;
1526
1527 assert(filename);
1528 assert(lvalue);
1529 assert(rvalue);
1530 assert(data);
1531
1532 r = safe_atou32(rvalue, &rt);
1533 if (r < 0) {
1534 log_syntax(unit, LOG_ERR, filename, line, r,
d5fa3339 1535 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
f594276b
JK
1536 return 0;
1537 }
1538
d5fa3339
YW
1539 if (streq_ptr(section, "DHCP")) {
1540 network->dhcp_route_table = rt;
1541 network->dhcp_route_table_set = true;
1542 } else { /* section is IPv6AcceptRA */
1543 network->ipv6_accept_ra_route_table = rt;
1544 network->ipv6_accept_ra_route_table_set = true;
1545 }
f594276b
JK
1546
1547 return 0;
1548}
1549
ab24039f
ZJS
1550DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
1551 "Failed to parse DHCP use domains setting");
b2a81c0b
LP
1552
1553static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1554 [DHCP_USE_DOMAINS_NO] = "no",
1555 [DHCP_USE_DOMAINS_ROUTE] = "route",
1556 [DHCP_USE_DOMAINS_YES] = "yes",
1557};
1558
1559DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
34437b4f
LP
1560
1561DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
1562
1563static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
1564 [LLDP_MODE_NO] = "no",
1565 [LLDP_MODE_YES] = "yes",
1566 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
1567};
1568
1569DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
8217ed5e
TH
1570
1571int config_parse_iaid(const char *unit,
1572 const char *filename,
1573 unsigned line,
1574 const char *section,
1575 unsigned section_line,
1576 const char *lvalue,
1577 int ltype,
1578 const char *rvalue,
1579 void *data,
1580 void *userdata) {
1581 Network *network = data;
1582 uint32_t iaid;
1583 int r;
1584
1585 assert(filename);
1586 assert(lvalue);
1587 assert(rvalue);
1588 assert(network);
1589
1590 r = safe_atou32(rvalue, &iaid);
1591 if (r < 0) {
1592 log_syntax(unit, LOG_ERR, filename, line, r,
1593 "Unable to read IAID, ignoring assignment: %s", rvalue);
1594 return 0;
1595 }
1596
1597 network->iaid = iaid;
1598 network->iaid_set = true;
1599
1600 return 0;
1601}