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