1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
4 #include <linux/if_arp.h>
7 #include "dhcp-identifier.h"
8 #include "dhcp-internal.h"
9 #include "dhcp6-internal.h"
11 #include "hexdecoct.h"
12 #include "in-addr-prefix-util.h"
13 #include "networkd-dhcp-common.h"
14 #include "networkd-link.h"
15 #include "networkd-manager.h"
16 #include "networkd-network.h"
17 #include "parse-util.h"
18 #include "socket-util.h"
19 #include "string-table.h"
23 static uint32_t link_get_vrf_table(Link
*link
) {
25 assert(link
->network
);
27 return link
->network
->vrf
? VRF(link
->network
->vrf
)->table
: RT_TABLE_MAIN
;
30 uint32_t link_get_dhcp4_route_table(Link
*link
) {
32 assert(link
->network
);
34 /* When the interface is part of an VRF use the VRFs routing table, unless
35 * another table is explicitly specified. */
37 if (link
->network
->dhcp_route_table_set
)
38 return link
->network
->dhcp_route_table
;
39 return link_get_vrf_table(link
);
42 uint32_t link_get_dhcp6_route_table(Link
*link
) {
44 assert(link
->network
);
46 if (link
->network
->dhcp6_route_table_set
)
47 return link
->network
->dhcp6_route_table
;
48 return link_get_vrf_table(link
);
51 uint32_t link_get_ipv6_accept_ra_route_table(Link
*link
) {
53 assert(link
->network
);
55 if (link
->network
->ipv6_accept_ra_route_table_set
)
56 return link
->network
->ipv6_accept_ra_route_table
;
57 return link_get_vrf_table(link
);
60 bool link_dhcp_enabled(Link
*link
, int family
) {
62 assert(IN_SET(family
, AF_INET
, AF_INET6
));
64 if (family
== AF_INET6
&& !socket_ipv6_is_supported())
67 if (link
->flags
& IFF_LOOPBACK
)
70 if (link
->iftype
== ARPHRD_CAN
)
76 return link
->network
->dhcp
& (family
== AF_INET
? ADDRESS_FAMILY_IPV4
: ADDRESS_FAMILY_IPV6
);
79 void network_adjust_dhcp(Network
*network
) {
81 assert(network
->dhcp
>= 0);
83 if (network
->dhcp
== ADDRESS_FAMILY_NO
)
86 /* Bonding slave does not support addressing. */
88 log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
90 network
->dhcp
= ADDRESS_FAMILY_NO
;
94 if (!FLAGS_SET(network
->link_local
, ADDRESS_FAMILY_IPV6
) &&
95 FLAGS_SET(network
->dhcp
, ADDRESS_FAMILY_IPV6
)) {
96 log_warning("%s: DHCPv6 client is enabled but IPv6 link local addressing is disabled. "
97 "Disabling DHCPv6 client.", network
->filename
);
98 SET_FLAG(network
->dhcp
, ADDRESS_FAMILY_IPV6
, false);
101 network_adjust_dhcp4(network
);
104 static bool duid_needs_product_uuid(const DUID
*duid
) {
107 return duid
->type
== DUID_TYPE_UUID
&& duid
->raw_data_len
== 0;
110 static const struct DUID fallback_duid
= { .type
= DUID_TYPE_EN
};
112 const DUID
*link_get_duid(Link
*link
, int family
) {
116 assert(IN_SET(family
, AF_INET
, AF_INET6
));
119 duid
= family
== AF_INET
? &link
->network
->dhcp_duid
: &link
->network
->dhcp6_duid
;
120 if (duid
->type
!= _DUID_TYPE_INVALID
) {
121 if (duid_needs_product_uuid(duid
))
122 return &link
->manager
->duid_product_uuid
;
128 duid
= family
== AF_INET
? &link
->manager
->dhcp_duid
: &link
->manager
->dhcp6_duid
;
129 if (link
->hw_addr
.length
== 0 && IN_SET(duid
->type
, DUID_TYPE_LLT
, DUID_TYPE_LL
))
130 /* Fallback to DUID that works without MAC address.
131 * This is useful for tunnel devices without MAC address. */
132 return &fallback_duid
;
137 static int get_product_uuid_handler(sd_bus_message
*m
, void *userdata
, sd_bus_error
*ret_error
) {
138 Manager
*manager
= userdata
;
139 const sd_bus_error
*e
;
147 /* To avoid calling GetProductUUID() bus method so frequently, set the flag below
148 * even if the method fails. */
149 manager
->has_product_uuid
= true;
151 e
= sd_bus_message_get_error(m
);
153 r
= sd_bus_error_get_errno(e
);
154 log_warning_errno(r
, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s",
155 bus_error_message(e
, r
));
159 r
= sd_bus_message_read_array(m
, 'y', &a
, &sz
);
161 log_warning_errno(r
, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
165 if (sz
!= sizeof(sd_id128_t
)) {
166 log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID.");
170 log_debug("Successfully obtained product UUID");
172 memcpy(&manager
->duid_product_uuid
.raw_data
, a
, sz
);
173 manager
->duid_product_uuid
.raw_data_len
= sz
;
178 int manager_request_product_uuid(Manager
*m
) {
179 static bool bus_method_is_called
= false;
184 if (bus_method_is_called
)
187 if (sd_bus_is_ready(m
->bus
) <= 0 && !m
->product_uuid_requested
) {
188 log_debug("Not connected to system bus, requesting product UUID later.");
189 m
->product_uuid_requested
= true;
193 m
->product_uuid_requested
= false;
195 r
= sd_bus_call_method_async(
198 "org.freedesktop.hostname1",
199 "/org/freedesktop/hostname1",
200 "org.freedesktop.hostname1",
202 get_product_uuid_handler
,
207 return log_warning_errno(r
, "Failed to get product UUID: %m");
209 log_debug("Requesting product UUID.");
211 bus_method_is_called
= true;
216 int dhcp_configure_duid(Link
*link
, const DUID
*duid
) {
221 assert(link
->manager
);
226 if (!duid_needs_product_uuid(duid
))
229 if (m
->has_product_uuid
)
232 r
= manager_request_product_uuid(m
);
234 log_link_warning_errno(link
, r
,
235 "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m");
237 m
->has_product_uuid
= true; /* Do not request UUID again on failure. */
244 bool address_is_filtered(int family
, const union in_addr_union
*address
, uint8_t prefixlen
, Set
*allow_list
, Set
*deny_list
) {
245 struct in_addr_prefix
*p
;
247 assert(IN_SET(family
, AF_INET
, AF_INET6
));
251 SET_FOREACH(p
, allow_list
)
252 if (p
->family
== family
&&
253 p
->prefixlen
<= prefixlen
&&
254 in_addr_prefix_covers(family
, &p
->address
, p
->prefixlen
, address
) > 0)
260 SET_FOREACH(p
, deny_list
)
261 if (p
->family
== family
&&
262 in_addr_prefix_intersect(family
, &p
->address
, p
->prefixlen
, address
, prefixlen
) > 0)
268 int config_parse_dhcp(
270 const char *filename
,
273 unsigned section_line
,
280 AddressFamily
*dhcp
= data
, s
;
287 /* Note that this is mostly like
288 * config_parse_address_family(), except that it
289 * understands some old names for the enum values */
291 s
= address_family_from_string(rvalue
);
294 /* Previously, we had a slightly different enum here,
295 * support its values for compatibility. */
297 s
= dhcp_deprecated_address_family_from_string(rvalue
);
299 log_syntax(unit
, LOG_WARNING
, filename
, line
, s
,
300 "Failed to parse DHCP option, ignoring: %s", rvalue
);
304 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
305 "DHCP=%s is deprecated, please use DHCP=%s instead.",
306 rvalue
, address_family_to_string(s
));
313 int config_parse_dhcp_or_ra_route_metric(
315 const char *filename
,
318 unsigned section_line
,
325 Network
*network
= userdata
;
331 assert(IN_SET(ltype
, AF_UNSPEC
, AF_INET
, AF_INET6
));
335 r
= safe_atou32(rvalue
, &metric
);
337 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
338 "Failed to parse RouteMetric=%s, ignoring assignment: %m", rvalue
);
344 network
->dhcp_route_metric
= metric
;
345 network
->dhcp_route_metric_set
= true;
348 network
->ipv6_accept_ra_route_metric
= metric
;
349 network
->ipv6_accept_ra_route_metric_set
= true;
352 /* For backward compatibility. */
353 if (!network
->dhcp_route_metric_set
)
354 network
->dhcp_route_metric
= metric
;
355 if (!network
->ipv6_accept_ra_route_metric_set
)
356 network
->ipv6_accept_ra_route_metric
= metric
;
359 assert_not_reached();
365 int config_parse_dhcp_use_dns(
367 const char *filename
,
370 unsigned section_line
,
377 Network
*network
= userdata
;
382 assert(IN_SET(ltype
, AF_UNSPEC
, AF_INET
, AF_INET6
));
386 r
= parse_boolean(rvalue
);
388 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
389 "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue
);
395 network
->dhcp_use_dns
= r
;
396 network
->dhcp_use_dns_set
= true;
399 network
->dhcp6_use_dns
= r
;
400 network
->dhcp6_use_dns_set
= true;
403 /* For backward compatibility. */
404 if (!network
->dhcp_use_dns_set
)
405 network
->dhcp_use_dns
= r
;
406 if (!network
->dhcp6_use_dns_set
)
407 network
->dhcp6_use_dns
= r
;
410 assert_not_reached();
416 int config_parse_dhcp_use_domains(
418 const char *filename
,
421 unsigned section_line
,
428 Network
*network
= userdata
;
433 assert(IN_SET(ltype
, AF_UNSPEC
, AF_INET
, AF_INET6
));
437 d
= dhcp_use_domains_from_string(rvalue
);
439 log_syntax(unit
, LOG_WARNING
, filename
, line
, d
,
440 "Failed to parse %s=%s, ignoring assignment: %m", lvalue
, rvalue
);
446 network
->dhcp_use_domains
= d
;
447 network
->dhcp_use_domains_set
= true;
450 network
->dhcp6_use_domains
= d
;
451 network
->dhcp6_use_domains_set
= true;
454 /* For backward compatibility. */
455 if (!network
->dhcp_use_domains_set
)
456 network
->dhcp_use_domains
= d
;
457 if (!network
->dhcp6_use_domains_set
)
458 network
->dhcp6_use_domains
= d
;
461 assert_not_reached();
467 int config_parse_dhcp_use_ntp(
469 const char *filename
,
472 unsigned section_line
,
479 Network
*network
= userdata
;
484 assert(IN_SET(ltype
, AF_UNSPEC
, AF_INET
, AF_INET6
));
488 r
= parse_boolean(rvalue
);
490 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
491 "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue
);
497 network
->dhcp_use_ntp
= r
;
498 network
->dhcp_use_ntp_set
= true;
501 network
->dhcp6_use_ntp
= r
;
502 network
->dhcp6_use_ntp_set
= true;
505 /* For backward compatibility. */
506 if (!network
->dhcp_use_ntp_set
)
507 network
->dhcp_use_ntp
= r
;
508 if (!network
->dhcp6_use_ntp_set
)
509 network
->dhcp6_use_ntp
= r
;
512 assert_not_reached();
518 int config_parse_dhcp_or_ra_route_table(
520 const char *filename
,
523 unsigned section_line
,
530 Network
*network
= userdata
;
537 (RTPROT_DHCP
<<16) | AF_UNSPEC
,
538 (RTPROT_DHCP
<<16) | AF_INET
,
539 (RTPROT_DHCP
<<16) | AF_INET6
,
540 (RTPROT_RA
<<16) | AF_INET6
));
544 r
= safe_atou32(rvalue
, &rt
);
546 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
547 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue
);
552 case (RTPROT_DHCP
<<16) | AF_INET
:
553 network
->dhcp_route_table
= rt
;
554 network
->dhcp_route_table_set
= true;
555 network
->dhcp_route_table_set_explicitly
= true;
557 case (RTPROT_DHCP
<<16) | AF_INET6
:
558 network
->dhcp6_route_table
= rt
;
559 network
->dhcp6_route_table_set
= true;
560 network
->dhcp6_route_table_set_explicitly
= true;
562 case (RTPROT_DHCP
<<16) | AF_UNSPEC
:
563 /* For backward compatibility. */
564 if (!network
->dhcp_route_table_set_explicitly
) {
565 network
->dhcp_route_table
= rt
;
566 network
->dhcp_route_table_set
= true;
568 if (!network
->dhcp6_route_table_set_explicitly
) {
569 network
->dhcp6_route_table
= rt
;
570 network
->dhcp6_route_table_set
= true;
573 case (RTPROT_RA
<<16) | AF_INET6
:
574 network
->ipv6_accept_ra_route_table
= rt
;
575 network
->ipv6_accept_ra_route_table_set
= true;
578 assert_not_reached();
584 int config_parse_iaid(
586 const char *filename
,
589 unsigned section_line
,
596 Network
*network
= userdata
;
604 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
606 r
= safe_atou32(rvalue
, &iaid
);
608 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
609 "Unable to read IAID, ignoring assignment: %s", rvalue
);
613 if (ltype
== AF_INET
) {
614 network
->dhcp_iaid
= iaid
;
615 network
->dhcp_iaid_set
= true;
616 if (!network
->dhcp6_iaid_set_explicitly
) {
617 /* Backward compatibility. Previously, IAID is shared by DHCPv4 and DHCPv6.
618 * If DHCPv6 IAID is not specified explicitly, then use DHCPv4 IAID for DHCPv6. */
619 network
->dhcp6_iaid
= iaid
;
620 network
->dhcp6_iaid_set
= true;
623 assert(ltype
== AF_INET6
);
624 network
->dhcp6_iaid
= iaid
;
625 network
->dhcp6_iaid_set
= true;
626 network
->dhcp6_iaid_set_explicitly
= true;
632 int config_parse_dhcp_user_or_vendor_class(
634 const char *filename
,
637 unsigned section_line
,
650 assert(IN_SET(ltype
, AF_INET
, AF_INET6
));
652 if (isempty(rvalue
)) {
657 for (const char *p
= rvalue
;;) {
658 _cleanup_free_
char *w
= NULL
;
661 r
= extract_first_word(&p
, &w
, NULL
, EXTRACT_CUNESCAPE
|EXTRACT_UNQUOTE
);
665 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
666 "Failed to split user classes option, ignoring: %s", rvalue
);
673 if (ltype
== AF_INET
) {
674 if (len
> UINT8_MAX
|| len
== 0) {
675 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
676 "%s length is not in the range 1…255, ignoring.", w
);
680 if (len
> UINT16_MAX
|| len
== 0) {
681 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
682 "%s length is not in the range 1…65535, ignoring.", w
);
687 r
= strv_consume(l
, TAKE_PTR(w
));
693 int config_parse_dhcp_send_option(
695 const char *filename
,
698 unsigned section_line
,
705 _cleanup_(sd_dhcp_option_unrefp
) sd_dhcp_option
*opt4
= NULL
;
706 _cleanup_(sd_dhcp6_option_unrefp
) sd_dhcp6_option
*opt6
= NULL
;
707 _unused_
_cleanup_(sd_dhcp_option_unrefp
) sd_dhcp_option
*old4
= NULL
;
708 _unused_
_cleanup_(sd_dhcp6_option_unrefp
) sd_dhcp6_option
*old6
= NULL
;
709 uint32_t uint32_data
, enterprise_identifier
= 0;
710 _cleanup_free_
char *word
= NULL
, *q
= NULL
;
711 OrderedHashmap
**options
= data
;
712 uint16_t u16
, uint16_data
;
713 union in_addr_union addr
;
714 DHCPOptionDataType type
;
715 uint8_t u8
, uint8_data
;
726 if (isempty(rvalue
)) {
727 *options
= ordered_hashmap_free(*options
);
732 if (ltype
== AF_INET6
&& streq(lvalue
, "SendVendorOption")) {
733 r
= extract_first_word(&p
, &word
, ":", 0);
736 if (r
<= 0 || isempty(p
)) {
737 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
738 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
742 r
= safe_atou32(word
, &enterprise_identifier
);
744 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
745 "Failed to parse DHCPv6 enterprise identifier data, ignoring assignment: %s", p
);
751 r
= extract_first_word(&p
, &word
, ":", 0);
754 if (r
<= 0 || isempty(p
)) {
755 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
756 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
760 if (ltype
== AF_INET6
) {
761 r
= safe_atou16(word
, &u16
);
763 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
764 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
767 if (u16
< 1 || u16
>= UINT16_MAX
) {
768 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
769 "Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue
);
773 r
= safe_atou8(word
, &u8
);
775 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
776 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
779 if (u8
< 1 || u8
>= UINT8_MAX
) {
780 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
781 "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue
);
787 r
= extract_first_word(&p
, &word
, ":", 0);
790 if (r
<= 0 || isempty(p
)) {
791 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
792 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
796 type
= dhcp_option_data_type_from_string(word
);
798 log_syntax(unit
, LOG_WARNING
, filename
, line
, type
,
799 "Invalid DHCP option data type, ignoring assignment: %s", p
);
804 case DHCP_OPTION_DATA_UINT8
:{
805 r
= safe_atou8(p
, &uint8_data
);
807 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
808 "Failed to parse DHCP uint8 data, ignoring assignment: %s", p
);
813 sz
= sizeof(uint8_t);
816 case DHCP_OPTION_DATA_UINT16
:{
819 r
= safe_atou16(p
, &k
);
821 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
822 "Failed to parse DHCP uint16 data, ignoring assignment: %s", p
);
826 uint16_data
= htobe16(k
);
827 udata
= &uint16_data
;
828 sz
= sizeof(uint16_t);
831 case DHCP_OPTION_DATA_UINT32
: {
834 r
= safe_atou32(p
, &k
);
836 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
837 "Failed to parse DHCP uint32 data, ignoring assignment: %s", p
);
841 uint32_data
= htobe32(k
);
842 udata
= &uint32_data
;
843 sz
= sizeof(uint32_t);
847 case DHCP_OPTION_DATA_IPV4ADDRESS
: {
848 r
= in_addr_from_string(AF_INET
, p
, &addr
);
850 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
851 "Failed to parse DHCP ipv4address data, ignoring assignment: %s", p
);
856 sz
= sizeof(addr
.in
.s_addr
);
859 case DHCP_OPTION_DATA_IPV6ADDRESS
: {
860 r
= in_addr_from_string(AF_INET6
, p
, &addr
);
862 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
863 "Failed to parse DHCP ipv6address data, ignoring assignment: %s", p
);
868 sz
= sizeof(addr
.in6
.s6_addr
);
871 case DHCP_OPTION_DATA_STRING
:
872 sz
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &q
);
874 log_syntax(unit
, LOG_WARNING
, filename
, line
, sz
,
875 "Failed to decode DHCP option data, ignoring assignment: %s", p
);
883 if (ltype
== AF_INET6
) {
884 r
= sd_dhcp6_option_new(u16
, udata
, sz
, enterprise_identifier
, &opt6
);
886 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
887 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
891 r
= ordered_hashmap_ensure_allocated(options
, &dhcp6_option_hash_ops
);
895 /* Overwrite existing option */
896 old6
= ordered_hashmap_get(*options
, UINT_TO_PTR(u16
));
897 r
= ordered_hashmap_replace(*options
, UINT_TO_PTR(u16
), opt6
);
899 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
900 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
905 r
= sd_dhcp_option_new(u8
, udata
, sz
, &opt4
);
907 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
908 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
912 r
= ordered_hashmap_ensure_allocated(options
, &dhcp_option_hash_ops
);
916 /* Overwrite existing option */
917 old4
= ordered_hashmap_get(*options
, UINT_TO_PTR(u8
));
918 r
= ordered_hashmap_replace(*options
, UINT_TO_PTR(u8
), opt4
);
920 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
921 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
929 int config_parse_dhcp_request_options(
931 const char *filename
,
934 unsigned section_line
,
941 Network
*network
= userdata
;
949 if (isempty(rvalue
)) {
950 if (ltype
== AF_INET
)
951 network
->dhcp_request_options
= set_free(network
->dhcp_request_options
);
953 network
->dhcp6_request_options
= set_free(network
->dhcp6_request_options
);
958 for (const char *p
= rvalue
;;) {
959 _cleanup_free_
char *n
= NULL
;
962 r
= extract_first_word(&p
, &n
, NULL
, 0);
966 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
967 "Failed to parse DHCP request option, ignoring assignment: %s",
974 r
= safe_atou32(n
, &i
);
976 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
977 "DHCP request option is invalid, ignoring assignment: %s", n
);
981 if (i
< 1 || i
>= UINT8_MAX
) {
982 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
983 "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n
);
987 r
= set_ensure_put(ltype
== AF_INET
? &network
->dhcp_request_options
: &network
->dhcp6_request_options
,
988 NULL
, UINT32_TO_PTR(i
));
990 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
991 "Failed to store DHCP request option '%s', ignoring assignment: %m", n
);
995 static const char* const dhcp_use_domains_table
[_DHCP_USE_DOMAINS_MAX
] = {
996 [DHCP_USE_DOMAINS_NO
] = "no",
997 [DHCP_USE_DOMAINS_ROUTE
] = "route",
998 [DHCP_USE_DOMAINS_YES
] = "yes",
1001 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains
, DHCPUseDomains
, DHCP_USE_DOMAINS_YES
);
1003 static const char * const dhcp_option_data_type_table
[_DHCP_OPTION_DATA_MAX
] = {
1004 [DHCP_OPTION_DATA_UINT8
] = "uint8",
1005 [DHCP_OPTION_DATA_UINT16
] = "uint16",
1006 [DHCP_OPTION_DATA_UINT32
] = "uint32",
1007 [DHCP_OPTION_DATA_STRING
] = "string",
1008 [DHCP_OPTION_DATA_IPV4ADDRESS
] = "ipv4address",
1009 [DHCP_OPTION_DATA_IPV6ADDRESS
] = "ipv6address",
1012 DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type
, DHCPOptionDataType
);
1014 static const char* const duid_type_table
[_DUID_TYPE_MAX
] = {
1015 [DUID_TYPE_LLT
] = "link-layer-time",
1016 [DUID_TYPE_EN
] = "vendor",
1017 [DUID_TYPE_LL
] = "link-layer",
1018 [DUID_TYPE_UUID
] = "uuid",
1020 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type
, DUIDType
);
1022 int config_parse_duid_type(
1024 const char *filename
,
1026 const char *section
,
1027 unsigned section_line
,
1034 _cleanup_free_
char *type_string
= NULL
;
1035 const char *p
= rvalue
;
1046 if (!force
&& duid
->set
)
1049 r
= extract_first_word(&p
, &type_string
, ":", 0);
1053 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1054 "Invalid syntax, ignoring: %s", rvalue
);
1058 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1059 "Failed to extract DUID type from '%s', ignoring.", rvalue
);
1063 type
= duid_type_from_string(type_string
);
1065 log_syntax(unit
, LOG_WARNING
, filename
, line
, type
,
1066 "Failed to parse DUID type '%s', ignoring.", type_string
);
1073 if (type
!= DUID_TYPE_LLT
) {
1074 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1075 "Invalid syntax, ignoring: %s", rvalue
);
1079 r
= parse_timestamp(p
, &u
);
1081 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1082 "Failed to parse timestamp, ignoring: %s", p
);
1095 int config_parse_manager_duid_type(
1097 const char *filename
,
1099 const char *section
,
1100 unsigned section_line
,
1107 Manager
*manager
= userdata
;
1112 /* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
1114 r
= config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp_duid
, manager
);
1118 return config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp6_duid
, manager
);
1121 int config_parse_network_duid_type(
1123 const char *filename
,
1125 const char *section
,
1126 unsigned section_line
,
1133 Network
*network
= userdata
;
1138 r
= config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, true, rvalue
, &network
->dhcp_duid
, network
);
1142 /* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
1143 return config_parse_duid_type(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &network
->dhcp6_duid
, network
);
1146 int config_parse_duid_rawdata(
1148 const char *filename
,
1150 const char *section
,
1151 unsigned section_line
,
1158 uint8_t raw_data
[MAX_DUID_LEN
];
1168 if (!force
&& duid
->set
)
1171 /* RawData contains DUID in format "NN:NN:NN..." */
1172 for (const char *p
= rvalue
;;) {
1175 _cleanup_free_
char *cbyte
= NULL
;
1177 r
= extract_first_word(&p
, &cbyte
, ":", 0);
1181 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to read DUID, ignoring assignment: %s.", rvalue
);
1187 if (count
>= MAX_DUID_LEN
) {
1188 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue
);
1192 len
= strlen(cbyte
);
1193 if (!IN_SET(len
, 1, 2)) {
1194 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte
, rvalue
);
1197 n1
= unhexchar(cbyte
[0]);
1199 n2
= unhexchar(cbyte
[1]);
1203 if (n1
< 0 || n2
< 0) {
1204 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte
, rvalue
);
1208 byte
= ((uint8_t) n1
<< (4 * (len
-1))) | (uint8_t) n2
;
1209 raw_data
[count
++] = byte
;
1212 assert_cc(sizeof(raw_data
) == sizeof(duid
->raw_data
));
1213 memcpy(duid
->raw_data
, raw_data
, count
);
1214 duid
->raw_data_len
= count
;
1220 int config_parse_manager_duid_rawdata(
1222 const char *filename
,
1224 const char *section
,
1225 unsigned section_line
,
1232 Manager
*manager
= userdata
;
1237 /* For backward compatibility. Setting both DHCPv4 and DHCPv6 DUID if they are not specified explicitly. */
1239 r
= config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp_duid
, manager
);
1243 return config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &manager
->dhcp6_duid
, manager
);
1246 int config_parse_network_duid_rawdata(
1248 const char *filename
,
1250 const char *section
,
1251 unsigned section_line
,
1258 Network
*network
= userdata
;
1263 r
= config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, true, rvalue
, &network
->dhcp_duid
, network
);
1267 /* For backward compatibility, also set DHCPv6 DUID if not specified explicitly. */
1268 return config_parse_duid_rawdata(unit
, filename
, line
, section
, section_line
, lvalue
, false, rvalue
, &network
->dhcp6_duid
, network
);