1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
27 #include "dns-domain.h"
29 #include "hostname-util.h"
30 #include "in-addr-util.h"
31 #include "network-internal.h"
32 #include "networkd-manager.h"
33 #include "networkd-network.h"
34 #include "parse-util.h"
36 #include "stat-util.h"
37 #include "string-table.h"
38 #include "string-util.h"
42 static void network_config_hash_func(const void *p
, struct siphash
*state
) {
43 const NetworkConfigSection
*c
= p
;
45 siphash24_compress(c
->filename
, strlen(c
->filename
), state
);
46 siphash24_compress(&c
->line
, sizeof(c
->line
), state
);
49 static int network_config_compare_func(const void *a
, const void *b
) {
50 const NetworkConfigSection
*x
= a
, *y
= b
;
53 r
= strcmp(x
->filename
, y
->filename
);
57 return y
->line
- x
->line
;
60 const struct hash_ops network_config_hash_ops
= {
61 .hash
= network_config_hash_func
,
62 .compare
= network_config_compare_func
,
65 int network_config_section_new(const char *filename
, unsigned line
, NetworkConfigSection
**s
) {
66 NetworkConfigSection
*cs
;
68 cs
= malloc0(offsetof(NetworkConfigSection
, filename
) + strlen(filename
) + 1);
72 strcpy(cs
->filename
, filename
);
81 void network_config_section_free(NetworkConfigSection
*cs
) {
85 /* Set defaults following RFC7844 */
86 void network_apply_anonymize_if_set(Network
*network
) {
87 if (!network
->dhcp_anonymize
)
90 SHOULD NOT send the Host Name option */
91 network
->dhcp_send_hostname
= false;
92 /* RFC7844 section 3.:
93 MAY contain the Client Identifier option
95 clients MUST use client identifiers based solely
96 on the link-layer address */
97 /* NOTE: Using MAC, as it does not reveal extra information,
98 * and some servers might not answer if this option is not sent */
99 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_MAC
;
101 SHOULD NOT use the Vendor Class Identifier option */
102 /* NOTE: it was not initiallized to any value in network_load_one. */
103 network
->dhcp_vendor_class_identifier
= false;
104 /* RFC7844 section 3.6.:
105 The client intending to protect its privacy SHOULD only request a
106 minimal number of options in the PRL and SHOULD also randomly shuffle
107 the ordering of option codes in the PRL. If this random ordering
108 cannot be implemented, the client MAY order the option codes in the
109 PRL by option code number (lowest to highest).
111 /* NOTE: dhcp_use_mtu is false by default,
112 * though it was not initiallized to any value in network_load_one.
113 * Maybe there should be another var called *send*?
114 * (to use the MTU sent by the server but to do not send
115 * the option in the PRL). */
116 network
->dhcp_use_mtu
= false;
117 /* NOTE: when Anonymize=yes, the PRL route options are sent by default,
118 * but this is needed to use them. */
119 network
->dhcp_use_routes
= true;
120 /* RFC7844 section 3.6.
121 * same comments as previous option */
122 network
->dhcp_use_timezone
= false;
125 static int network_load_one(Manager
*manager
, const char *filename
) {
126 _cleanup_network_free_ Network
*network
= NULL
;
127 _cleanup_fclose_
FILE *file
= NULL
;
129 const char *dropin_dirname
;
137 file
= fopen(filename
, "re");
145 if (null_or_empty_fd(fileno(file
))) {
146 log_debug("Skipping empty file: %s", filename
);
150 network
= new0(Network
, 1);
154 network
->manager
= manager
;
156 LIST_HEAD_INIT(network
->static_addresses
);
157 LIST_HEAD_INIT(network
->static_routes
);
158 LIST_HEAD_INIT(network
->static_fdb_entries
);
159 LIST_HEAD_INIT(network
->ipv6_proxy_ndp_addresses
);
160 LIST_HEAD_INIT(network
->address_labels
);
161 LIST_HEAD_INIT(network
->static_prefixes
);
162 LIST_HEAD_INIT(network
->rules
);
164 network
->stacked_netdevs
= hashmap_new(&string_hash_ops
);
165 if (!network
->stacked_netdevs
)
168 network
->addresses_by_section
= hashmap_new(&network_config_hash_ops
);
169 if (!network
->addresses_by_section
)
172 network
->routes_by_section
= hashmap_new(&network_config_hash_ops
);
173 if (!network
->routes_by_section
)
176 network
->fdb_entries_by_section
= hashmap_new(NULL
);
177 if (!network
->fdb_entries_by_section
)
180 network
->address_labels_by_section
= hashmap_new(&network_config_hash_ops
);
181 if (!network
->address_labels_by_section
)
184 network
->prefixes_by_section
= hashmap_new(&network_config_hash_ops
);
185 if (!network
->prefixes_by_section
)
188 network
->rules_by_section
= hashmap_new(&network_config_hash_ops
);
189 if (!network
->rules_by_section
)
192 network
->filename
= strdup(filename
);
193 if (!network
->filename
)
196 network
->name
= strdup(basename(filename
));
200 d
= strrchr(network
->name
, '.');
204 assert(streq(d
, ".network"));
208 network
->required_for_online
= true;
209 network
->dhcp
= ADDRESS_FAMILY_NO
;
210 network
->dhcp_use_ntp
= true;
211 network
->dhcp_use_dns
= true;
212 network
->dhcp_use_hostname
= true;
213 network
->dhcp_use_routes
= true;
214 /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
215 network
->dhcp_send_hostname
= true;
216 /* To enable/disable RFC7844 Anonymity Profiles */
217 network
->dhcp_anonymize
= false;
218 network
->dhcp_route_metric
= DHCP_ROUTE_METRIC
;
219 /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
220 network
->dhcp_client_identifier
= DHCP_CLIENT_ID_DUID
;
221 network
->dhcp_route_table
= RT_TABLE_MAIN
;
222 network
->dhcp_route_table_set
= false;
223 /* NOTE: the following vars were not set to any default,
224 * even if they are commented in the man?
225 * These vars might be overwriten by network_apply_anonymize_if_set */
226 network
->dhcp_vendor_class_identifier
= false;
227 /* NOTE: from man: UseMTU=... Defaults to false*/
228 network
->dhcp_use_mtu
= false;
229 /* NOTE: from man: UseTimezone=... Defaults to "no".*/
230 network
->dhcp_use_timezone
= false;
231 network
->rapid_commit
= true;
233 network
->dhcp_server_emit_dns
= true;
234 network
->dhcp_server_emit_ntp
= true;
235 network
->dhcp_server_emit_router
= true;
236 network
->dhcp_server_emit_timezone
= true;
238 network
->router_emit_dns
= true;
239 network
->router_emit_domains
= true;
241 network
->use_bpdu
= true;
242 network
->allow_port_to_be_root
= true;
243 network
->unicast_flood
= true;
244 network
->priority
= LINK_BRIDGE_PORT_PRIORITY_INVALID
;
246 network
->lldp_mode
= LLDP_MODE_ROUTERS_ONLY
;
248 network
->llmnr
= RESOLVE_SUPPORT_YES
;
249 network
->mdns
= RESOLVE_SUPPORT_NO
;
250 network
->dnssec_mode
= _DNSSEC_MODE_INVALID
;
252 network
->link_local
= ADDRESS_FAMILY_IPV6
;
254 network
->ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
255 network
->ipv6_accept_ra
= -1;
256 network
->ipv6_dad_transmits
= -1;
257 network
->ipv6_hop_limit
= -1;
258 network
->ipv6_proxy_ndp
= -1;
259 network
->duid
.type
= _DUID_TYPE_INVALID
;
260 network
->proxy_arp
= -1;
262 network
->ipv6_accept_ra_use_dns
= true;
263 network
->ipv6_accept_ra_route_table
= RT_TABLE_MAIN
;
265 dropin_dirname
= strjoina(network
->name
, ".network.d");
267 r
= config_parse_many(filename
, network_dirs
, dropin_dirname
,
273 "RoutingPolicyRule\0"
276 "DHCPv4\0" /* compat */
279 "IPv6NDPProxyAddress\0"
283 "IPv6PrefixDelegation\0"
285 config_item_perf_lookup
, network_network_gperf_lookup
,
286 CONFIG_PARSE_WARN
, network
);
290 network_apply_anonymize_if_set(network
);
292 /* IPMasquerade=yes implies IPForward=yes */
293 if (network
->ip_masquerade
)
294 network
->ip_forward
|= ADDRESS_FAMILY_IPV4
;
296 LIST_PREPEND(networks
, manager
->networks
, network
);
298 r
= hashmap_ensure_allocated(&manager
->networks_by_name
, &string_hash_ops
);
302 r
= hashmap_put(manager
->networks_by_name
, network
->name
, network
);
306 LIST_FOREACH(routes
, route
, network
->static_routes
) {
307 if (!route
->family
) {
308 log_warning("Route section without Gateway field configured in %s. "
309 "Ignoring", filename
);
314 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
315 if (!address
->family
) {
316 log_warning("Address section without Address field configured in %s. "
317 "Ignoring", filename
);
327 int network_load(Manager
*manager
) {
329 _cleanup_strv_free_
char **files
= NULL
;
335 while ((network
= manager
->networks
))
336 network_free(network
);
338 r
= conf_files_list_strv(&files
, ".network", NULL
, 0, network_dirs
);
340 return log_error_errno(r
, "Failed to enumerate network files: %m");
342 STRV_FOREACH_BACKWARDS(f
, files
) {
343 r
= network_load_one(manager
, *f
);
351 void network_free(Network
*network
) {
352 IPv6ProxyNDPAddress
*ipv6_proxy_ndp_address
;
353 RoutingPolicyRule
*rule
;
365 free(network
->filename
);
367 free(network
->match_mac
);
368 strv_free(network
->match_path
);
369 strv_free(network
->match_driver
);
370 strv_free(network
->match_type
);
371 strv_free(network
->match_name
);
373 free(network
->description
);
374 free(network
->dhcp_vendor_class_identifier
);
375 free(network
->dhcp_hostname
);
379 strv_free(network
->ntp
);
381 strv_free(network
->search_domains
);
382 strv_free(network
->route_domains
);
383 strv_free(network
->bind_carrier
);
385 netdev_unref(network
->bridge
);
386 netdev_unref(network
->bond
);
387 netdev_unref(network
->vrf
);
389 HASHMAP_FOREACH(netdev
, network
->stacked_netdevs
, i
) {
390 hashmap_remove(network
->stacked_netdevs
, netdev
->ifname
);
391 netdev_unref(netdev
);
393 hashmap_free(network
->stacked_netdevs
);
395 while ((route
= network
->static_routes
))
398 while ((address
= network
->static_addresses
))
399 address_free(address
);
401 while ((fdb_entry
= network
->static_fdb_entries
))
402 fdb_entry_free(fdb_entry
);
404 while ((ipv6_proxy_ndp_address
= network
->ipv6_proxy_ndp_addresses
))
405 ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address
);
407 while ((label
= network
->address_labels
))
408 address_label_free(label
);
410 while ((prefix
= network
->static_prefixes
))
413 while ((rule
= network
->rules
))
414 routing_policy_rule_free(rule
);
416 hashmap_free(network
->addresses_by_section
);
417 hashmap_free(network
->routes_by_section
);
418 hashmap_free(network
->fdb_entries_by_section
);
419 hashmap_free(network
->address_labels_by_section
);
420 hashmap_free(network
->prefixes_by_section
);
421 hashmap_free(network
->rules_by_section
);
423 if (network
->manager
) {
424 if (network
->manager
->networks
)
425 LIST_REMOVE(networks
, network
->manager
->networks
, network
);
427 if (network
->manager
->networks_by_name
)
428 hashmap_remove(network
->manager
->networks_by_name
, network
->name
);
433 condition_free_list(network
->match_host
);
434 condition_free_list(network
->match_virt
);
435 condition_free_list(network
->match_kernel_cmdline
);
436 condition_free_list(network
->match_kernel_version
);
437 condition_free_list(network
->match_arch
);
439 free(network
->dhcp_server_timezone
);
440 free(network
->dhcp_server_dns
);
441 free(network
->dhcp_server_ntp
);
443 set_free_free(network
->dnssec_negative_trust_anchors
);
448 int network_get_by_name(Manager
*manager
, const char *name
, Network
**ret
) {
455 network
= hashmap_get(manager
->networks_by_name
, name
);
464 int network_get(Manager
*manager
, struct udev_device
*device
,
465 const char *ifname
, const struct ether_addr
*address
,
468 struct udev_device
*parent
;
469 const char *path
= NULL
, *parent_driver
= NULL
, *driver
= NULL
, *devtype
= NULL
;
475 path
= udev_device_get_property_value(device
, "ID_PATH");
477 parent
= udev_device_get_parent(device
);
479 parent_driver
= udev_device_get_driver(parent
);
481 driver
= udev_device_get_property_value(device
, "ID_NET_DRIVER");
483 devtype
= udev_device_get_devtype(device
);
486 LIST_FOREACH(networks
, network
, manager
->networks
) {
487 if (net_match_config(network
->match_mac
, network
->match_path
,
488 network
->match_driver
, network
->match_type
,
489 network
->match_name
, network
->match_host
,
490 network
->match_virt
, network
->match_kernel_cmdline
,
491 network
->match_kernel_version
, network
->match_arch
,
492 address
, path
, parent_driver
, driver
,
494 if (network
->match_name
&& device
) {
496 uint8_t name_assign_type
= NET_NAME_UNKNOWN
;
498 attr
= udev_device_get_sysattr_value(device
, "name_assign_type");
500 (void) safe_atou8(attr
, &name_assign_type
);
502 if (name_assign_type
== NET_NAME_ENUM
)
503 log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
504 ifname
, network
->filename
);
506 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
508 log_debug("%s: found matching network '%s'", ifname
, network
->filename
);
520 int network_apply(Network
*network
, Link
*link
) {
526 link
->network
= network
;
528 if (network
->ipv4ll_route
) {
531 r
= route_new_static(network
, NULL
, 0, &route
);
535 r
= inet_pton(AF_INET
, "169.254.0.0", &route
->dst
.in
);
541 route
->family
= AF_INET
;
542 route
->dst_prefixlen
= 16;
543 route
->scope
= RT_SCOPE_LINK
;
544 route
->priority
= IPV4LL_ROUTE_METRIC
;
545 route
->protocol
= RTPROT_STATIC
;
548 if (network
->n_dns
> 0 ||
549 !strv_isempty(network
->ntp
) ||
550 !strv_isempty(network
->search_domains
) ||
551 !strv_isempty(network
->route_domains
))
557 bool network_has_static_ipv6_addresses(Network
*network
) {
562 LIST_FOREACH(addresses
, address
, network
->static_addresses
) {
563 if (address
->family
== AF_INET6
)
570 int config_parse_netdev(const char *unit
,
571 const char *filename
,
574 unsigned section_line
,
580 Network
*network
= userdata
;
581 _cleanup_free_
char *kind_string
= NULL
;
592 kind_string
= strdup(lvalue
);
596 /* the keys are CamelCase versions of the kind */
597 for (p
= kind_string
; *p
; p
++)
600 kind
= netdev_kind_from_string(kind_string
);
601 if (kind
== _NETDEV_KIND_INVALID
) {
602 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid NetDev kind: %s", lvalue
);
606 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
608 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s could not be found, ignoring assignment: %s", lvalue
, rvalue
);
612 if (netdev
->kind
!= kind
) {
613 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue
, rvalue
);
618 case NETDEV_KIND_BRIDGE
:
619 network
->bridge
= netdev
;
622 case NETDEV_KIND_BOND
:
623 network
->bond
= netdev
;
626 case NETDEV_KIND_VRF
:
627 network
->vrf
= netdev
;
630 case NETDEV_KIND_VLAN
:
631 case NETDEV_KIND_MACVLAN
:
632 case NETDEV_KIND_MACVTAP
:
633 case NETDEV_KIND_IPVLAN
:
634 case NETDEV_KIND_VXLAN
:
635 case NETDEV_KIND_VCAN
:
636 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
638 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add NetDev '%s' to network: %m", rvalue
);
644 assert_not_reached("Cannot parse NetDev");
652 int config_parse_domains(
654 const char *filename
,
657 unsigned section_line
,
672 if (isempty(rvalue
)) {
673 n
->search_domains
= strv_free(n
->search_domains
);
674 n
->route_domains
= strv_free(n
->route_domains
);
680 _cleanup_free_
char *w
= NULL
, *normalized
= NULL
;
684 r
= extract_first_word(&p
, &w
, NULL
, 0);
686 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract search or route domain, ignoring: %s", rvalue
);
692 is_route
= w
[0] == '~';
693 domain
= is_route
? w
+ 1 : w
;
695 if (dns_name_is_root(domain
) || streq(domain
, "*")) {
696 /* If the root domain appears as is, or the special token "*" is found, we'll consider this as
697 * routing domain, unconditionally. */
699 domain
= "."; /* make sure we don't allow empty strings, thus write the root domain as "." */
702 r
= dns_name_normalize(domain
, &normalized
);
704 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "'%s' is not a valid domain name, ignoring.", domain
);
710 if (is_localhost(domain
)) {
711 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain
);
717 r
= strv_extend(&n
->route_domains
, domain
);
722 r
= strv_extend(&n
->search_domains
, domain
);
728 strv_uniq(n
->route_domains
);
729 strv_uniq(n
->search_domains
);
734 int config_parse_tunnel(const char *unit
,
735 const char *filename
,
738 unsigned section_line
,
744 Network
*network
= userdata
;
753 r
= netdev_get(network
->manager
, rvalue
, &netdev
);
755 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel is invalid, ignoring assignment: %s", rvalue
);
759 if (!IN_SET(netdev
->kind
,
765 NETDEV_KIND_IP6GRETAP
,
768 NETDEV_KIND_IP6TNL
)) {
769 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
770 "NetDev is not a tunnel, ignoring assignment: %s", rvalue
);
774 r
= hashmap_put(network
->stacked_netdevs
, netdev
->ifname
, netdev
);
776 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue
);
785 int config_parse_ipv4ll(
787 const char *filename
,
790 unsigned section_line
,
797 AddressFamilyBoolean
*link_local
= data
;
804 /* Note that this is mostly like
805 * config_parse_address_family_boolean(), except that it
806 * applies only to IPv4 */
808 SET_FLAG(*link_local
, ADDRESS_FAMILY_IPV4
, parse_boolean(rvalue
));
813 int config_parse_dhcp(
815 const char *filename
,
818 unsigned section_line
,
825 AddressFamilyBoolean
*dhcp
= data
, s
;
832 /* Note that this is mostly like
833 * config_parse_address_family_boolean(), except that it
834 * understands some old names for the enum values */
836 s
= address_family_boolean_from_string(rvalue
);
839 /* Previously, we had a slightly different enum here,
840 * support its values for compatbility. */
842 if (streq(rvalue
, "none"))
843 s
= ADDRESS_FAMILY_NO
;
844 else if (streq(rvalue
, "v4"))
845 s
= ADDRESS_FAMILY_IPV4
;
846 else if (streq(rvalue
, "v6"))
847 s
= ADDRESS_FAMILY_IPV6
;
848 else if (streq(rvalue
, "both"))
849 s
= ADDRESS_FAMILY_YES
;
851 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DHCP option, ignoring: %s", rvalue
);
860 static const char* const dhcp_client_identifier_table
[_DHCP_CLIENT_ID_MAX
] = {
861 [DHCP_CLIENT_ID_MAC
] = "mac",
862 [DHCP_CLIENT_ID_DUID
] = "duid"
865 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier
, DHCPClientIdentifier
);
866 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier
, dhcp_client_identifier
, DHCPClientIdentifier
, "Failed to parse client identifier type");
868 int config_parse_ipv6token(
870 const char *filename
,
873 unsigned section_line
,
880 union in_addr_union buffer
;
881 struct in6_addr
*token
= data
;
889 r
= in_addr_from_string(AF_INET6
, rvalue
, &buffer
);
891 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse IPv6 token, ignoring: %s", rvalue
);
895 r
= in_addr_is_null(AF_INET6
, &buffer
);
897 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue
);
901 if ((buffer
.in6
.s6_addr32
[0] | buffer
.in6
.s6_addr32
[1]) != 0) {
902 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue
);
911 static const char* const ipv6_privacy_extensions_table
[_IPV6_PRIVACY_EXTENSIONS_MAX
] = {
912 [IPV6_PRIVACY_EXTENSIONS_NO
] = "no",
913 [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC
] = "prefer-public",
914 [IPV6_PRIVACY_EXTENSIONS_YES
] = "yes",
917 DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions
, IPv6PrivacyExtensions
);
919 int config_parse_ipv6_privacy_extensions(
921 const char *filename
,
924 unsigned section_line
,
931 IPv6PrivacyExtensions
*ipv6_privacy_extensions
= data
;
937 assert(ipv6_privacy_extensions
);
939 /* Our enum shall be a superset of booleans, hence first try
940 * to parse as boolean, and then as enum */
942 k
= parse_boolean(rvalue
);
944 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_YES
;
946 *ipv6_privacy_extensions
= IPV6_PRIVACY_EXTENSIONS_NO
;
948 IPv6PrivacyExtensions s
;
950 s
= ipv6_privacy_extensions_from_string(rvalue
);
953 if (streq(rvalue
, "kernel"))
954 s
= _IPV6_PRIVACY_EXTENSIONS_INVALID
;
956 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue
);
961 *ipv6_privacy_extensions
= s
;
967 int config_parse_hostname(
969 const char *filename
,
972 unsigned section_line
,
979 char **hostname
= data
, *hn
= NULL
;
986 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &hn
, userdata
);
990 if (!hostname_is_valid(hn
, false)) {
991 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Hostname is not valid, ignoring assignment: %s", rvalue
);
997 *hostname
= hostname_cleanup(hn
);
1001 int config_parse_timezone(
1003 const char *filename
,
1005 const char *section
,
1006 unsigned section_line
,
1013 char **datap
= data
, *tz
= NULL
;
1020 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &tz
, userdata
);
1024 if (!timezone_is_valid(tz
)) {
1025 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Timezone is not valid, ignoring assignment: %s", rvalue
);
1036 int config_parse_dhcp_server_dns(
1038 const char *filename
,
1040 const char *section
,
1041 unsigned section_line
,
1049 const char *p
= rvalue
;
1057 _cleanup_free_
char *w
= NULL
;
1058 struct in_addr a
, *m
;
1060 r
= extract_first_word(&p
, &w
, NULL
, 0);
1064 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1070 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
1071 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
1075 m
= realloc(n
->dhcp_server_dns
, (n
->n_dhcp_server_dns
+ 1) * sizeof(struct in_addr
));
1079 m
[n
->n_dhcp_server_dns
++] = a
;
1080 n
->dhcp_server_dns
= m
;
1086 int config_parse_radv_dns(
1088 const char *filename
,
1090 const char *section
,
1091 unsigned section_line
,
1099 const char *p
= rvalue
;
1107 _cleanup_free_
char *w
= NULL
;
1108 union in_addr_union a
;
1110 r
= extract_first_word(&p
, &w
, NULL
, 0);
1114 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1120 if (in_addr_from_string(AF_INET6
, w
, &a
) >= 0) {
1123 m
= realloc(n
->router_dns
, (n
->n_router_dns
+ 1) * sizeof(struct in6_addr
));
1127 m
[n
->n_router_dns
++] = a
.in6
;
1131 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse DNS server address, ignoring: %s", w
);
1138 int config_parse_radv_search_domains(
1140 const char *filename
,
1142 const char *section
,
1143 unsigned section_line
,
1151 const char *p
= rvalue
;
1159 _cleanup_free_
char *w
= NULL
;
1160 _cleanup_free_
char *idna
= NULL
;
1162 r
= extract_first_word(&p
, &w
, NULL
, 0);
1166 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1172 r
= dns_name_apply_idna(w
, &idna
);
1174 r
= strv_push(&n
->router_search_domains
, idna
);
1177 } else if (r
== 0) {
1178 r
= strv_push(&n
->router_search_domains
, w
);
1187 int config_parse_dhcp_server_ntp(
1189 const char *filename
,
1191 const char *section
,
1192 unsigned section_line
,
1200 const char *p
= rvalue
;
1208 _cleanup_free_
char *w
= NULL
;
1209 struct in_addr a
, *m
;
1211 r
= extract_first_word(&p
, &w
, NULL
, 0);
1215 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract word, ignoring: %s", rvalue
);
1221 if (inet_pton(AF_INET
, w
, &a
) <= 0) {
1222 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse NTP server address, ignoring: %s", w
);
1226 m
= realloc(n
->dhcp_server_ntp
, (n
->n_dhcp_server_ntp
+ 1) * sizeof(struct in_addr
));
1230 m
[n
->n_dhcp_server_ntp
++] = a
;
1231 n
->dhcp_server_ntp
= m
;
1235 int config_parse_dns(
1237 const char *filename
,
1239 const char *section
,
1240 unsigned section_line
,
1247 Network
*n
= userdata
;
1255 _cleanup_free_
char *w
= NULL
;
1256 union in_addr_union a
;
1257 struct in_addr_data
*m
;
1260 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1264 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid syntax, ignoring: %s", rvalue
);
1270 r
= in_addr_from_string_auto(w
, &family
, &a
);
1272 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse dns server address, ignoring: %s", w
);
1276 m
= realloc(n
->dns
, (n
->n_dns
+ 1) * sizeof(struct in_addr_data
));
1280 m
[n
->n_dns
++] = (struct in_addr_data
) {
1291 int config_parse_dnssec_negative_trust_anchors(
1293 const char *filename
,
1295 const char *section
,
1296 unsigned section_line
,
1303 const char *p
= rvalue
;
1311 if (isempty(rvalue
)) {
1312 n
->dnssec_negative_trust_anchors
= set_free_free(n
->dnssec_negative_trust_anchors
);
1317 _cleanup_free_
char *w
= NULL
;
1319 r
= extract_first_word(&p
, &w
, NULL
, 0);
1321 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue
);
1327 r
= dns_name_is_valid(w
);
1329 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name, ignoring.", w
);
1333 r
= set_ensure_allocated(&n
->dnssec_negative_trust_anchors
, &dns_name_hash_ops
);
1337 r
= set_put(n
->dnssec_negative_trust_anchors
, w
);
1347 int config_parse_ntp(
1349 const char *filename
,
1351 const char *section
,
1352 unsigned section_line
,
1366 if (isempty(rvalue
)) {
1372 _cleanup_free_
char *w
= NULL
;
1374 r
= extract_first_word(&rvalue
, &w
, NULL
, 0);
1378 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract NTP server name, ignoring: %s", rvalue
);
1384 r
= dns_name_is_valid_or_address(w
);
1386 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "%s is not a valid domain name or IP address, ignoring.", w
);
1390 r
= strv_push(l
, w
);
1400 int config_parse_dhcp_route_table(const char *unit
,
1401 const char *filename
,
1403 const char *section
,
1404 unsigned section_line
,
1410 Network
*network
= data
;
1419 r
= safe_atou32(rvalue
, &rt
);
1421 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1422 "Unable to read RouteTable, ignoring assignment: %s", rvalue
);
1426 network
->dhcp_route_table
= rt
;
1427 network
->dhcp_route_table_set
= true;
1432 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains
, dhcp_use_domains
, DHCPUseDomains
, "Failed to parse DHCP use domains setting");
1434 static const char* const dhcp_use_domains_table
[_DHCP_USE_DOMAINS_MAX
] = {
1435 [DHCP_USE_DOMAINS_NO
] = "no",
1436 [DHCP_USE_DOMAINS_ROUTE
] = "route",
1437 [DHCP_USE_DOMAINS_YES
] = "yes",
1440 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains
, DHCPUseDomains
, DHCP_USE_DOMAINS_YES
);
1442 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode
, lldp_mode
, LLDPMode
, "Failed to parse LLDP= setting.");
1444 static const char* const lldp_mode_table
[_LLDP_MODE_MAX
] = {
1445 [LLDP_MODE_NO
] = "no",
1446 [LLDP_MODE_YES
] = "yes",
1447 [LLDP_MODE_ROUTERS_ONLY
] = "routers-only",
1450 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode
, LLDPMode
, LLDP_MODE_YES
);