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 NetworkConfigSection
*c
, struct siphash
*state
) {
25 siphash24_compress(c
->filename
, strlen(c
->filename
), state
);
26 siphash24_compress(&c
->line
, sizeof(c
->line
), state
);
29 static int network_config_compare_func(const NetworkConfigSection
*x
, const NetworkConfigSection
*y
) {
32 r
= strcmp(x
->filename
, y
->filename
);
36 return CMP(x
->line
, y
->line
);
39 DEFINE_HASH_OPS(network_config_hash_ops
, NetworkConfigSection
, network_config_hash_func
, network_config_compare_func
);
41 int network_config_section_new(const char *filename
, unsigned line
, NetworkConfigSection
**s
) {
42 NetworkConfigSection
*cs
;
44 cs
= malloc0(offsetof(NetworkConfigSection
, filename
) + strlen(filename
) + 1);
48 strcpy(cs
->filename
, filename
);
56 void network_config_section_free(NetworkConfigSection
*cs
) {
60 /* Set defaults following RFC7844 */
61 void network_apply_anonymize_if_set(Network
*network
) {
62 if (!network
->dhcp_anonymize
)
65 SHOULD NOT send the Host Name option */
66 network
->dhcp_send_hostname
= false;
67 /* RFC7844 section 3.:
68 MAY contain the Client Identifier option
70 clients MUST use client identifiers based solely
71 on the link-layer address */
72 /* NOTE: Using MAC, as it does not reveal extra information,
73 * and some servers might not answer if this option is not sent */
74 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_MAC
;
76 SHOULD NOT use the Vendor Class Identifier option */
77 network
->dhcp_vendor_class_identifier
= mfree(network
->dhcp_vendor_class_identifier
);
78 /* RFC7844 section 3.6.:
79 The client intending to protect its privacy SHOULD only request a
80 minimal number of options in the PRL and SHOULD also randomly shuffle
81 the ordering of option codes in the PRL. If this random ordering
82 cannot be implemented, the client MAY order the option codes in the
83 PRL by option code number (lowest to highest).
85 /* NOTE: dhcp_use_mtu is false by default,
86 * though it was not initiallized to any value in network_load_one.
87 * Maybe there should be another var called *send*?
88 * (to use the MTU sent by the server but to do not send
89 * the option in the PRL). */
90 network
->dhcp_use_mtu
= false;
91 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
92 * but this is needed to use them. */
93 network
->dhcp_use_routes
= true;
94 /* RFC7844 section 3.6.
95 * same comments as previous option */
96 network
->dhcp_use_timezone
= false;
99 int network_load_one(Manager
*manager
, const char *filename
) {
100 _cleanup_(network_freep
) Network
*network
= NULL
;
101 _cleanup_fclose_
FILE *file
= NULL
;
103 const char *dropin_dirname
;
111 file
= fopen(filename
, "re");
119 if (null_or_empty_fd(fileno(file
))) {
120 log_debug("Skipping empty file: %s", filename
);
124 network
= new(Network
, 1);
128 *network
= (Network
) {
131 .required_for_online
= true,
132 .dhcp
= ADDRESS_FAMILY_NO
,
133 .dhcp_use_ntp
= true,
134 .dhcp_use_dns
= true,
135 .dhcp_use_hostname
= true,
136 .dhcp_use_routes
= true,
137 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
138 .dhcp_send_hostname
= true,
139 /* To enable/disable RFC7844 Anonymity Profiles */
140 .dhcp_anonymize
= false,
141 .dhcp_route_metric
= DHCP_ROUTE_METRIC
,
142 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
143 .dhcp_client_identifier
= DHCP_CLIENT_ID_DUID
,
144 .dhcp_route_table
= RT_TABLE_MAIN
,
145 .dhcp_route_table_set
= false,
146 /* NOTE: from man: UseMTU=... Defaults to false*/
147 .dhcp_use_mtu
= false,
148 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
149 .dhcp_use_timezone
= false,
150 .rapid_commit
= true,
152 .dhcp_server_emit_dns
= true,
153 .dhcp_server_emit_ntp
= true,
154 .dhcp_server_emit_router
= true,
155 .dhcp_server_emit_timezone
= true,
157 .router_emit_dns
= true,
158 .router_emit_domains
= true,
163 .allow_port_to_be_root
= -1,
165 .priority
= LINK_BRIDGE_PORT_PRIORITY_INVALID
,
167 .lldp_mode
= LLDP_MODE_ROUTERS_ONLY
,
169 .llmnr
= RESOLVE_SUPPORT_YES
,
170 .mdns
= RESOLVE_SUPPORT_NO
,
171 .dnssec_mode
= _DNSSEC_MODE_INVALID
,
172 .dns_over_tls_mode
= _DNS_OVER_TLS_MODE_INVALID
,
174 .link_local
= ADDRESS_FAMILY_IPV6
,
176 .ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
,
177 .ipv6_accept_ra
= -1,
178 .ipv6_dad_transmits
= -1,
179 .ipv6_hop_limit
= -1,
180 .ipv6_proxy_ndp
= -1,
181 .duid
.type
= _DUID_TYPE_INVALID
,
186 .ipv6_accept_ra_use_dns
= true,
187 .ipv6_accept_ra_route_table
= RT_TABLE_MAIN
,
190 network
->filename
= strdup(filename
);
191 if (!network
->filename
)
194 network
->name
= strdup(basename(filename
));
198 d
= strrchr(network
->name
, '.');
204 dropin_dirname
= strjoina(network
->name
, ".network.d");
206 r
= config_parse_many(filename
, network_dirs
, dropin_dirname
,
212 "RoutingPolicyRule\0"
215 "DHCPv4\0" /* compat */
218 "IPv6NDPProxyAddress\0"
222 "IPv6PrefixDelegation\0"
225 config_item_perf_lookup
, network_network_gperf_lookup
,
226 CONFIG_PARSE_WARN
, network
);
230 network_apply_anonymize_if_set(network
);
232 /* IPMasquerade=yes implies IPForward=yes */
233 if (network
->ip_masquerade
)
234 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
236 if (network
->mtu
> 0 && network
->dhcp_use_mtu
) {
237 log_warning("MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set in %s. "
238 "Disabling UseMTU=.", filename
);
239 network
->dhcp_use_mtu
= false;
242 LIST_PREPEND(networks
, manager
->networks
, network
);
244 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
248 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
252 LIST_FOREACH(routes
, route
, network
->static_routes
) {
253 if (!route
->family
) {
254 log_warning("Route section without Gateway field configured in %s. "
255 "Ignoring", filename
);
260 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
261 if (!address
->family
) {
262 log_warning("Address section without Address field configured in %s. "
263 "Ignoring", filename
);
273 int network_load(Manager
*manager
) {
275 _cleanup_strv_free_
char **files
= NULL
;
281 while ((network
= manager
->networks
))
282 network_free(network
);
284 r
= conf_files_list_strv(&files
, ".network", NULL
, 0, network_dirs
);
286 return log_error_errno(r
, "Failed to enumerate network files: %m");
288 STRV_FOREACH_BACKWARDS(f
, files
) {
289 r
= network_load_one(manager
, *f
);
297 void network_free(Network
*network
) {
298 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
299 RoutingPolicyRule
*rule
;
309 free(network
->filename
);
311 set_free_free(network
->match_mac
);
312 strv_free(network
->match_path
);
313 strv_free(network
->match_driver
);
314 strv_free(network
->match_type
);
315 strv_free(network
->match_name
);
317 free(network
->description
);
318 free(network
->dhcp_vendor_class_identifier
);
319 strv_free(network
->dhcp_user_class
);
320 free(network
->dhcp_hostname
);
324 strv_free(network
->ntp
);
326 strv_free(network
->search_domains
);
327 strv_free(network
->route_domains
);
328 strv_free(network
->bind_carrier
);
330 strv_free(network
->router_search_domains
);
331 free(network
->router_dns
);
333 netdev_unref(network
->bridge
);
334 netdev_unref(network
->bond
);
335 netdev_unref(network
->vrf
);
337 hashmap_free_with_destructor(network
->stacked_netdevs
, netdev_unref
);
339 while ((route
= network
->static_routes
))
342 while ((address
= network
->static_addresses
))
343 address_free(address
);
345 while ((fdb_entry
= network
->static_fdb_entries
))
346 fdb_entry_free(fdb_entry
);
348 while ((ipv6_proxy_ndp_address
= network
->ipv6_proxy_ndp_addresses
))
349 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address
);
351 while ((label
= network
->address_labels
))
352 address_label_free(label
);
354 while ((prefix
= network
->static_prefixes
))
357 while ((rule
= network
->rules
))
358 routing_policy_rule_free(rule
);
360 hashmap_free(network
->addresses_by_section
);
361 hashmap_free(network
->routes_by_section
);
362 hashmap_free(network
->fdb_entries_by_section
);
363 hashmap_free(network
->address_labels_by_section
);
364 hashmap_free(network
->prefixes_by_section
);
365 hashmap_free(network
->rules_by_section
);
367 if (network
->manager
) {
368 if (network
->manager
->networks
)
369 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
371 if (network
->manager
->networks_by_name
&& network
->name
)
372 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
374 if (network
->manager
->duids_requesting_uuid
)
375 set_remove(network
->manager
->duids_requesting_uuid
, &network
->duid
);
380 condition_free_list(network
->match_host
);
381 condition_free_list(network
->match_virt
);
382 condition_free_list(network
->match_kernel_cmdline
);
383 condition_free_list(network
->match_kernel_version
);
384 condition_free_list(network
->match_arch
);
386 free(network
->dhcp_server_timezone
);
387 free(network
->dhcp_server_dns
);
388 free(network
->dhcp_server_ntp
);
390 set_free_free(network
->dnssec_negative_trust_anchors
);
395 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
402 network
= hashmap_get(manager
->networks_by_name
, name
);
411 int network_get(Manager
*manager
, sd_device
*device
,
412 const char *ifname
, const struct ether_addr
*address
,
414 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
422 (void) sd_device_get_property_value(device
, "ID_PATH", &path
);
424 if (sd_device_get_parent(device
, &parent
) >= 0)
425 (void) sd_device_get_driver(parent
, &parent_driver
);
427 (void) sd_device_get_property_value(device
, "ID_NET_DRIVER", &driver
);
429 (void) sd_device_get_devtype(device
, &devtype
);
432 LIST_FOREACH(networks
, network
, manager
->networks
) {
433 if (net_match_config(network
->match_mac
, network
->match_path
,
434 network
->match_driver
, network
->match_type
,
435 network
->match_name
, network
->match_host
,
436 network
->match_virt
, network
->match_kernel_cmdline
,
437 network
->match_kernel_version
, network
->match_arch
,
438 address
, path
, parent_driver
, driver
,
440 if (network
->match_name
&& device
) {
442 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
444 if (sd_device_get_sysattr_value(device
, "name_assign_type", &attr
) >= 0)
445 (void) safe_atou8(attr
, &name_assign_type
);
447 if (name_assign_type
== NET_NAME_ENUM
)
448 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
449 ifname
, network
->filename
);
451 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
453 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
465 int network_apply(Network
*network
, Link
*link
) {
471 link
->network
= network
;
473 if (network
->ipv4ll_route
) {
476 r
= route_new_static(network
, NULL
, 0, &route
);
480 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
486 route
->family
= AF_INET
;
487 route
->dst_prefixlen
= 16;
488 route
->scope
= RT_SCOPE_LINK
;
489 route
->priority
= IPV4LL_ROUTE_METRIC
;
490 route
->protocol
= RTPROT_STATIC
;
493 if (network
->n_dns
> 0 ||
494 !strv_isempty(network
->ntp
) ||
495 !strv_isempty(network
->search_domains
) ||
496 !strv_isempty(network
->route_domains
))
502 bool network_has_static_ipv6_addresses(Network
*network
) {
507 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
508 if (address
->family
== AF_INET6
)
515 int config_parse_netdev(const char *unit
,
516 const char *filename
,
519 unsigned section_line
,
525 Network
*network
= userdata
;
526 _cleanup_free_
char *kind_string
= NULL
;
537 kind_string
= strdup(lvalue
);
541 /* the keys are CamelCase versions of the kind */
542 for (p
= kind_string
; *p
; p
++)
545 kind
= netdev_kind_from_string(kind_string
);
546 if (kind
== _NETDEV_KIND_INVALID
) {
547 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
551 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
553 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
557 if (netdev
->kind
!= kind
) {
558 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
563 case NETDEV_KIND_BRIDGE
:
564 network
->bridge
= netdev_unref(network
->bridge
);
565 network
->bridge
= netdev
;
568 case NETDEV_KIND_BOND
:
569 network
->bond
= netdev_unref(network
->bond
);
570 network
->bond
= netdev
;
573 case NETDEV_KIND_VRF
:
574 network
->vrf
= netdev_unref(network
->vrf
);
575 network
->vrf
= netdev
;
578 case NETDEV_KIND_VLAN
:
579 case NETDEV_KIND_MACVLAN
:
580 case NETDEV_KIND_MACVTAP
:
581 case NETDEV_KIND_IPVLAN
:
582 case NETDEV_KIND_VXLAN
:
583 case NETDEV_KIND_VCAN
:
584 r
= hashmap_ensure_allocated(&network
->stacked_netdevs
, &string_hash_ops
);
588 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
590 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add NetDev '%s' to network: %m", rvalue
);
596 assert_not_reached("Cannot parse NetDev");
604 int config_parse_domains(
606 const char *filename
,
609 unsigned section_line
,
624 if (isempty(rvalue
)) {
625 n
->search_domains
= strv_free(n
->search_domains
);
626 n
->route_domains
= strv_free(n
->route_domains
);
632 _cleanup_free_
char *w
= NULL
, *normalized
= NULL
;
636 r
= extract_first_word(&p
, &w
, NULL
, 0);
638 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract search or route domain, ignoring: %s", rvalue
);
644 is_route
= w
[0] == '~';
645 domain
= is_route
? w
+ 1 : w
;
647 if (dns_name_is_root(domain
) || streq(domain
, "*")) {
648 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
649 * routing domain, unconditionally. */
651 domain
= "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
654 r
= dns_name_normalize(domain
, &normalized
);
656 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "'%s' is not a valid domain name, ignoring.", domain
);
662 if (is_localhost(domain
)) {
663 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain
);
669 r
= strv_extend(&n
->route_domains
, domain
);
674 r
= strv_extend(&n
->search_domains
, domain
);
680 strv_uniq(n
->route_domains
);
681 strv_uniq(n
->search_domains
);
686 int config_parse_tunnel(const char *unit
,
687 const char *filename
,
690 unsigned section_line
,
696 Network
*network
= userdata
;
705 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
707 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
711 if (!IN_SET(netdev
->kind
,
717 NETDEV_KIND_IP6GRETAP
,
720 NETDEV_KIND_IP6TNL
)) {
721 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
722 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
726 r
= hashmap_ensure_allocated(&network
->stacked_netdevs
, &string_hash_ops
);
730 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
732 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
741 int config_parse_ipv4ll(
743 const char *filename
,
746 unsigned section_line
,
753 AddressFamilyBoolean
*link_local
= data
;
760 /* Note that this is mostly like
761 * config_parse_address_family_boolean(), except that it
762 * applies only to IPv4 */
764 SET_FLAG(*link_local
, ADDRESS_FAMILY_IPV4
, parse_boolean(rvalue
));
769 int config_parse_dhcp(
771 const char *filename
,
774 unsigned section_line
,
781 AddressFamilyBoolean
*dhcp
= data
, s
;
788 /* Note that this is mostly like
789 * config_parse_address_family_boolean(), except that it
790 * understands some old names for the enum values */
792 s
= address_family_boolean_from_string(rvalue
);
795 /* Previously, we had a slightly different enum here,
796 * support its values for compatbility. */
798 if (streq(rvalue
, "none"))
799 s
= ADDRESS_FAMILY_NO
;
800 else if (streq(rvalue
, "v4"))
801 s
= ADDRESS_FAMILY_IPV4
;
802 else if (streq(rvalue
, "v6"))
803 s
= ADDRESS_FAMILY_IPV6
;
804 else if (streq(rvalue
, "both"))
805 s
= ADDRESS_FAMILY_YES
;
807 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
816 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
817 [DHCP_CLIENT_ID_MAC
] = "mac",
818 [DHCP_CLIENT_ID_DUID
] = "duid",
819 [DHCP_CLIENT_ID_DUID_ONLY
] = "duid-only",
822 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DHCPClientIdentifier
);
823 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DHCPClientIdentifier
, "Failed to parse client identifier type");
825 int config_parse_ipv6token(
827 const char *filename
,
830 unsigned section_line
,
837 union in_addr_union buffer
;
838 struct in6_addr
*token
= data
;
846 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
848 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
852 r
= in_addr_is_null(AF_INET6
, &buffer
);
854 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue
);
858 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
859 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue
);
868 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
869 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
870 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
871 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
874 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
876 int config_parse_ipv6_privacy_extensions(
878 const char *filename
,
881 unsigned section_line
,
888 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
894 assert(ipv6_privacy_extensions
);
896 /* Our enum shall be a superset of booleans, hence first try
897 * to parse as boolean, and then as enum */
899 k
= parse_boolean(rvalue
);
901 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
903 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
905 IPv6PrivacyExtensions s
;
907 s
= ipv6_privacy_extensions_from_string(rvalue
);
910 if (streq(rvalue
, "kernel"))
911 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
913 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
918 *ipv6_privacy_extensions
= s
;
924 int config_parse_hostname(
926 const char *filename
,
929 unsigned section_line
,
936 _cleanup_free_
char *hn
= NULL
;
937 char **hostname
= data
;
944 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
948 if (!hostname_is_valid(hn
, false)) {
949 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
953 r
= dns_name_is_valid(hn
);
955 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue
);
959 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue
);
963 return free_and_replace(*hostname
, hn
);
966 int config_parse_timezone(
968 const char *filename
,
971 unsigned section_line
,
978 _cleanup_free_
char *tz
= NULL
;
986 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
990 if (!timezone_is_valid(tz
, LOG_ERR
)) {
991 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
995 return free_and_replace(*datap
, tz
);
998 int config_parse_dhcp_server_dns(
1000 const char *filename
,
1002 const char *section
,
1003 unsigned section_line
,
1011 const char *p
= rvalue
;
1019 _cleanup_free_
char *w
= NULL
;
1020 struct in_addr a
, *m
;
1022 r
= extract_first_word(&p
, &w
, NULL
, 0);
1026 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1032 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
1033 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
1037 m
= reallocarray(n
->dhcp_server_dns
, n
->n_dhcp_server_dns
+ 1, sizeof(struct in_addr
));
1041 m
[n
->n_dhcp_server_dns
++] = a
;
1042 n
->dhcp_server_dns
= m
;
1048 int config_parse_radv_dns(
1050 const char *filename
,
1052 const char *section
,
1053 unsigned section_line
,
1061 const char *p
= rvalue
;
1069 _cleanup_free_
char *w
= NULL
;
1070 union in_addr_union a
;
1072 r
= extract_first_word(&p
, &w
, NULL
, 0);
1076 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1082 if (in_addr_from_string(AF_INET6
, w
, &a
) >= 0) {
1085 m
= reallocarray(n
->router_dns
, n
->n_router_dns
+ 1, sizeof(struct in6_addr
));
1089 m
[n
->n_router_dns
++] = a
.in6
;
1093 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
1100 int config_parse_radv_search_domains(
1102 const char *filename
,
1104 const char *section
,
1105 unsigned section_line
,
1113 const char *p
= rvalue
;
1121 _cleanup_free_
char *w
= NULL
, *idna
= NULL
;
1123 r
= extract_first_word(&p
, &w
, NULL
, 0);
1127 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1133 r
= dns_name_apply_idna(w
, &idna
);
1135 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to apply IDNA to domain name '%s', ignoring: %m", w
);
1139 r
= strv_push(&n
->router_search_domains
, idna
);
1143 r
= strv_push(&n
->router_search_domains
, w
);
1152 int config_parse_dhcp_server_ntp(
1154 const char *filename
,
1156 const char *section
,
1157 unsigned section_line
,
1165 const char *p
= rvalue
;
1173 _cleanup_free_
char *w
= NULL
;
1174 struct in_addr a
, *m
;
1176 r
= extract_first_word(&p
, &w
, NULL
, 0);
1180 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1186 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
1187 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
1191 m
= reallocarray(n
->dhcp_server_ntp
, n
->n_dhcp_server_ntp
+ 1, sizeof(struct in_addr
));
1195 m
[n
->n_dhcp_server_ntp
++] = a
;
1196 n
->dhcp_server_ntp
= m
;
1200 int config_parse_dns(
1202 const char *filename
,
1204 const char *section
,
1205 unsigned section_line
,
1212 Network
*n
= userdata
;
1220 _cleanup_free_
char *w
= NULL
;
1221 union in_addr_union a
;
1222 struct in_addr_data
*m
;
1225 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1229 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1235 r
= in_addr_from_string_auto(w
, &family
, &a
);
1237 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse dns server address, ignoring: %s", w
);
1241 m
= reallocarray(n
->dns
, n
->n_dns
+ 1, sizeof(struct in_addr_data
));
1245 m
[n
->n_dns
++] = (struct in_addr_data
) {
1256 int config_parse_dnssec_negative_trust_anchors(
1258 const char *filename
,
1260 const char *section
,
1261 unsigned section_line
,
1268 const char *p
= rvalue
;
1276 if (isempty(rvalue
)) {
1277 n
->dnssec_negative_trust_anchors
= set_free_free(n
->dnssec_negative_trust_anchors
);
1282 _cleanup_free_
char *w
= NULL
;
1284 r
= extract_first_word(&p
, &w
, NULL
, 0);
1286 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue
);
1292 r
= dns_name_is_valid(w
);
1294 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name, ignoring.", w
);
1298 r
= set_ensure_allocated(&n
->dnssec_negative_trust_anchors
, &dns_name_hash_ops
);
1302 r
= set_put(n
->dnssec_negative_trust_anchors
, w
);
1312 int config_parse_ntp(
1314 const char *filename
,
1316 const char *section
,
1317 unsigned section_line
,
1331 if (isempty(rvalue
)) {
1337 _cleanup_free_
char *w
= NULL
;
1339 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1343 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract NTP server name, ignoring: %s", rvalue
);
1349 r
= dns_name_is_valid_or_address(w
);
1351 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name or IP address, ignoring.", w
);
1355 r
= strv_push(l
, w
);
1365 int config_parse_dhcp_user_class(
1367 const char *filename
,
1369 const char *section
,
1370 unsigned section_line
,
1384 if (isempty(rvalue
)) {
1390 _cleanup_free_
char *w
= NULL
;
1392 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1396 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to split user classes option, ignoring: %s", rvalue
);
1402 if (strlen(w
) > 255) {
1403 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s length is not in the range 1-255, ignoring.", w
);
1407 r
= strv_push(l
, w
);
1417 int config_parse_dhcp_route_table(const char *unit
,
1418 const char *filename
,
1420 const char *section
,
1421 unsigned section_line
,
1427 Network
*network
= data
;
1436 r
= safe_atou32(rvalue
, &rt
);
1438 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1439 "Unable to read RouteTable, ignoring assignment: %s", rvalue
);
1443 network
->dhcp_route_table
= rt
;
1444 network
->dhcp_route_table_set
= true;
1449 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains
, dhcp_use_domains
, DHCPUseDomains
, "Failed to parse DHCP use domains setting");
1451 static const char* const dhcp_use_domains_table
[_DHCP_USE_DOMAINS_MAX
] = {
1452 [DHCP_USE_DOMAINS_NO
] = "no",
1453 [DHCP_USE_DOMAINS_ROUTE
] = "route",
1454 [DHCP_USE_DOMAINS_YES
] = "yes",
1457 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains
, DHCPUseDomains
, DHCP_USE_DOMAINS_YES
);
1459 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode
, lldp_mode
, LLDPMode
, "Failed to parse LLDP= setting.");
1461 static const char* const lldp_mode_table
[_LLDP_MODE_MAX
] = {
1462 [LLDP_MODE_NO
] = "no",
1463 [LLDP_MODE_YES
] = "yes",
1464 [LLDP_MODE_ROUTERS_ONLY
] = "routers-only",
1467 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode
, LLDPMode
, LLDP_MODE_YES
);