1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include "alloc-util.h"
7 #include "conf-files.h"
8 #include "conf-parser.h"
9 #include "dns-domain.h"
11 #include "hostname-util.h"
12 #include "in-addr-util.h"
13 #include "network-internal.h"
14 #include "networkd-manager.h"
15 #include "networkd-network.h"
16 #include "parse-util.h"
18 #include "stat-util.h"
19 #include "string-table.h"
20 #include "string-util.h"
24 static void network_config_hash_func(const void *p
, struct siphash
*state
) {
25 const NetworkConfigSection
*c
= p
;
27 siphash24_compress(c
->filename
, strlen(c
->filename
), state
);
28 siphash24_compress(&c
->line
, sizeof(c
->line
), state
);
31 static int network_config_compare_func(const void *a
, const void *b
) {
32 const NetworkConfigSection
*x
= a
, *y
= b
;
35 r
= strcmp(x
->filename
, y
->filename
);
39 return CMP(x
->line
, y
->line
);
42 const struct hash_ops network_config_hash_ops
= {
43 .hash
= network_config_hash_func
,
44 .compare
= network_config_compare_func
,
47 int network_config_section_new(const char *filename
, unsigned line
, NetworkConfigSection
**s
) {
48 NetworkConfigSection
*cs
;
50 cs
= malloc0(offsetof(NetworkConfigSection
, filename
) + strlen(filename
) + 1);
54 strcpy(cs
->filename
, filename
);
62 void network_config_section_free(NetworkConfigSection
*cs
) {
66 /* Set defaults following RFC7844 */
67 void network_apply_anonymize_if_set(Network
*network
) {
68 if (!network
->dhcp_anonymize
)
71 SHOULD NOT send the Host Name option */
72 network
->dhcp_send_hostname
= false;
73 /* RFC7844 section 3.:
74 MAY contain the Client Identifier option
76 clients MUST use client identifiers based solely
77 on the link-layer address */
78 /* NOTE: Using MAC, as it does not reveal extra information,
79 * and some servers might not answer if this option is not sent */
80 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_MAC
;
82 SHOULD NOT use the Vendor Class Identifier option */
83 network
->dhcp_vendor_class_identifier
= mfree(network
->dhcp_vendor_class_identifier
);
84 /* RFC7844 section 3.6.:
85 The client intending to protect its privacy SHOULD only request a
86 minimal number of options in the PRL and SHOULD also randomly shuffle
87 the ordering of option codes in the PRL. If this random ordering
88 cannot be implemented, the client MAY order the option codes in the
89 PRL by option code number (lowest to highest).
91 /* NOTE: dhcp_use_mtu is false by default,
92 * though it was not initiallized to any value in network_load_one.
93 * Maybe there should be another var called *send*?
94 * (to use the MTU sent by the server but to do not send
95 * the option in the PRL). */
96 network
->dhcp_use_mtu
= false;
97 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
98 * but this is needed to use them. */
99 network
->dhcp_use_routes
= true;
100 /* RFC7844 section 3.6.
101 * same comments as previous option */
102 network
->dhcp_use_timezone
= false;
105 int network_load_one(Manager
*manager
, const char *filename
) {
106 _cleanup_(network_freep
) Network
*network
= NULL
;
107 _cleanup_fclose_
FILE *file
= NULL
;
109 const char *dropin_dirname
;
117 file
= fopen(filename
, "re");
125 if (null_or_empty_fd(fileno(file
))) {
126 log_debug("Skipping empty file: %s", filename
);
130 network
= new(Network
, 1);
134 *network
= (Network
) {
137 .required_for_online
= true,
138 .dhcp
= ADDRESS_FAMILY_NO
,
139 .dhcp_use_ntp
= true,
140 .dhcp_use_dns
= true,
141 .dhcp_use_hostname
= true,
142 .dhcp_use_routes
= true,
143 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
144 .dhcp_send_hostname
= true,
145 /* To enable/disable RFC7844 Anonymity Profiles */
146 .dhcp_anonymize
= false,
147 .dhcp_route_metric
= DHCP_ROUTE_METRIC
,
148 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
149 .dhcp_client_identifier
= DHCP_CLIENT_ID_DUID
,
150 .dhcp_route_table
= RT_TABLE_MAIN
,
151 .dhcp_route_table_set
= false,
152 /* NOTE: from man: UseMTU=... Defaults to false*/
153 .dhcp_use_mtu
= false,
154 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
155 .dhcp_use_timezone
= false,
156 .rapid_commit
= true,
158 .dhcp_server_emit_dns
= true,
159 .dhcp_server_emit_ntp
= true,
160 .dhcp_server_emit_router
= true,
161 .dhcp_server_emit_timezone
= true,
163 .router_emit_dns
= true,
164 .router_emit_domains
= true,
169 .allow_port_to_be_root
= -1,
171 .priority
= LINK_BRIDGE_PORT_PRIORITY_INVALID
,
173 .lldp_mode
= LLDP_MODE_ROUTERS_ONLY
,
175 .llmnr
= RESOLVE_SUPPORT_YES
,
176 .mdns
= RESOLVE_SUPPORT_NO
,
177 .dnssec_mode
= _DNSSEC_MODE_INVALID
,
178 .dns_over_tls_mode
= _DNS_OVER_TLS_MODE_INVALID
,
180 .link_local
= ADDRESS_FAMILY_IPV6
,
182 .ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
,
183 .ipv6_accept_ra
= -1,
184 .ipv6_dad_transmits
= -1,
185 .ipv6_hop_limit
= -1,
186 .ipv6_proxy_ndp
= -1,
187 .duid
.type
= _DUID_TYPE_INVALID
,
192 .ipv6_accept_ra_use_dns
= true,
193 .ipv6_accept_ra_route_table
= RT_TABLE_MAIN
,
196 network
->filename
= strdup(filename
);
197 if (!network
->filename
)
200 network
->name
= strdup(basename(filename
));
204 d
= strrchr(network
->name
, '.');
210 dropin_dirname
= strjoina(network
->name
, ".network.d");
212 r
= config_parse_many(filename
, network_dirs
, dropin_dirname
,
218 "RoutingPolicyRule\0"
221 "DHCPv4\0" /* compat */
224 "IPv6NDPProxyAddress\0"
228 "IPv6PrefixDelegation\0"
231 config_item_perf_lookup
, network_network_gperf_lookup
,
232 CONFIG_PARSE_WARN
, network
);
236 network_apply_anonymize_if_set(network
);
238 /* IPMasquerade=yes implies IPForward=yes */
239 if (network
->ip_masquerade
)
240 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
242 if (network
->mtu
> 0 && network
->dhcp_use_mtu
) {
243 log_warning("MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set in %s. "
244 "Disabling UseMTU=.", filename
);
245 network
->dhcp_use_mtu
= false;
248 LIST_PREPEND(networks
, manager
->networks
, network
);
250 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
254 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
258 LIST_FOREACH(routes
, route
, network
->static_routes
) {
259 if (!route
->family
) {
260 log_warning("Route section without Gateway field configured in %s. "
261 "Ignoring", filename
);
266 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
267 if (!address
->family
) {
268 log_warning("Address section without Address field configured in %s. "
269 "Ignoring", filename
);
279 int network_load(Manager
*manager
) {
281 _cleanup_strv_free_
char **files
= NULL
;
287 while ((network
= manager
->networks
))
288 network_free(network
);
290 r
= conf_files_list_strv(&files
, ".network", NULL
, 0, network_dirs
);
292 return log_error_errno(r
, "Failed to enumerate network files: %m");
294 STRV_FOREACH_BACKWARDS(f
, files
) {
295 r
= network_load_one(manager
, *f
);
303 void network_free(Network
*network
) {
304 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
305 RoutingPolicyRule
*rule
;
315 free(network
->filename
);
317 set_free_free(network
->match_mac
);
318 strv_free(network
->match_path
);
319 strv_free(network
->match_driver
);
320 strv_free(network
->match_type
);
321 strv_free(network
->match_name
);
323 free(network
->description
);
324 free(network
->dhcp_vendor_class_identifier
);
325 strv_free(network
->dhcp_user_class
);
326 free(network
->dhcp_hostname
);
330 strv_free(network
->ntp
);
332 strv_free(network
->search_domains
);
333 strv_free(network
->route_domains
);
334 strv_free(network
->bind_carrier
);
336 strv_free(network
->router_search_domains
);
337 free(network
->router_dns
);
339 netdev_unref(network
->bridge
);
340 netdev_unref(network
->bond
);
341 netdev_unref(network
->vrf
);
343 hashmap_free_with_destructor(network
->stacked_netdevs
, netdev_unref
);
345 while ((route
= network
->static_routes
))
348 while ((address
= network
->static_addresses
))
349 address_free(address
);
351 while ((fdb_entry
= network
->static_fdb_entries
))
352 fdb_entry_free(fdb_entry
);
354 while ((ipv6_proxy_ndp_address
= network
->ipv6_proxy_ndp_addresses
))
355 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address
);
357 while ((label
= network
->address_labels
))
358 address_label_free(label
);
360 while ((prefix
= network
->static_prefixes
))
363 while ((rule
= network
->rules
))
364 routing_policy_rule_free(rule
);
366 hashmap_free(network
->addresses_by_section
);
367 hashmap_free(network
->routes_by_section
);
368 hashmap_free(network
->fdb_entries_by_section
);
369 hashmap_free(network
->address_labels_by_section
);
370 hashmap_free(network
->prefixes_by_section
);
371 hashmap_free(network
->rules_by_section
);
373 if (network
->manager
) {
374 if (network
->manager
->networks
)
375 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
377 if (network
->manager
->networks_by_name
&& network
->name
)
378 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
380 if (network
->manager
->duids_requesting_uuid
)
381 set_remove(network
->manager
->duids_requesting_uuid
, &network
->duid
);
386 condition_free_list(network
->match_host
);
387 condition_free_list(network
->match_virt
);
388 condition_free_list(network
->match_kernel_cmdline
);
389 condition_free_list(network
->match_kernel_version
);
390 condition_free_list(network
->match_arch
);
392 free(network
->dhcp_server_timezone
);
393 free(network
->dhcp_server_dns
);
394 free(network
->dhcp_server_ntp
);
396 set_free_free(network
->dnssec_negative_trust_anchors
);
401 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
408 network
= hashmap_get(manager
->networks_by_name
, name
);
417 int network_get(Manager
*manager
, sd_device
*device
,
418 const char *ifname
, const struct ether_addr
*address
,
420 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
428 (void) sd_device_get_property_value(device
, "ID_PATH", &path
);
430 if (sd_device_get_parent(device
, &parent
) >= 0)
431 (void) sd_device_get_driver(parent
, &parent_driver
);
433 (void) sd_device_get_property_value(device
, "ID_NET_DRIVER", &driver
);
435 (void) sd_device_get_devtype(device
, &devtype
);
438 LIST_FOREACH(networks
, network
, manager
->networks
) {
439 if (net_match_config(network
->match_mac
, network
->match_path
,
440 network
->match_driver
, network
->match_type
,
441 network
->match_name
, network
->match_host
,
442 network
->match_virt
, network
->match_kernel_cmdline
,
443 network
->match_kernel_version
, network
->match_arch
,
444 address
, path
, parent_driver
, driver
,
446 if (network
->match_name
&& device
) {
448 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
450 if (sd_device_get_sysattr_value(device
, "name_assign_type", &attr
) >= 0)
451 (void) safe_atou8(attr
, &name_assign_type
);
453 if (name_assign_type
== NET_NAME_ENUM
)
454 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
455 ifname
, network
->filename
);
457 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
459 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
471 int network_apply(Network
*network
, Link
*link
) {
477 link
->network
= network
;
479 if (network
->ipv4ll_route
) {
482 r
= route_new_static(network
, NULL
, 0, &route
);
486 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
492 route
->family
= AF_INET
;
493 route
->dst_prefixlen
= 16;
494 route
->scope
= RT_SCOPE_LINK
;
495 route
->priority
= IPV4LL_ROUTE_METRIC
;
496 route
->protocol
= RTPROT_STATIC
;
499 if (network
->n_dns
> 0 ||
500 !strv_isempty(network
->ntp
) ||
501 !strv_isempty(network
->search_domains
) ||
502 !strv_isempty(network
->route_domains
))
508 bool network_has_static_ipv6_addresses(Network
*network
) {
513 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
514 if (address
->family
== AF_INET6
)
521 int config_parse_netdev(const char *unit
,
522 const char *filename
,
525 unsigned section_line
,
531 Network
*network
= userdata
;
532 _cleanup_free_
char *kind_string
= NULL
;
543 kind_string
= strdup(lvalue
);
547 /* the keys are CamelCase versions of the kind */
548 for (p
= kind_string
; *p
; p
++)
551 kind
= netdev_kind_from_string(kind_string
);
552 if (kind
== _NETDEV_KIND_INVALID
) {
553 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
557 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
559 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
563 if (netdev
->kind
!= kind
) {
564 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
569 case NETDEV_KIND_BRIDGE
:
570 network
->bridge
= netdev_unref(network
->bridge
);
571 network
->bridge
= netdev
;
574 case NETDEV_KIND_BOND
:
575 network
->bond
= netdev_unref(network
->bond
);
576 network
->bond
= netdev
;
579 case NETDEV_KIND_VRF
:
580 network
->vrf
= netdev_unref(network
->vrf
);
581 network
->vrf
= netdev
;
584 case NETDEV_KIND_VLAN
:
585 case NETDEV_KIND_MACVLAN
:
586 case NETDEV_KIND_MACVTAP
:
587 case NETDEV_KIND_IPVLAN
:
588 case NETDEV_KIND_VXLAN
:
589 case NETDEV_KIND_VCAN
:
590 r
= hashmap_ensure_allocated(&network
->stacked_netdevs
, &string_hash_ops
);
594 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
596 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add NetDev '%s' to network: %m", rvalue
);
602 assert_not_reached("Cannot parse NetDev");
610 int config_parse_domains(
612 const char *filename
,
615 unsigned section_line
,
630 if (isempty(rvalue
)) {
631 n
->search_domains
= strv_free(n
->search_domains
);
632 n
->route_domains
= strv_free(n
->route_domains
);
638 _cleanup_free_
char *w
= NULL
, *normalized
= NULL
;
642 r
= extract_first_word(&p
, &w
, NULL
, 0);
644 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract search or route domain, ignoring: %s", rvalue
);
650 is_route
= w
[0] == '~';
651 domain
= is_route
? w
+ 1 : w
;
653 if (dns_name_is_root(domain
) || streq(domain
, "*")) {
654 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
655 * routing domain, unconditionally. */
657 domain
= "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
660 r
= dns_name_normalize(domain
, &normalized
);
662 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "'%s' is not a valid domain name, ignoring.", domain
);
668 if (is_localhost(domain
)) {
669 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain
);
675 r
= strv_extend(&n
->route_domains
, domain
);
680 r
= strv_extend(&n
->search_domains
, domain
);
686 strv_uniq(n
->route_domains
);
687 strv_uniq(n
->search_domains
);
692 int config_parse_tunnel(const char *unit
,
693 const char *filename
,
696 unsigned section_line
,
702 Network
*network
= userdata
;
711 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
713 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
717 if (!IN_SET(netdev
->kind
,
723 NETDEV_KIND_IP6GRETAP
,
726 NETDEV_KIND_IP6TNL
)) {
727 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
728 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
732 r
= hashmap_ensure_allocated(&network
->stacked_netdevs
, &string_hash_ops
);
736 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
738 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
747 int config_parse_ipv4ll(
749 const char *filename
,
752 unsigned section_line
,
759 AddressFamilyBoolean
*link_local
= data
;
766 /* Note that this is mostly like
767 * config_parse_address_family_boolean(), except that it
768 * applies only to IPv4 */
770 SET_FLAG(*link_local
, ADDRESS_FAMILY_IPV4
, parse_boolean(rvalue
));
775 int config_parse_dhcp(
777 const char *filename
,
780 unsigned section_line
,
787 AddressFamilyBoolean
*dhcp
= data
, s
;
794 /* Note that this is mostly like
795 * config_parse_address_family_boolean(), except that it
796 * understands some old names for the enum values */
798 s
= address_family_boolean_from_string(rvalue
);
801 /* Previously, we had a slightly different enum here,
802 * support its values for compatbility. */
804 if (streq(rvalue
, "none"))
805 s
= ADDRESS_FAMILY_NO
;
806 else if (streq(rvalue
, "v4"))
807 s
= ADDRESS_FAMILY_IPV4
;
808 else if (streq(rvalue
, "v6"))
809 s
= ADDRESS_FAMILY_IPV6
;
810 else if (streq(rvalue
, "both"))
811 s
= ADDRESS_FAMILY_YES
;
813 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
822 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
823 [DHCP_CLIENT_ID_MAC
] = "mac",
824 [DHCP_CLIENT_ID_DUID
] = "duid",
825 [DHCP_CLIENT_ID_DUID_ONLY
] = "duid-only",
828 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DHCPClientIdentifier
);
829 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DHCPClientIdentifier
, "Failed to parse client identifier type");
831 int config_parse_ipv6token(
833 const char *filename
,
836 unsigned section_line
,
843 union in_addr_union buffer
;
844 struct in6_addr
*token
= data
;
852 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
854 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
858 r
= in_addr_is_null(AF_INET6
, &buffer
);
860 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue
);
864 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
865 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue
);
874 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
875 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
876 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
877 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
880 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
882 int config_parse_ipv6_privacy_extensions(
884 const char *filename
,
887 unsigned section_line
,
894 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
900 assert(ipv6_privacy_extensions
);
902 /* Our enum shall be a superset of booleans, hence first try
903 * to parse as boolean, and then as enum */
905 k
= parse_boolean(rvalue
);
907 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
909 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
911 IPv6PrivacyExtensions s
;
913 s
= ipv6_privacy_extensions_from_string(rvalue
);
916 if (streq(rvalue
, "kernel"))
917 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
919 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
924 *ipv6_privacy_extensions
= s
;
930 int config_parse_hostname(
932 const char *filename
,
935 unsigned section_line
,
942 _cleanup_free_
char *hn
= NULL
;
943 char **hostname
= data
;
950 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
954 if (!hostname_is_valid(hn
, false)) {
955 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
959 r
= dns_name_is_valid(hn
);
961 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue
);
965 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue
);
969 return free_and_replace(*hostname
, hn
);
972 int config_parse_timezone(
974 const char *filename
,
977 unsigned section_line
,
984 _cleanup_free_
char *tz
= NULL
;
992 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
996 if (!timezone_is_valid(tz
, LOG_ERR
)) {
997 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
1001 return free_and_replace(*datap
, tz
);
1004 int config_parse_dhcp_server_dns(
1006 const char *filename
,
1008 const char *section
,
1009 unsigned section_line
,
1017 const char *p
= rvalue
;
1025 _cleanup_free_
char *w
= NULL
;
1026 struct in_addr a
, *m
;
1028 r
= extract_first_word(&p
, &w
, NULL
, 0);
1032 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1038 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
1039 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
1043 m
= reallocarray(n
->dhcp_server_dns
, n
->n_dhcp_server_dns
+ 1, sizeof(struct in_addr
));
1047 m
[n
->n_dhcp_server_dns
++] = a
;
1048 n
->dhcp_server_dns
= m
;
1054 int config_parse_radv_dns(
1056 const char *filename
,
1058 const char *section
,
1059 unsigned section_line
,
1067 const char *p
= rvalue
;
1075 _cleanup_free_
char *w
= NULL
;
1076 union in_addr_union a
;
1078 r
= extract_first_word(&p
, &w
, NULL
, 0);
1082 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1088 if (in_addr_from_string(AF_INET6
, w
, &a
) >= 0) {
1091 m
= reallocarray(n
->router_dns
, n
->n_router_dns
+ 1, sizeof(struct in6_addr
));
1095 m
[n
->n_router_dns
++] = a
.in6
;
1099 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
1106 int config_parse_radv_search_domains(
1108 const char *filename
,
1110 const char *section
,
1111 unsigned section_line
,
1119 const char *p
= rvalue
;
1127 _cleanup_free_
char *w
= NULL
, *idna
= NULL
;
1129 r
= extract_first_word(&p
, &w
, NULL
, 0);
1133 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1139 r
= dns_name_apply_idna(w
, &idna
);
1141 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to apply IDNA to domain name '%s', ignoring: %m", w
);
1145 r
= strv_push(&n
->router_search_domains
, idna
);
1149 r
= strv_push(&n
->router_search_domains
, w
);
1158 int config_parse_dhcp_server_ntp(
1160 const char *filename
,
1162 const char *section
,
1163 unsigned section_line
,
1171 const char *p
= rvalue
;
1179 _cleanup_free_
char *w
= NULL
;
1180 struct in_addr a
, *m
;
1182 r
= extract_first_word(&p
, &w
, NULL
, 0);
1186 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1192 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
1193 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
1197 m
= reallocarray(n
->dhcp_server_ntp
, n
->n_dhcp_server_ntp
+ 1, sizeof(struct in_addr
));
1201 m
[n
->n_dhcp_server_ntp
++] = a
;
1202 n
->dhcp_server_ntp
= m
;
1206 int config_parse_dns(
1208 const char *filename
,
1210 const char *section
,
1211 unsigned section_line
,
1218 Network
*n
= userdata
;
1226 _cleanup_free_
char *w
= NULL
;
1227 union in_addr_union a
;
1228 struct in_addr_data
*m
;
1231 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1235 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1241 r
= in_addr_from_string_auto(w
, &family
, &a
);
1243 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse dns server address, ignoring: %s", w
);
1247 m
= reallocarray(n
->dns
, n
->n_dns
+ 1, sizeof(struct in_addr_data
));
1251 m
[n
->n_dns
++] = (struct in_addr_data
) {
1262 int config_parse_dnssec_negative_trust_anchors(
1264 const char *filename
,
1266 const char *section
,
1267 unsigned section_line
,
1274 const char *p
= rvalue
;
1282 if (isempty(rvalue
)) {
1283 n
->dnssec_negative_trust_anchors
= set_free_free(n
->dnssec_negative_trust_anchors
);
1288 _cleanup_free_
char *w
= NULL
;
1290 r
= extract_first_word(&p
, &w
, NULL
, 0);
1292 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue
);
1298 r
= dns_name_is_valid(w
);
1300 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name, ignoring.", w
);
1304 r
= set_ensure_allocated(&n
->dnssec_negative_trust_anchors
, &dns_name_hash_ops
);
1308 r
= set_put(n
->dnssec_negative_trust_anchors
, w
);
1318 int config_parse_ntp(
1320 const char *filename
,
1322 const char *section
,
1323 unsigned section_line
,
1337 if (isempty(rvalue
)) {
1343 _cleanup_free_
char *w
= NULL
;
1345 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1349 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract NTP server name, ignoring: %s", rvalue
);
1355 r
= dns_name_is_valid_or_address(w
);
1357 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name or IP address, ignoring.", w
);
1361 r
= strv_push(l
, w
);
1371 int config_parse_dhcp_user_class(
1373 const char *filename
,
1375 const char *section
,
1376 unsigned section_line
,
1390 if (isempty(rvalue
)) {
1396 _cleanup_free_
char *w
= NULL
;
1398 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1402 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to split user classes option, ignoring: %s", rvalue
);
1408 if (strlen(w
) > 255) {
1409 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s length is not in the range 1-255, ignoring.", w
);
1413 r
= strv_push(l
, w
);
1423 int config_parse_dhcp_route_table(const char *unit
,
1424 const char *filename
,
1426 const char *section
,
1427 unsigned section_line
,
1433 Network
*network
= data
;
1442 r
= safe_atou32(rvalue
, &rt
);
1444 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1445 "Unable to read RouteTable, ignoring assignment: %s", rvalue
);
1449 network
->dhcp_route_table
= rt
;
1450 network
->dhcp_route_table_set
= true;
1455 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains
, dhcp_use_domains
, DHCPUseDomains
, "Failed to parse DHCP use domains setting");
1457 static const char* const dhcp_use_domains_table
[_DHCP_USE_DOMAINS_MAX
] = {
1458 [DHCP_USE_DOMAINS_NO
] = "no",
1459 [DHCP_USE_DOMAINS_ROUTE
] = "route",
1460 [DHCP_USE_DOMAINS_YES
] = "yes",
1463 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains
, DHCPUseDomains
, DHCP_USE_DOMAINS_YES
);
1465 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode
, lldp_mode
, LLDPMode
, "Failed to parse LLDP= setting.");
1467 static const char* const lldp_mode_table
[_LLDP_MODE_MAX
] = {
1468 [LLDP_MODE_NO
] = "no",
1469 [LLDP_MODE_YES
] = "yes",
1470 [LLDP_MODE_ROUTERS_ONLY
] = "routers-only",
1473 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode
, LLDPMode
, LLDP_MODE_YES
);