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