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