Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/network/networkd-network.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
3
#include <net/if.h>
4
#include <netinet/in.h>
5
#include <linux/netdevice.h>
6
7
#include "alloc-util.h"
8
#include "conf-files.h"
9
#include "conf-parser.h"
10
#include "dns-domain.h"
11
#include "fd-util.h"
12
#include "hostname-util.h"
13
#include "in-addr-util.h"
14
#include "network-internal.h"
15
#include "networkd-manager.h"
16
#include "networkd-network.h"
17
#include "parse-util.h"
18
#include "set.h"
19
#include "socket-util.h"
20
#include "stat-util.h"
21
#include "string-table.h"
22
#include "string-util.h"
23
#include "strv.h"
24
#include "util.h"
25
26
/* Let's assume that anything above this number is a user misconfiguration. */
27
3.94k
#define MAX_NTP_SERVERS 128
28
29
/* Set defaults following RFC7844 */
30
9.80k
void network_apply_anonymize_if_set(Network *network) {
31
9.80k
        if (!network->dhcp_anonymize)
32
9.80k
                return;
33
5
        /* RFC7844 3.7
34
5
         SHOULD NOT send the Host Name option */
35
5
        network->dhcp_send_hostname = false;
36
5
        /* RFC7844 section 3.:
37
5
         MAY contain the Client Identifier option
38
5
         Section 3.5:
39
5
         clients MUST use client identifiers based solely
40
5
         on the link-layer address */
41
5
        /* NOTE: Using MAC, as it does not reveal extra information,
42
5
        * and some servers might not answer if this option is not sent */
43
5
        network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
44
5
        /* RFC 7844 3.10:
45
5
         SHOULD NOT use the Vendor Class Identifier option */
46
5
        network->dhcp_vendor_class_identifier = mfree(network->dhcp_vendor_class_identifier);
47
5
        /* RFC7844 section 3.6.:
48
5
         The client intending to protect its privacy SHOULD only request a
49
5
         minimal number of options in the PRL and SHOULD also randomly shuffle
50
5
         the ordering of option codes in the PRL.  If this random ordering
51
5
         cannot be implemented, the client MAY order the option codes in the
52
5
         PRL by option code number (lowest to highest).
53
5
        */
54
5
        /* NOTE: dhcp_use_mtu is false by default,
55
5
        * though it was not initiallized to any value in network_load_one.
56
5
        * Maybe there should be another var called *send*?
57
5
        * (to use the MTU sent by the server but to do not send
58
5
        * the option in the PRL). */
59
5
        network->dhcp_use_mtu = false;
60
5
        /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
61
5
         * but this is needed to use them. */
62
5
        network->dhcp_use_routes = true;
63
5
        /* RFC7844 section 3.6.
64
5
        * same comments as previous option */
65
5
        network->dhcp_use_timezone = false;
66
5
}
67
68
28.5k
static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
69
28.5k
        const char *kind_string;
70
28.5k
        NetDev *netdev;
71
28.5k
        int r;
72
28.5k
73
28.5k
        /* For test-networkd-conf, the check must be earlier than the assertions. */
74
28.5k
        if (!name)
75
27.9k
                return 0;
76
521
77
521
        assert(network);
78
521
        assert(network->manager);
79
521
        assert(network->filename);
80
521
        assert(ret_netdev);
81
521
82
521
        if (kind == _NETDEV_KIND_TUNNEL)
83
52
                kind_string = "tunnel";
84
469
        else {
85
469
                kind_string = netdev_kind_to_string(kind);
86
469
                if (!kind_string)
87
0
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
88
521
                                               "%s: Invalid NetDev kind of %s, ignoring assignment.",
89
521
                                               network->filename, name);
90
521
        }
91
521
92
521
        r = netdev_get(network->manager, name, &netdev);
93
521
        if (r < 0)
94
521
                return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
95
0
                                       network->filename, name);
96
0
97
0
        if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
98
0
                                      IN_SET(netdev->kind,
99
0
                                             NETDEV_KIND_IPIP,
100
0
                                             NETDEV_KIND_SIT,
101
0
                                             NETDEV_KIND_GRE,
102
0
                                             NETDEV_KIND_GRETAP,
103
0
                                             NETDEV_KIND_IP6GRE,
104
0
                                             NETDEV_KIND_IP6GRETAP,
105
0
                                             NETDEV_KIND_VTI,
106
0
                                             NETDEV_KIND_VTI6,
107
0
                                             NETDEV_KIND_IP6TNL,
108
0
                                             NETDEV_KIND_ERSPAN)))
109
0
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
110
0
                                       "%s: NetDev %s is not a %s, ignoring assignment",
111
0
                                       network->filename, name, kind_string);
112
0
113
0
        *ret_netdev = netdev_ref(netdev);
114
0
        return 1;
115
0
}
116
117
9.34k
static int network_resolve_stacked_netdevs(Network *network) {
118
9.34k
        void *name, *kind;
119
9.34k
        Iterator i;
120
9.34k
        int r;
121
9.34k
122
9.34k
        assert(network);
123
9.34k
124
9.34k
        HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) {
125
475
                _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
126
475
127
475
                r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
128
475
                if (r <= 0)
129
475
                        continue;
130
0
131
0
                r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
132
0
                if (r < 0)
133
0
                        return log_oom();
134
0
135
0
                r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
136
0
                if (r < 0)
137
0
                        return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
138
0
                                               network->filename, (const char *) name);
139
0
140
0
                netdev = NULL;
141
0
        }
142
9.34k
143
9.34k
        return 0;
144
9.34k
}
145
146
9.80k
int network_verify(Network *network) {
147
9.80k
        Address *address, *address_next;
148
9.80k
        Route *route, *route_next;
149
9.80k
        FdbEntry *fdb, *fdb_next;
150
9.80k
        Neighbor *neighbor, *neighbor_next;
151
9.80k
        AddressLabel *label, *label_next;
152
9.80k
        Prefix *prefix, *prefix_next;
153
9.80k
        RoutingPolicyRule *rule, *rule_next;
154
9.80k
155
9.80k
        assert(network);
156
9.80k
        assert(network->filename);
157
9.80k
158
9.80k
        if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
159
9.80k
            strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
160
9.80k
            strv_isempty(network->match_name) && !network->conditions)
161
9.80k
                log_warning("%s: No valid settings found in the [Match] section. "
162
9.80k
                            "The file will match all interfaces. "
163
9.80k
                            "If that is intended, please add Name=* in the [Match] section.",
164
9.80k
                            network->filename);
165
9.80k
166
9.80k
        /* skip out early if configuration does not match the environment */
167
9.80k
        if (!condition_test_list(network->conditions, NULL, NULL, NULL))
168
463
                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
169
9.34k
                                       "%s: Conditions in the file do not match the system environment, skipping.",
170
9.34k
                                       network->filename);
171
9.34k
172
9.34k
        (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
173
9.34k
        (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
174
9.34k
        (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
175
9.34k
        (void) network_resolve_stacked_netdevs(network);
176
9.34k
177
9.34k
        /* Free unnecessary entries. */
178
9.34k
        network->bond_name = mfree(network->bond_name);
179
9.34k
        network->bridge_name = mfree(network->bridge_name);
180
9.34k
        network->vrf_name = mfree(network->vrf_name);
181
9.34k
        network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
182
9.34k
183
9.34k
        if (network->bond) {
184
0
                /* Bonding slave does not support addressing. */
185
0
                if (network->ipv6_accept_ra > 0) {
186
0
                        log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
187
0
                                    network->filename);
188
0
                        network->ipv6_accept_ra = 0;
189
0
                }
190
0
                if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
191
0
                        log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
192
0
                                    network->filename);
193
0
                        network->link_local = ADDRESS_FAMILY_NO;
194
0
                }
195
0
                if (network->dhcp != ADDRESS_FAMILY_NO) {
196
0
                        log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
197
0
                                    network->filename);
198
0
                        network->dhcp = ADDRESS_FAMILY_NO;
199
0
                }
200
0
                if (network->dhcp_server) {
201
0
                        log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
202
0
                                    network->filename);
203
0
                        network->dhcp_server = false;
204
0
                }
205
0
                if (network->n_static_addresses > 0) {
206
0
                        log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
207
0
                                    network->filename);
208
0
                        while ((address = network->static_addresses))
209
0
                                address_free(address);
210
0
                }
211
0
                if (network->n_static_routes > 0) {
212
0
                        log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
213
0
                                    network->filename);
214
0
                        while ((route = network->static_routes))
215
0
                                route_free(route);
216
0
                }
217
0
        }
218
9.34k
219
9.34k
        if (network->link_local < 0)
220
9.33k
                network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
221
9.34k
222
9.34k
        if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) &&
223
9.34k
            !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
224
1
                log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. "
225
1
                            "Disabling the fallback assignment.", network->filename);
226
1
                SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false);
227
1
        }
228
9.34k
229
9.34k
        if (network->ipv6_accept_ra < 0 && network->bridge)
230
0
                network->ipv6_accept_ra = false;
231
9.34k
232
9.34k
        /* IPMasquerade=yes implies IPForward=yes */
233
9.34k
        if (network->ip_masquerade)
234
1
                network->ip_forward |= ADDRESS_FAMILY_IPV4;
235
9.34k
236
9.34k
        if (network->mtu > 0 && network->dhcp_use_mtu) {
237
1
                log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
238
1
                            "Disabling UseMTU=.", network->filename);
239
1
                network->dhcp_use_mtu = false;
240
1
        }
241
9.34k
242
9.34k
        if (network->dhcp_critical >= 0) {
243
1
                if (network->keep_configuration >= 0)
244
1
                        log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. "
245
1
                                    "Ignoring CriticalConnection=.", network->filename);
246
1
                else if (network->dhcp_critical)
247
1
                        /* CriticalConnection=yes also preserve foreign static configurations. */
248
1
                        network->keep_configuration = KEEP_CONFIGURATION_YES;
249
0
                else
250
0
                        /* For backward compatibility, we do not release DHCP addresses on manager stop. */
251
0
                        network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
252
1
        }
253
9.34k
254
9.34k
        if (network->keep_configuration < 0)
255
9.34k
                /* For backward compatibility, we do not release DHCP addresses on manager stop. */
256
9.34k
                network->keep_configuration = KEEP_CONFIGURATION_DHCP_ON_STOP;
257
9.34k
258
9.34k
        LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
259
9.34k
                if (address_section_verify(address) < 0)
260
967
                        address_free(address);
261
9.34k
262
9.34k
        LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
263
17.0k
                if (route_section_verify(route, network) < 0)
264
9.74k
                        route_free(route);
265
9.34k
266
9.34k
        LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
267
9.34k
                if (section_is_invalid(fdb->section))
268
368
                        fdb_entry_free(fdb);
269
9.34k
270
9.34k
        LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
271
9.34k
                if (section_is_invalid(neighbor->section))
272
670
                        neighbor_free(neighbor);
273
9.34k
274
9.34k
        LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
275
9.34k
                if (section_is_invalid(label->section))
276
1.22k
                        address_label_free(label);
277
9.34k
278
9.34k
        LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
279
9.34k
                if (section_is_invalid(prefix->section))
280
662
                        prefix_free(prefix);
281
9.34k
282
9.34k
        LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
283
9.34k
                if (section_is_invalid(rule->section))
284
933
                        routing_policy_rule_free(rule);
285
9.34k
286
9.34k
        return 0;
287
9.34k
}
288
289
12.1k
int network_load_one(Manager *manager, const char *filename) {
290
12.1k
        _cleanup_free_ char *fname = NULL, *name = NULL;
291
12.1k
        _cleanup_(network_unrefp) Network *network = NULL;
292
12.1k
        _cleanup_fclose_ FILE *file = NULL;
293
12.1k
        const char *dropin_dirname;
294
12.1k
        char *d;
295
12.1k
        int r;
296
12.1k
297
12.1k
        assert(manager);
298
12.1k
        assert(filename);
299
12.1k
300
12.1k
        file = fopen(filename, "re");
301
12.1k
        if (!file) {
302
0
                if (errno == ENOENT)
303
0
                        return 0;
304
0
305
0
                return -errno;
306
0
        }
307
12.1k
308
12.1k
        if (null_or_empty_fd(fileno(file))) {
309
0
                log_debug("Skipping empty file: %s", filename);
310
0
                return 0;
311
0
        }
312
12.1k
313
12.1k
        fname = strdup(filename);
314
12.1k
        if (!fname)
315
0
                return log_oom();
316
12.1k
317
12.1k
        name = strdup(basename(filename));
318
12.1k
        if (!name)
319
0
                return log_oom();
320
12.1k
321
12.1k
        d = strrchr(name, '.');
322
12.1k
        if (!d)
323
0
                return -EINVAL;
324
12.1k
325
12.1k
        *d = '\0';
326
12.1k
327
24.2k
        dropin_dirname = strjoina(name, ".network.d");
328
24.2k
329
24.2k
        network = new(Network, 1);
330
24.2k
        if (!network)
331
0
                return log_oom();
332
12.1k
333
12.1k
        *network = (Network) {
334
12.1k
                .filename = TAKE_PTR(fname),
335
12.1k
                .name = TAKE_PTR(name),
336
12.1k
337
12.1k
                .manager = manager,
338
12.1k
                .n_ref = 1,
339
12.1k
340
12.1k
                .required_for_online = true,
341
12.1k
                .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
342
12.1k
                .dhcp = ADDRESS_FAMILY_NO,
343
12.1k
                .dhcp_critical = -1,
344
12.1k
                .dhcp_use_ntp = true,
345
12.1k
                .dhcp_use_dns = true,
346
12.1k
                .dhcp_use_hostname = true,
347
12.1k
                .dhcp_use_routes = true,
348
12.1k
                /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
349
12.1k
                .dhcp_send_hostname = true,
350
12.1k
                /* To enable/disable RFC7844 Anonymity Profiles */
351
12.1k
                .dhcp_anonymize = false,
352
12.1k
                .dhcp_route_metric = DHCP_ROUTE_METRIC,
353
12.1k
                /* NOTE: this var might be overwritten by network_apply_anonymize_if_set */
354
12.1k
                .dhcp_client_identifier = DHCP_CLIENT_ID_DUID,
355
12.1k
                .dhcp_route_table = RT_TABLE_MAIN,
356
12.1k
                .dhcp_route_table_set = false,
357
12.1k
                /* NOTE: from man: UseMTU=... Defaults to false*/
358
12.1k
                .dhcp_use_mtu = false,
359
12.1k
                /* NOTE: from man: UseTimezone=... Defaults to "no".*/
360
12.1k
                .dhcp_use_timezone = false,
361
12.1k
                .rapid_commit = true,
362
12.1k
363
12.1k
                .dhcp_server_emit_dns = true,
364
12.1k
                .dhcp_server_emit_ntp = true,
365
12.1k
                .dhcp_server_emit_router = true,
366
12.1k
                .dhcp_server_emit_timezone = true,
367
12.1k
368
12.1k
                .router_emit_dns = true,
369
12.1k
                .router_emit_domains = true,
370
12.1k
371
12.1k
                .use_bpdu = -1,
372
12.1k
                .hairpin = -1,
373
12.1k
                .fast_leave = -1,
374
12.1k
                .allow_port_to_be_root = -1,
375
12.1k
                .unicast_flood = -1,
376
12.1k
                .multicast_flood = -1,
377
12.1k
                .multicast_to_unicast = -1,
378
12.1k
                .neighbor_suppression = -1,
379
12.1k
                .learning = -1,
380
12.1k
                .bridge_proxy_arp = -1,
381
12.1k
                .bridge_proxy_arp_wifi = -1,
382
12.1k
                .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
383
12.1k
                .multicast_router = _MULTICAST_ROUTER_INVALID,
384
12.1k
385
12.1k
                .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
386
12.1k
387
12.1k
                .dns_default_route = -1,
388
12.1k
                .llmnr = RESOLVE_SUPPORT_YES,
389
12.1k
                .mdns = RESOLVE_SUPPORT_NO,
390
12.1k
                .dnssec_mode = _DNSSEC_MODE_INVALID,
391
12.1k
                .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
392
12.1k
393
12.1k
                /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
394
12.1k
                .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
395
12.1k
396
12.1k
                .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
397
12.1k
                .ipv6_accept_ra = -1,
398
12.1k
                .ipv6_dad_transmits = -1,
399
12.1k
                .ipv6_hop_limit = -1,
400
12.1k
                .ipv6_proxy_ndp = -1,
401
12.1k
                .duid.type = _DUID_TYPE_INVALID,
402
12.1k
                .proxy_arp = -1,
403
12.1k
                .arp = -1,
404
12.1k
                .multicast = -1,
405
12.1k
                .allmulticast = -1,
406
12.1k
                .ipv6_accept_ra_use_dns = true,
407
12.1k
                .ipv6_accept_ra_use_autonomous_prefix = true,
408
12.1k
                .ipv6_accept_ra_use_onlink_prefix = true,
409
12.1k
                .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
410
12.1k
                .ipv6_accept_ra_route_table_set = false,
411
12.1k
412
12.1k
                .keep_configuration = _KEEP_CONFIGURATION_INVALID,
413
12.1k
414
12.1k
                .can_triple_sampling = -1,
415
12.1k
        };
416
12.1k
417
12.1k
        r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
418
12.1k
                              "Match\0"
419
12.1k
                              "Link\0"
420
12.1k
                              "Network\0"
421
12.1k
                              "Address\0"
422
12.1k
                              "Neighbor\0"
423
12.1k
                              "IPv6AddressLabel\0"
424
12.1k
                              "RoutingPolicyRule\0"
425
12.1k
                              "Route\0"
426
12.1k
                              "DHCP\0"
427
12.1k
                              "DHCPv4\0" /* compat */
428
12.1k
                              "DHCPServer\0"
429
12.1k
                              "IPv6AcceptRA\0"
430
12.1k
                              "IPv6NDPProxyAddress\0"
431
12.1k
                              "Bridge\0"
432
12.1k
                              "BridgeFDB\0"
433
12.1k
                              "BridgeVLAN\0"
434
12.1k
                              "IPv6PrefixDelegation\0"
435
12.1k
                              "IPv6Prefix\0"
436
12.1k
                              "CAN\0",
437
12.1k
                              config_item_perf_lookup, network_network_gperf_lookup,
438
12.1k
                              CONFIG_PARSE_WARN, network);
439
12.1k
        if (r < 0)
440
2.32k
                return r;
441
9.80k
442
9.80k
        network_apply_anonymize_if_set(network);
443
9.80k
444
9.80k
        r = network_add_ipv4ll_route(network);
445
9.80k
        if (r < 0)
446
9.80k
                log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
447
9.80k
448
9.80k
        r = network_add_default_route_on_device(network);
449
9.80k
        if (r < 0)
450
9.80k
                log_warning_errno(r, "%s: Failed to add default route on device, ignoring: %m",
451
9.80k
                                  network->filename);
452
9.80k
453
9.80k
        r = ordered_hashmap_ensure_allocated(&manager->networks, &string_hash_ops);
454
9.80k
        if (r < 0)
455
0
                return r;
456
9.80k
457
9.80k
        r = ordered_hashmap_put(manager->networks, network->name, network);
458
9.80k
        if (r < 0)
459
0
                return r;
460
9.80k
461
9.80k
        if (network_verify(network) < 0)
462
463
                return 0;
463
9.34k
464
9.34k
        network = NULL;
465
9.34k
        return 0;
466
9.34k
}
467
468
0
int network_load(Manager *manager) {
469
0
        _cleanup_strv_free_ char **files = NULL;
470
0
        char **f;
471
0
        int r;
472
0
473
0
        assert(manager);
474
0
475
0
        ordered_hashmap_clear_with_destructor(manager->networks, network_unref);
476
0
477
0
        r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
478
0
        if (r < 0)
479
0
                return log_error_errno(r, "Failed to enumerate network files: %m");
480
0
481
0
        STRV_FOREACH(f, files) {
482
0
                r = network_load_one(manager, *f);
483
0
                if (r < 0)
484
0
                        return r;
485
0
        }
486
0
487
0
        return 0;
488
0
}
489
490
12.1k
static Network *network_free(Network *network) {
491
12.1k
        IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
492
12.1k
        RoutingPolicyRule *rule;
493
12.1k
        FdbEntry *fdb_entry;
494
12.1k
        Neighbor *neighbor;
495
12.1k
        AddressLabel *label;
496
12.1k
        Prefix *prefix;
497
12.1k
        Address *address;
498
12.1k
        Route *route;
499
12.1k
500
12.1k
        if (!network)
501
0
                return NULL;
502
12.1k
503
12.1k
        free(network->filename);
504
12.1k
505
12.1k
        set_free_free(network->match_mac);
506
12.1k
        strv_free(network->match_path);
507
12.1k
        strv_free(network->match_driver);
508
12.1k
        strv_free(network->match_type);
509
12.1k
        strv_free(network->match_name);
510
12.1k
        condition_free_list(network->conditions);
511
12.1k
512
12.1k
        free(network->description);
513
12.1k
        free(network->dhcp_vendor_class_identifier);
514
12.1k
        strv_free(network->dhcp_user_class);
515
12.1k
        free(network->dhcp_hostname);
516
12.1k
        set_free(network->dhcp_black_listed_ip);
517
12.1k
        free(network->mac);
518
12.1k
519
12.1k
        strv_free(network->ntp);
520
12.1k
        free(network->dns);
521
12.1k
        ordered_set_free_free(network->search_domains);
522
12.1k
        ordered_set_free_free(network->route_domains);
523
12.1k
        strv_free(network->bind_carrier);
524
12.1k
525
12.1k
        ordered_set_free_free(network->router_search_domains);
526
12.1k
        free(network->router_dns);
527
12.1k
        set_free_free(network->ndisc_black_listed_prefix);
528
12.1k
529
12.1k
        free(network->bridge_name);
530
12.1k
        free(network->bond_name);
531
12.1k
        free(network->vrf_name);
532
12.1k
        hashmap_free_free_key(network->stacked_netdev_names);
533
12.1k
        netdev_unref(network->bridge);
534
12.1k
        netdev_unref(network->bond);
535
12.1k
        netdev_unref(network->vrf);
536
12.1k
        hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
537
12.1k
538
69.7k
        while ((route = network->static_routes))
539
57.6k
                route_free(route);
540
12.1k
541
22.2k
        while ((address = network->static_addresses))
542
10.1k
                address_free(address);
543
12.1k
544
18.8k
        while ((fdb_entry = network->static_fdb_entries))
545
6.75k
                fdb_entry_free(fdb_entry);
546
12.1k
547
13.4k
        while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
548
1.30k
                ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
549
12.1k
550
12.6k
        while ((neighbor = network->neighbors))
551
490
                neighbor_free(neighbor);
552
12.1k
553
14.5k
        while ((label = network->address_labels))
554
2.40k
                address_label_free(label);
555
12.1k
556
13.0k
        while ((prefix = network->static_prefixes))
557
915
                prefix_free(prefix);
558
12.1k
559
14.9k
        while ((rule = network->rules))
560
2.80k
                routing_policy_rule_free(rule);
561
12.1k
562
12.1k
        hashmap_free(network->addresses_by_section);
563
12.1k
        hashmap_free(network->routes_by_section);
564
12.1k
        hashmap_free(network->fdb_entries_by_section);
565
12.1k
        hashmap_free(network->neighbors_by_section);
566
12.1k
        hashmap_free(network->address_labels_by_section);
567
12.1k
        hashmap_free(network->prefixes_by_section);
568
12.1k
        hashmap_free(network->rules_by_section);
569
12.1k
570
12.1k
        if (network->manager) {
571
12.1k
                if (network->manager->networks && network->name)
572
9.80k
                        ordered_hashmap_remove(network->manager->networks, network->name);
573
12.1k
574
12.1k
                if (network->manager->duids_requesting_uuid)
575
0
                        set_remove(network->manager->duids_requesting_uuid, &network->duid);
576
12.1k
        }
577
12.1k
578
12.1k
        free(network->name);
579
12.1k
580
12.1k
        free(network->dhcp_server_timezone);
581
12.1k
        free(network->dhcp_server_dns);
582
12.1k
        free(network->dhcp_server_ntp);
583
12.1k
584
12.1k
        set_free_free(network->dnssec_negative_trust_anchors);
585
12.1k
586
12.1k
        return mfree(network);
587
12.1k
}
588
589
DEFINE_TRIVIAL_REF_UNREF_FUNC(Network, network, network_free);
590
591
0
int network_get_by_name(Manager *manager, const char *name, Network **ret) {
592
0
        Network *network;
593
0
594
0
        assert(manager);
595
0
        assert(name);
596
0
        assert(ret);
597
0
598
0
        network = ordered_hashmap_get(manager->networks, name);
599
0
        if (!network)
600
0
                return -ENOENT;
601
0
602
0
        *ret = network;
603
0
604
0
        return 0;
605
0
}
606
607
int network_get(Manager *manager, sd_device *device,
608
                const char *ifname, const struct ether_addr *address,
609
0
                Network **ret) {
610
0
        const char *path = NULL, *driver = NULL, *devtype = NULL;
611
0
        Network *network;
612
0
        Iterator i;
613
0
614
0
        assert(manager);
615
0
        assert(ret);
616
0
617
0
        if (device) {
618
0
                (void) sd_device_get_property_value(device, "ID_PATH", &path);
619
0
620
0
                (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
621
0
622
0
                (void) sd_device_get_devtype(device, &devtype);
623
0
        }
624
0
625
0
        ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
626
0
                if (net_match_config(network->match_mac, network->match_path,
627
0
                                     network->match_driver, network->match_type,
628
0
                                     network->match_name,
629
0
                                     address, path, driver, devtype, ifname)) {
630
0
                        if (network->match_name && device) {
631
0
                                const char *attr;
632
0
                                uint8_t name_assign_type = NET_NAME_UNKNOWN;
633
0
634
0
                                if (sd_device_get_sysattr_value(device, "name_assign_type", &attr) >= 0)
635
0
                                        (void) safe_atou8(attr, &name_assign_type);
636
0
637
0
                                if (name_assign_type == NET_NAME_ENUM)
638
0
                                        log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
639
0
                                                    ifname, network->filename);
640
0
                                else
641
0
                                        log_debug("%s: found matching network '%s'", ifname, network->filename);
642
0
                        } else
643
0
                                log_debug("%s: found matching network '%s'", ifname, network->filename);
644
0
645
0
                        *ret = network;
646
0
                        return 0;
647
0
                }
648
0
649
0
        *ret = NULL;
650
0
651
0
        return -ENOENT;
652
0
}
653
654
0
int network_apply(Network *network, Link *link) {
655
0
        assert(network);
656
0
        assert(link);
657
0
658
0
        link->network = network_ref(network);
659
0
660
0
        if (network->n_dns > 0 ||
661
0
            !strv_isempty(network->ntp) ||
662
0
            !ordered_set_isempty(network->search_domains) ||
663
0
            !ordered_set_isempty(network->route_domains))
664
0
                link_dirty(link);
665
0
666
0
        return 0;
667
0
}
668
669
0
bool network_has_static_ipv6_addresses(Network *network) {
670
0
        Address *address;
671
0
672
0
        assert(network);
673
0
674
0
        LIST_FOREACH(addresses, address, network->static_addresses) {
675
0
                if (address->family == AF_INET6)
676
0
                        return true;
677
0
        }
678
0
679
0
        return false;
680
0
}
681
682
int config_parse_stacked_netdev(const char *unit,
683
                const char *filename,
684
                unsigned line,
685
                const char *section,
686
                unsigned section_line,
687
                const char *lvalue,
688
                int ltype,
689
                const char *rvalue,
690
                void *data,
691
3.93k
                void *userdata) {
692
3.93k
        _cleanup_free_ char *name = NULL;
693
3.93k
        NetDevKind kind = ltype;
694
3.93k
        Hashmap **h = data;
695
3.93k
        int r;
696
3.93k
697
3.93k
        assert(filename);
698
3.93k
        assert(lvalue);
699
3.93k
        assert(rvalue);
700
3.93k
        assert(data);
701
3.93k
        assert(IN_SET(kind,
702
3.93k
                      NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
703
3.93k
                      NETDEV_KIND_IPVLAN, NETDEV_KIND_IPVTAP, NETDEV_KIND_VXLAN,
704
3.93k
                      NETDEV_KIND_L2TP, NETDEV_KIND_MACSEC, _NETDEV_KIND_TUNNEL));
705
3.93k
706
3.93k
        if (!ifname_valid(rvalue)) {
707
1.62k
                log_syntax(unit, LOG_ERR, filename, line, 0,
708
1.62k
                           "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
709
1.62k
                return 0;
710
1.62k
        }
711
2.31k
712
2.31k
        name = strdup(rvalue);
713
2.31k
        if (!name)
714
0
                return log_oom();
715
2.31k
716
2.31k
        r = hashmap_ensure_allocated(h, &string_hash_ops);
717
2.31k
        if (r < 0)
718
0
                return log_oom();
719
2.31k
720
2.31k
        r = hashmap_put(*h, name, INT_TO_PTR(kind));
721
2.31k
        if (r < 0)
722
2.31k
                log_syntax(unit, LOG_ERR, filename, line, r,
723
2.31k
                           "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
724
2.31k
        else if (r == 0)
725
2.11k
                log_syntax(unit, LOG_DEBUG, filename, line, r,
726
2.11k
                           "NetDev '%s' specified twice, ignoring.", name);
727
2.11k
        else
728
2.11k
                name = NULL;
729
2.31k
730
2.31k
        return 0;
731
2.31k
}
732
733
int config_parse_domains(
734
                const char *unit,
735
                const char *filename,
736
                unsigned line,
737
                const char *section,
738
                unsigned section_line,
739
                const char *lvalue,
740
                int ltype,
741
                const char *rvalue,
742
                void *data,
743
7.40k
                void *userdata) {
744
7.40k
745
7.40k
        const char *p;
746
7.40k
        Network *n = data;
747
7.40k
        int r;
748
7.40k
749
7.40k
        assert(n);
750
7.40k
        assert(lvalue);
751
7.40k
        assert(rvalue);
752
7.40k
753
7.40k
        if (isempty(rvalue)) {
754
3.53k
                n->search_domains = ordered_set_free_free(n->search_domains);
755
3.53k
                n->route_domains = ordered_set_free_free(n->route_domains);
756
3.53k
                return 0;
757
3.53k
        }
758
3.86k
759
3.86k
        p = rvalue;
760
67.1k
        for (;;) {
761
67.1k
                _cleanup_free_ char *w = NULL, *normalized = NULL;
762
67.1k
                const char *domain;
763
67.1k
                bool is_route;
764
67.1k
765
67.1k
                r = extract_first_word(&p, &w, NULL, 0);
766
67.1k
                if (r < 0) {
767
419
                        log_syntax(unit, LOG_ERR, filename, line, r,
768
419
                                   "Failed to extract search or route domain, ignoring: %s", rvalue);
769
419
                        break;
770
419
                }
771
66.7k
                if (r == 0)
772
3.45k
                        break;
773
63.3k
774
63.3k
                is_route = w[0] == '~';
775
63.3k
                domain = is_route ? w + 1 : w;
776
63.3k
777
63.3k
                if (dns_name_is_root(domain) || streq(domain, "*")) {
778
2.88k
                        /* If the root domain appears as is, or the special token "*" is found, we'll
779
2.88k
                         * consider this as routing domain, unconditionally. */
780
2.88k
                        is_route = true;
781
2.88k
                        domain = "."; /* make sure we don't allow empty strings, thus write the root
782
2.88k
                                       * domain as "." */
783
60.4k
                } else {
784
60.4k
                        r = dns_name_normalize(domain, 0, &normalized);
785
60.4k
                        if (r < 0) {
786
3.06k
                                log_syntax(unit, LOG_ERR, filename, line, r,
787
3.06k
                                           "'%s' is not a valid domain name, ignoring.", domain);
788
3.06k
                                continue;
789
3.06k
                        }
790
57.3k
791
57.3k
                        domain = normalized;
792
57.3k
793
57.3k
                        if (is_localhost(domain)) {
794
806
                                log_syntax(unit, LOG_ERR, filename, line, 0,
795
806
                                           "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
796
806
                                           domain);
797
806
                                continue;
798
806
                        }
799
59.4k
                }
800
59.4k
801
59.4k
                OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
802
59.4k
                r = ordered_set_ensure_allocated(set, &string_hash_ops);
803
59.4k
                if (r < 0)
804
0
                        return r;
805
59.4k
806
59.4k
                r = ordered_set_put_strdup(*set, domain);
807
59.4k
                if (r < 0)
808
0
                        return log_oom();
809
59.4k
        }
810
3.86k
811
3.86k
        return 0;
812
3.86k
}
813
814
int config_parse_ipv4ll(
815
                const char* unit,
816
                const char *filename,
817
                unsigned line,
818
                const char *section,
819
                unsigned section_line,
820
                const char *lvalue,
821
                int ltype,
822
                const char *rvalue,
823
                void *data,
824
612
                void *userdata) {
825
612
826
612
        AddressFamilyBoolean *link_local = data;
827
612
        int r;
828
612
829
612
        assert(filename);
830
612
        assert(lvalue);
831
612
        assert(rvalue);
832
612
        assert(data);
833
612
834
612
        /* Note that this is mostly like
835
612
         * config_parse_address_family_boolean(), except that it
836
612
         * applies only to IPv4 */
837
612
838
612
        r = parse_boolean(rvalue);
839
612
        if (r < 0) {
840
208
                log_syntax(unit, LOG_ERR, filename, line, r,
841
208
                           "Failed to parse %s=%s, ignoring assignment. "
842
208
                           "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
843
208
                           lvalue, rvalue, lvalue);
844
208
                return 0;
845
208
        }
846
404
847
404
        SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
848
404
849
404
        log_syntax(unit, LOG_WARNING, filename, line, 0,
850
404
                   "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
851
404
                   lvalue, rvalue, address_family_boolean_to_string(*link_local));
852
404
853
404
        return 0;
854
404
}
855
856
int config_parse_dhcp(
857
                const char* unit,
858
                const char *filename,
859
                unsigned line,
860
                const char *section,
861
                unsigned section_line,
862
                const char *lvalue,
863
                int ltype,
864
                const char *rvalue,
865
                void *data,
866
2.98k
                void *userdata) {
867
2.98k
868
2.98k
        AddressFamilyBoolean *dhcp = data, s;
869
2.98k
870
2.98k
        assert(filename);
871
2.98k
        assert(lvalue);
872
2.98k
        assert(rvalue);
873
2.98k
        assert(data);
874
2.98k
875
2.98k
        /* Note that this is mostly like
876
2.98k
         * config_parse_address_family_boolean(), except that it
877
2.98k
         * understands some old names for the enum values */
878
2.98k
879
2.98k
        s = address_family_boolean_from_string(rvalue);
880
2.98k
        if (s < 0) {
881
2.36k
882
2.36k
                /* Previously, we had a slightly different enum here,
883
2.36k
                 * support its values for compatibility. */
884
2.36k
885
2.36k
                if (streq(rvalue, "none"))
886
2.36k
                        s = ADDRESS_FAMILY_NO;
887
2.17k
                else if (streq(rvalue, "v4"))
888
2.17k
                        s = ADDRESS_FAMILY_IPV4;
889
1.97k
                else if (streq(rvalue, "v6"))
890
1.97k
                        s = ADDRESS_FAMILY_IPV6;
891
1.59k
                else if (streq(rvalue, "both"))
892
1.59k
                        s = ADDRESS_FAMILY_YES;
893
1.40k
                else {
894
1.40k
                        log_syntax(unit, LOG_ERR, filename, line, 0,
895
1.40k
                                   "Failed to parse DHCP option, ignoring: %s", rvalue);
896
1.40k
                        return 0;
897
1.40k
                }
898
962
899
962
                log_syntax(unit, LOG_WARNING, filename, line, 0,
900
962
                           "DHCP=%s is deprecated, please use DHCP=%s instead.",
901
962
                           rvalue, address_family_boolean_to_string(s));
902
962
        }
903
2.98k
904
2.98k
        *dhcp = s;
905
1.58k
        return 0;
906
2.98k
}
907
908
static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
909
        [DHCP_CLIENT_ID_MAC] = "mac",
910
        [DHCP_CLIENT_ID_DUID] = "duid",
911
        [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
912
};
913
914
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
915
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
916
                         "Failed to parse client identifier type");
917
918
int config_parse_ipv6token(
919
                const char* unit,
920
                const char *filename,
921
                unsigned line,
922
                const char *section,
923
                unsigned section_line,
924
                const char *lvalue,
925
                int ltype,
926
                const char *rvalue,
927
                void *data,
928
1.49k
                void *userdata) {
929
1.49k
930
1.49k
        union in_addr_union buffer;
931
1.49k
        struct in6_addr *token = data;
932
1.49k
        int r;
933
1.49k
934
1.49k
        assert(filename);
935
1.49k
        assert(lvalue);
936
1.49k
        assert(rvalue);
937
1.49k
        assert(token);
938
1.49k
939
1.49k
        r = in_addr_from_string(AF_INET6, rvalue, &buffer);
940
1.49k
        if (r < 0) {
941
290
                log_syntax(unit, LOG_ERR, filename, line, r,
942
290
                           "Failed to parse IPv6 token, ignoring: %s", rvalue);
943
290
                return 0;
944
290
        }
945
1.20k
946
1.20k
        if (in_addr_is_null(AF_INET6, &buffer)) {
947
198
                log_syntax(unit, LOG_ERR, filename, line, 0,
948
198
                           "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
949
198
                return 0;
950
198
        }
951
1.00k
952
1.00k
        if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
953
554
                log_syntax(unit, LOG_ERR, filename, line, 0,
954
554
                           "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
955
554
                return 0;
956
554
        }
957
453
958
453
        *token = buffer.in6;
959
453
960
453
        return 0;
961
453
}
962
963
static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = {
964
        [IPV6_PRIVACY_EXTENSIONS_NO] = "no",
965
        [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public",
966
        [IPV6_PRIVACY_EXTENSIONS_YES] = "yes",
967
};
968
969
DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions);
970
971
int config_parse_ipv6_privacy_extensions(
972
                const char* unit,
973
                const char *filename,
974
                unsigned line,
975
                const char *section,
976
                unsigned section_line,
977
                const char *lvalue,
978
                int ltype,
979
                const char *rvalue,
980
                void *data,
981
1.16k
                void *userdata) {
982
1.16k
983
1.16k
        IPv6PrivacyExtensions *ipv6_privacy_extensions = data;
984
1.16k
        int k;
985
1.16k
986
1.16k
        assert(filename);
987
1.16k
        assert(lvalue);
988
1.16k
        assert(rvalue);
989
1.16k
        assert(ipv6_privacy_extensions);
990
1.16k
991
1.16k
        /* Our enum shall be a superset of booleans, hence first try
992
1.16k
         * to parse as boolean, and then as enum */
993
1.16k
994
1.16k
        k = parse_boolean(rvalue);
995
1.16k
        if (k > 0)
996
194
                *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES;
997
967
        else if (k == 0)
998
194
                *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
999
773
        else {
1000
773
                IPv6PrivacyExtensions s;
1001
773
1002
773
                s = ipv6_privacy_extensions_from_string(rvalue);
1003
773
                if (s < 0) {
1004
466
1005
466
                        if (streq(rvalue, "kernel"))
1006
466
                                s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
1007
272
                        else {
1008
272
                                log_syntax(unit, LOG_ERR, filename, line, 0,
1009
272
                                           "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
1010
272
                                return 0;
1011
272
                        }
1012
501
                }
1013
501
1014
501
                *ipv6_privacy_extensions = s;
1015
501
        }
1016
1.16k
1017
1.16k
        return 0;
1018
1.16k
}
1019
1020
int config_parse_hostname(
1021
                const char *unit,
1022
                const char *filename,
1023
                unsigned line,
1024
                const char *section,
1025
                unsigned section_line,
1026
                const char *lvalue,
1027
                int ltype,
1028
                const char *rvalue,
1029
                void *data,
1030
3.03k
                void *userdata) {
1031
3.03k
1032
3.03k
        _cleanup_free_ char *hn = NULL;
1033
3.03k
        char **hostname = data;
1034
3.03k
        int r;
1035
3.03k
1036
3.03k
        assert(filename);
1037
3.03k
        assert(lvalue);
1038
3.03k
        assert(rvalue);
1039
3.03k
1040
3.03k
        r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata);
1041
3.03k
        if (r < 0)
1042
0
                return r;
1043
3.03k
1044
3.03k
        if (!hostname_is_valid(hn, false)) {
1045
2.47k
                log_syntax(unit, LOG_ERR, filename, line, 0,
1046
2.47k
                           "Hostname is not valid, ignoring assignment: %s", rvalue);
1047
2.47k
                return 0;
1048
2.47k
        }
1049
561
1050
561
        r = dns_name_is_valid(hn);
1051
561
        if (r < 0) {
1052
0
                log_syntax(unit, LOG_ERR, filename, line, r,
1053
0
                           "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
1054
0
                return 0;
1055
0
        }
1056
561
        if (r == 0) {
1057
194
                log_syntax(unit, LOG_ERR, filename, line, 0,
1058
194
                           "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
1059
194
                return 0;
1060
194
        }
1061
367
1062
367
        return free_and_replace(*hostname, hn);
1063
367
}
1064
1065
int config_parse_timezone(
1066
                const char *unit,
1067
                const char *filename,
1068
                unsigned line,
1069
                const char *section,
1070
                unsigned section_line,
1071
                const char *lvalue,
1072
                int ltype,
1073
                const char *rvalue,
1074
                void *data,
1075
5.00k
                void *userdata) {
1076
5.00k
1077
5.00k
        _cleanup_free_ char *tz = NULL;
1078
5.00k
        char **datap = data;
1079
5.00k
        int r;
1080
5.00k
1081
5.00k
        assert(filename);
1082
5.00k
        assert(lvalue);
1083
5.00k
        assert(rvalue);
1084
5.00k
1085
5.00k
        r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
1086
5.00k
        if (r < 0)
1087
0
                return r;
1088
5.00k
1089
5.00k
        if (!timezone_is_valid(tz, LOG_ERR)) {
1090
5.00k
                log_syntax(unit, LOG_ERR, filename, line, 0,
1091
5.00k
                           "Timezone is not valid, ignoring assignment: %s", rvalue);
1092
5.00k
                return 0;
1093
5.00k
        }
1094
0
1095
0
        return free_and_replace(*datap, tz);
1096
0
}
1097
1098
int config_parse_dhcp_server_dns(
1099
                const char *unit,
1100
                const char *filename,
1101
                unsigned line,
1102
                const char *section,
1103
                unsigned section_line,
1104
                const char *lvalue,
1105
                int ltype,
1106
                const char *rvalue,
1107
                void *data,
1108
551
                void *userdata) {
1109
551
1110
551
        Network *n = data;
1111
551
        const char *p = rvalue;
1112
551
        int r;
1113
551
1114
551
        assert(filename);
1115
551
        assert(lvalue);
1116
551
        assert(rvalue);
1117
551
1118
1.05k
        for (;;) {
1119
1.05k
                _cleanup_free_ char *w = NULL;
1120
1.05k
                union in_addr_union a;
1121
1.05k
                struct in_addr *m;
1122
1.05k
1123
1.05k
                r = extract_first_word(&p, &w, NULL, 0);
1124
1.05k
                if (r == -ENOMEM)
1125
1.05k
                        return log_oom();
1126
1.05k
                if (r < 0) {
1127
194
                        log_syntax(unit, LOG_ERR, filename, line, r,
1128
194
                                   "Failed to extract word, ignoring: %s", rvalue);
1129
194
                        return 0;
1130
194
                }
1131
862
                if (r == 0)
1132
357
                        break;
1133
505
1134
505
                r = in_addr_from_string(AF_INET, w, &a);
1135
505
                if (r < 0) {
1136
311
                        log_syntax(unit, LOG_ERR, filename, line, r,
1137
311
                                   "Failed to parse DNS server address '%s', ignoring assignment: %m", w);
1138
311
                        continue;
1139
311
                }
1140
194
1141
194
                m = reallocarray(n->dhcp_server_dns, n->n_dhcp_server_dns + 1, sizeof(struct in_addr));
1142
194
                if (!m)
1143
0
                        return log_oom();
1144
194
1145
194
                m[n->n_dhcp_server_dns++] = a.in;
1146
194
                n->dhcp_server_dns = m;
1147
194
        }
1148
551
1149
551
        return 0;
1150
551
}
1151
1152
int config_parse_radv_dns(
1153
                const char *unit,
1154
                const char *filename,
1155
                unsigned line,
1156
                const char *section,
1157
                unsigned section_line,
1158
                const char *lvalue,
1159
                int ltype,
1160
                const char *rvalue,
1161
                void *data,
1162
5.30k
                void *userdata) {
1163
5.30k
1164
5.30k
        Network *n = data;
1165
5.30k
        const char *p = rvalue;
1166
5.30k
        int r;
1167
5.30k
1168
5.30k
        assert(filename);
1169
5.30k
        assert(lvalue);
1170
5.30k
        assert(rvalue);
1171
5.30k
1172
12.1k
        for (;;) {
1173
12.1k
                _cleanup_free_ char *w = NULL;
1174
12.1k
                union in_addr_union a;
1175
12.1k
1176
12.1k
                r = extract_first_word(&p, &w, NULL, 0);
1177
12.1k
                if (r == -ENOMEM)
1178
12.1k
                        return log_oom();
1179
12.1k
                if (r < 0) {
1180
194
                        log_syntax(unit, LOG_ERR, filename, line, r,
1181
194
                                   "Failed to extract word, ignoring: %s", rvalue);
1182
194
                        return 0;
1183
194
                }
1184
11.9k
                if (r == 0)
1185
5.11k
                        break;
1186
6.81k
1187
6.81k
                if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
1188
4.89k
                        struct in6_addr *m;
1189
4.89k
1190
4.89k
                        m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
1191
4.89k
                        if (!m)
1192
0
                                return log_oom();
1193
4.89k
1194
4.89k
                        m[n->n_router_dns++] = a.in6;
1195
4.89k
                        n->router_dns = m;
1196
4.89k
1197
4.89k
                } else
1198
6.81k
                        log_syntax(unit, LOG_ERR, filename, line, 0,
1199
6.81k
                                   "Failed to parse DNS server address, ignoring: %s", w);
1200
6.81k
        }
1201
5.30k
1202
5.30k
        return 0;
1203
5.30k
}
1204
1205
int config_parse_radv_search_domains(
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
415
                void *userdata) {
1216
415
1217
415
        Network *n = data;
1218
415
        const char *p = rvalue;
1219
415
        int r;
1220
415
1221
415
        assert(filename);
1222
415
        assert(lvalue);
1223
415
        assert(rvalue);
1224
415
1225
501
        for (;;) {
1226
501
                _cleanup_free_ char *w = NULL, *idna = NULL;
1227
501
1228
501
                r = extract_first_word(&p, &w, NULL, 0);
1229
501
                if (r == -ENOMEM)
1230
501
                        return log_oom();
1231
501
                if (r < 0) {
1232
194
                        log_syntax(unit, LOG_ERR, filename, line, r,
1233
194
                                   "Failed to extract word, ignoring: %s", rvalue);
1234
194
                        return 0;
1235
194
                }
1236
307
                if (r == 0)
1237
219
                        break;
1238
88
1239
88
                r = dns_name_apply_idna(w, &idna);
1240
88
                if (r < 0) {
1241
0
                        log_syntax(unit, LOG_ERR, filename, line, r,
1242
0
                                   "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
1243
0
                        continue;
1244
88
                } else if (r == 0)
1245
88
                        /* transfer ownership to simplify subsequent operations */
1246
88
                        idna = TAKE_PTR(w);
1247
88
1248
88
                r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
1249
88
                if (r < 0)
1250
0
                        return r;
1251
88
1252
88
                r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
1253
88
                if (r < 0)
1254
2
                        return r;
1255
88
        }
1256
415
1257
415
        return 0;
1258
415
}
1259
1260
int config_parse_dhcp_server_ntp(
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
713
                void *userdata) {
1271
713
1272
713
        Network *n = data;
1273
713
        const char *p = rvalue;
1274
713
        int r;
1275
713
1276
713
        assert(filename);
1277
713
        assert(lvalue);
1278
713
        assert(rvalue);
1279
713
1280
1.24k
        for (;;) {
1281
1.24k
                _cleanup_free_ char *w = NULL;
1282
1.24k
                union in_addr_union a;
1283
1.24k
                struct in_addr *m;
1284
1.24k
1285
1.24k
                r = extract_first_word(&p, &w, NULL, 0);
1286
1.24k
                if (r == -ENOMEM)
1287
1.24k
                        return log_oom();
1288
1.24k
                if (r < 0) {
1289
194
                        log_syntax(unit, LOG_ERR, filename, line, r,
1290
194
                                   "Failed to extract word, ignoring: %s", rvalue);
1291
194
                        return 0;
1292
194
                }
1293
1.05k
                if (r == 0)
1294
519
                        return 0;
1295
534
1296
534
                r = in_addr_from_string(AF_INET, w, &a);
1297
534
                if (r < 0) {
1298
340
                        log_syntax(unit, LOG_ERR, filename, line, r,
1299
340
                                   "Failed to parse NTP server address '%s', ignoring: %m", w);
1300
340
                        continue;
1301
340
                }
1302
194
1303
194
                m = reallocarray(n->dhcp_server_ntp, n->n_dhcp_server_ntp + 1, sizeof(struct in_addr));
1304
194
                if (!m)
1305
0
                        return log_oom();
1306
194
1307
194
                m[n->n_dhcp_server_ntp++] = a.in;
1308
194
                n->dhcp_server_ntp = m;
1309
194
        }
1310
713
}
1311
1312
int config_parse_dns(
1313
                const char *unit,
1314
                const char *filename,
1315
                unsigned line,
1316
                const char *section,
1317
                unsigned section_line,
1318
                const char *lvalue,
1319
                int ltype,
1320
                const char *rvalue,
1321
                void *data,
1322
8.12k
                void *userdata) {
1323
8.12k
1324
8.12k
        Network *n = userdata;
1325
8.12k
        int r;
1326
8.12k
1327
8.12k
        assert(filename);
1328
8.12k
        assert(lvalue);
1329
8.12k
        assert(rvalue);
1330
8.12k
1331
26.1k
        for (;;) {
1332
26.1k
                _cleanup_free_ char *w = NULL;
1333
26.1k
                union in_addr_union a;
1334
26.1k
                struct in_addr_data *m;
1335
26.1k
                int family;
1336
26.1k
1337
26.1k
                r = extract_first_word(&rvalue, &w, NULL, 0);
1338
26.1k
                if (r == -ENOMEM)
1339
26.1k
                        return log_oom();
1340
26.1k
                if (r < 0) {
1341
194
                        log_syntax(unit, LOG_ERR, filename, line, r,
1342
194
                                   "Invalid syntax, ignoring: %s", rvalue);
1343
194
                        break;
1344
194
                }
1345
26.0k
                if (r == 0)
1346
7.92k
                        break;
1347
18.0k
1348
18.0k
                r = in_addr_from_string_auto(w, &family, &a);
1349
18.0k
                if (r < 0) {
1350
6.58k
                        log_syntax(unit, LOG_ERR, filename, line, r,
1351
6.58k
                                   "Failed to parse dns server address, ignoring: %s", w);
1352
6.58k
                        continue;
1353
6.58k
                }
1354
11.4k
1355
11.4k
                m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
1356
11.4k
                if (!m)
1357
0
                        return log_oom();
1358
11.4k
1359
11.4k
                m[n->n_dns++] = (struct in_addr_data) {
1360
11.4k
                        .family = family,
1361
11.4k
                        .address = a,
1362
11.4k
                };
1363
11.4k
1364
11.4k
                n->dns = m;
1365
11.4k
        }
1366
8.12k
1367
8.12k
        return 0;
1368
8.12k
}
1369
1370
int config_parse_dnssec_negative_trust_anchors(
1371
                const char *unit,
1372
                const char *filename,
1373
                unsigned line,
1374
                const char *section,
1375
                unsigned section_line,
1376
                const char *lvalue,
1377
                int ltype,
1378
                const char *rvalue,
1379
                void *data,
1380
2.43k
                void *userdata) {
1381
2.43k
1382
2.43k
        const char *p = rvalue;
1383
2.43k
        Network *n = data;
1384
2.43k
        int r;
1385
2.43k
1386
2.43k
        assert(n);
1387
2.43k
        assert(lvalue);
1388
2.43k
        assert(rvalue);
1389
2.43k
1390
2.43k
        if (isempty(rvalue)) {
1391
1.16k
                n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors);
1392
1.16k
                return 0;
1393
1.16k
        }
1394
1.26k
1395
41.7k
        for (;;) {
1396
41.7k
                _cleanup_free_ char *w = NULL;
1397
41.7k
1398
41.7k
                r = extract_first_word(&p, &w, NULL, 0);
1399
41.7k
                if (r < 0) {
1400
391
                        log_syntax(unit, LOG_ERR, filename, line, r,
1401
391
                                   "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
1402
391
                        break;
1403
391
                }
1404
41.3k
                if (r == 0)
1405
878
                        break;
1406
40.4k
1407
40.4k
                r = dns_name_is_valid(w);
1408
40.4k
                if (r <= 0) {
1409
2.26k
                        log_syntax(unit, LOG_ERR, filename, line, r,
1410
2.26k
                                   "%s is not a valid domain name, ignoring.", w);
1411
2.26k
                        continue;
1412
2.26k
                }
1413
38.2k
1414
38.2k
                r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
1415
38.2k
                if (r < 0)
1416
0
                        return log_oom();
1417
38.2k
1418
38.2k
                r = set_put(n->dnssec_negative_trust_anchors, w);
1419
38.2k
                if (r < 0)
1420
0
                        return log_oom();
1421
38.2k
                if (r > 0)
1422
13.4k
                        w = NULL;
1423
38.2k
        }
1424
1.26k
1425
1.26k
        return 0;
1426
1.26k
}
1427
1428
int config_parse_ntp(
1429
                const char *unit,
1430
                const char *filename,
1431
                unsigned line,
1432
                const char *section,
1433
                unsigned section_line,
1434
                const char *lvalue,
1435
                int ltype,
1436
                const char *rvalue,
1437
                void *data,
1438
4.85k
                void *userdata) {
1439
4.85k
1440
4.85k
        char ***l = data;
1441
4.85k
        int r;
1442
4.85k
1443
4.85k
        assert(l);
1444
4.85k
        assert(lvalue);
1445
4.85k
        assert(rvalue);
1446
4.85k
1447
4.85k
        if (isempty(rvalue)) {
1448
2.48k
                *l = strv_free(*l);
1449
2.48k
                return 0;
1450
2.48k
        }
1451
2.36k
1452
7.29k
        for (;;) {
1453
7.29k
                _cleanup_free_ char *w = NULL;
1454
7.29k
1455
7.29k
                r = extract_first_word(&rvalue, &w, NULL, 0);
1456
7.29k
                if (r == -ENOMEM)
1457
7.29k
                        return log_oom();
1458
7.29k
                if (r < 0) {
1459
211
                        log_syntax(unit, LOG_ERR, filename, line, r,
1460
211
                                   "Failed to extract NTP server name, ignoring: %s", rvalue);
1461
211
                        break;
1462
211
                }
1463
7.08k
                if (r == 0)
1464
1.88k
                        break;
1465
5.19k
1466
5.19k
                r = dns_name_is_valid_or_address(w);
1467
5.19k
                if (r <= 0) {
1468
1.25k
                        log_syntax(unit, LOG_ERR, filename, line, r,
1469
1.25k
                                   "%s is not a valid domain name or IP address, ignoring.", w);
1470
1.25k
                        continue;
1471
1.25k
                }
1472
3.94k
1473
3.94k
                if (strv_length(*l) > MAX_NTP_SERVERS) {
1474
272
                        log_syntax(unit, LOG_WARNING, filename, line, 0,
1475
272
                                   "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
1476
272
                                   MAX_NTP_SERVERS, w);
1477
272
                        break;
1478
272
                }
1479
3.67k
1480
3.67k
                r = strv_consume(l, TAKE_PTR(w));
1481
3.67k
                if (r < 0)
1482
0
                        return log_oom();
1483
3.67k
        }
1484
2.36k
1485
2.36k
        return 0;
1486
2.36k
}
1487
1488
int config_parse_dhcp_user_class(
1489
                const char *unit,
1490
                const char *filename,
1491
                unsigned line,
1492
                const char *section,
1493
                unsigned section_line,
1494
                const char *lvalue,
1495
                int ltype,
1496
                const char *rvalue,
1497
                void *data,
1498
694
                void *userdata) {
1499
694
1500
694
        char ***l = data;
1501
694
        int r;
1502
694
1503
694
        assert(l);
1504
694
        assert(lvalue);
1505
694
        assert(rvalue);
1506
694
1507
694
        if (isempty(rvalue)) {
1508
196
                *l = strv_free(*l);
1509
196
                return 0;
1510
196
        }
1511
498
1512
1.33k
        for (;;) {
1513
1.33k
                _cleanup_free_ char *w = NULL;
1514
1.33k
1515
1.33k
                r = extract_first_word(&rvalue, &w, NULL, 0);
1516
1.33k
                if (r == -ENOMEM)
1517
1.33k
                        return log_oom();
1518
1.33k
                if (r < 0) {
1519
194
                        log_syntax(unit, LOG_ERR, filename, line, r,
1520
194
                                   "Failed to split user classes option, ignoring: %s", rvalue);
1521
194
                        break;
1522
194
                }
1523
1.14k
                if (r == 0)
1524
304
                        break;
1525
840
1526
840
                if (strlen(w) > 255) {
1527
194
                        log_syntax(unit, LOG_ERR, filename, line, 0,
1528
194
                                   "%s length is not in the range 1-255, ignoring.", w);
1529
194
                        continue;
1530
194
                }
1531
646
1532
646
                r = strv_push(l, w);
1533
646
                if (r < 0)
1534
0
                        return log_oom();
1535
646
1536
646
                w = NULL;
1537
646
        }
1538
498
1539
498
        return 0;
1540
498
}
1541
1542
int config_parse_section_route_table(
1543
                const char *unit,
1544
                const char *filename,
1545
                unsigned line,
1546
                const char *section,
1547
                unsigned section_line,
1548
                const char *lvalue,
1549
                int ltype,
1550
                const char *rvalue,
1551
                void *data,
1552
584
                void *userdata) {
1553
584
1554
584
        Network *network = data;
1555
584
        uint32_t rt;
1556
584
        int r;
1557
584
1558
584
        assert(filename);
1559
584
        assert(lvalue);
1560
584
        assert(rvalue);
1561
584
        assert(data);
1562
584
1563
584
        r = safe_atou32(rvalue, &rt);
1564
584
        if (r < 0) {
1565
196
                log_syntax(unit, LOG_ERR, filename, line, r,
1566
196
                           "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
1567
196
                return 0;
1568
196
        }
1569
388
1570
388
        if (streq_ptr(section, "DHCP")) {
1571
194
                network->dhcp_route_table = rt;
1572
194
                network->dhcp_route_table_set = true;
1573
194
        } else { /* section is IPv6AcceptRA */
1574
194
                network->ipv6_accept_ra_route_table = rt;
1575
194
                network->ipv6_accept_ra_route_table_set = true;
1576
194
        }
1577
388
1578
388
        return 0;
1579
388
}
1580
1581
int config_parse_dhcp_max_attempts(
1582
                const char *unit,
1583
                const char *filename,
1584
                unsigned line,
1585
                const char *section,
1586
                unsigned section_line,
1587
                const char *lvalue,
1588
                int ltype,
1589
                const char *rvalue,
1590
                void *data,
1591
0
                void *userdata) {
1592
0
1593
0
        Network *network = data;
1594
0
        uint64_t a;
1595
0
        int r;
1596
0
1597
0
        assert(network);
1598
0
        assert(lvalue);
1599
0
        assert(rvalue);
1600
0
1601
0
        if (isempty(rvalue)) {
1602
0
                network->dhcp_max_attempts = 0;
1603
0
                return 0;
1604
0
        }
1605
0
1606
0
        if (streq(rvalue, "infinity")) {
1607
0
                network->dhcp_max_attempts = (uint64_t) -1;
1608
0
                return 0;
1609
0
        }
1610
0
1611
0
        r = safe_atou64(rvalue, &a);
1612
0
        if (r < 0) {
1613
0
                log_syntax(unit, LOG_ERR, filename, line, r,
1614
0
                           "Failed to parse DHCP maximum attempts, ignoring: %s", rvalue);
1615
0
                return 0;
1616
0
        }
1617
0
1618
0
        if (a == 0) {
1619
0
                log_syntax(unit, LOG_ERR, filename, line, 0,
1620
0
                           "%s= must be positive integer or 'infinity', ignoring: %s", lvalue, rvalue);
1621
0
                return 0;
1622
0
        }
1623
0
1624
0
        network->dhcp_max_attempts = a;
1625
0
1626
0
        return 0;
1627
0
}
1628
1629
int config_parse_dhcp_black_listed_ip_address(
1630
                const char *unit,
1631
                const char *filename,
1632
                unsigned line,
1633
                const char *section,
1634
                unsigned section_line,
1635
                const char *lvalue,
1636
                int ltype,
1637
                const char *rvalue,
1638
                void *data,
1639
0
                void *userdata) {
1640
0
1641
0
        Network *network = data;
1642
0
        const char *p;
1643
0
        int r;
1644
0
1645
0
        assert(filename);
1646
0
        assert(lvalue);
1647
0
        assert(rvalue);
1648
0
        assert(data);
1649
0
1650
0
        if (isempty(rvalue)) {
1651
0
                network->dhcp_black_listed_ip = set_free(network->dhcp_black_listed_ip);
1652
0
                return 0;
1653
0
        }
1654
0
1655
0
        for (p = rvalue;;) {
1656
0
                _cleanup_free_ char *n = NULL;
1657
0
                union in_addr_union ip;
1658
0
1659
0
                r = extract_first_word(&p, &n, NULL, 0);
1660
0
                if (r < 0) {
1661
0
                        log_syntax(unit, LOG_ERR, filename, line, r,
1662
0
                                   "Failed to parse DHCP black listed ip address, ignoring assignment: %s",
1663
0
                                   rvalue);
1664
0
                        return 0;
1665
0
                }
1666
0
                if (r == 0)
1667
0
                        return 0;
1668
0
1669
0
                r = in_addr_from_string(AF_INET, n, &ip);
1670
0
                if (r < 0) {
1671
0
                        log_syntax(unit, LOG_ERR, filename, line, r,
1672
0
                                   "DHCP black listed ip address is invalid, ignoring assignment: %s", n);
1673
0
                        continue;
1674
0
                }
1675
0
1676
0
                r = set_ensure_allocated(&network->dhcp_black_listed_ip, NULL);
1677
0
                if (r < 0)
1678
0
                        return log_oom();
1679
0
1680
0
                r = set_put(network->dhcp_black_listed_ip, UINT32_TO_PTR(ip.in.s_addr));
1681
0
                if (r < 0)
1682
0
                        log_syntax(unit, LOG_ERR, filename, line, r,
1683
0
                                   "Failed to store DHCP black listed ip address '%s', ignoring assignment: %m", n);
1684
0
        }
1685
0
1686
0
        return 0;
1687
0
}
1688
1689
DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains,
1690
                         "Failed to parse DHCP use domains setting");
1691
1692
static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
1693
        [DHCP_USE_DOMAINS_NO] = "no",
1694
        [DHCP_USE_DOMAINS_ROUTE] = "route",
1695
        [DHCP_USE_DOMAINS_YES] = "yes",
1696
};
1697
1698
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
1699
1700
int config_parse_iaid(const char *unit,
1701
                      const char *filename,
1702
                      unsigned line,
1703
                      const char *section,
1704
                      unsigned section_line,
1705
                      const char *lvalue,
1706
                      int ltype,
1707
                      const char *rvalue,
1708
                      void *data,
1709
429
                      void *userdata) {
1710
429
        Network *network = data;
1711
429
        uint32_t iaid;
1712
429
        int r;
1713
429
1714
429
        assert(filename);
1715
429
        assert(lvalue);
1716
429
        assert(rvalue);
1717
429
        assert(network);
1718
429
1719
429
        r = safe_atou32(rvalue, &iaid);
1720
429
        if (r < 0) {
1721
233
                log_syntax(unit, LOG_ERR, filename, line, r,
1722
233
                           "Unable to read IAID, ignoring assignment: %s", rvalue);
1723
233
                return 0;
1724
233
        }
1725
196
1726
196
        network->iaid = iaid;
1727
196
        network->iaid_set = true;
1728
196
1729
196
        return 0;
1730
196
}
1731
1732
int config_parse_required_for_online(
1733
                const char *unit,
1734
                const char *filename,
1735
                unsigned line,
1736
                const char *section,
1737
                unsigned section_line,
1738
                const char *lvalue,
1739
                int ltype,
1740
                const char *rvalue,
1741
                void *data,
1742
960
                void *userdata) {
1743
960
1744
960
        Network *network = data;
1745
960
        LinkOperationalState s;
1746
960
        bool required = true;
1747
960
        int r;
1748
960
1749
960
        if (isempty(rvalue)) {
1750
194
                network->required_for_online = true;
1751
194
                network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
1752
194
                return 0;
1753
194
        }
1754
766
1755
766
        s = link_operstate_from_string(rvalue);
1756
766
        if (s < 0) {
1757
571
                r = parse_boolean(rvalue);
1758
571
                if (r < 0) {
1759
303
                        log_syntax(unit, LOG_ERR, filename, line, r,
1760
303
                                   "Failed to parse %s= setting, ignoring assignment: %s",
1761
303
                                   lvalue, rvalue);
1762
303
                        return 0;
1763
303
                }
1764
268
1765
268
                required = r;
1766
268
                s = LINK_OPERSTATE_DEGRADED;
1767
268
        }
1768
766
1769
766
        network->required_for_online = required;
1770
463
        network->required_operstate_for_online = s;
1771
463
1772
463
        return 0;
1773
766
}
1774
1775
DEFINE_CONFIG_PARSE_ENUM(config_parse_keep_configuration, keep_configuration, KeepConfiguration,
1776
                         "Failed to parse KeepConfiguration= setting");
1777
1778
static const char* const keep_configuration_table[_KEEP_CONFIGURATION_MAX] = {
1779
        [KEEP_CONFIGURATION_NO]           = "no",
1780
        [KEEP_CONFIGURATION_DHCP_ON_STOP] = "dhcp-on-stop",
1781
        [KEEP_CONFIGURATION_DHCP]         = "dhcp",
1782
        [KEEP_CONFIGURATION_STATIC]       = "static",
1783
        [KEEP_CONFIGURATION_YES]          = "yes",
1784
};
1785
1786
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(keep_configuration, KeepConfiguration, KEEP_CONFIGURATION_YES);