1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "dhcp-internal.h"
4 #include "dhcp6-internal.h"
6 #include "in-addr-util.h"
7 #include "networkd-dhcp-common.h"
8 #include "networkd-network.h"
9 #include "parse-util.h"
10 #include "string-table.h"
14 int config_parse_dhcp(
19 unsigned section_line
,
26 AddressFamily
*dhcp
= data
, s
;
33 /* Note that this is mostly like
34 * config_parse_address_family(), except that it
35 * understands some old names for the enum values */
37 s
= address_family_from_string(rvalue
);
40 /* Previously, we had a slightly different enum here,
41 * support its values for compatibility. */
43 if (streq(rvalue
, "none"))
44 s
= ADDRESS_FAMILY_NO
;
45 else if (streq(rvalue
, "v4"))
46 s
= ADDRESS_FAMILY_IPV4
;
47 else if (streq(rvalue
, "v6"))
48 s
= ADDRESS_FAMILY_IPV6
;
49 else if (streq(rvalue
, "both"))
50 s
= ADDRESS_FAMILY_YES
;
52 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
53 "Failed to parse DHCP option, ignoring: %s", rvalue
);
57 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
58 "DHCP=%s is deprecated, please use DHCP=%s instead.",
59 rvalue
, address_family_to_string(s
));
66 int config_parse_dhcp_use_dns(
71 unsigned section_line
,
78 Network
*network
= data
;
86 r
= parse_boolean(rvalue
);
88 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
89 "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue
);
93 network
->dhcp_use_dns
= r
;
94 network
->dhcp6_use_dns
= r
;
99 int config_parse_dhcp_use_sip(
101 const char *filename
,
104 unsigned section_line
,
111 Network
*network
= data
;
119 r
= parse_boolean(rvalue
);
121 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
122 "Failed to parse UseSIP=%s, ignoring assignment: %m", rvalue
);
126 network
->dhcp_use_sip
= r
;
131 int config_parse_dhcp_use_ntp(
133 const char *filename
,
136 unsigned section_line
,
143 Network
*network
= data
;
151 r
= parse_boolean(rvalue
);
153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
154 "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue
);
158 network
->dhcp_use_ntp
= r
;
159 network
->dhcp6_use_ntp
= r
;
164 int config_parse_section_route_table(
166 const char *filename
,
169 unsigned section_line
,
176 Network
*network
= data
;
185 r
= safe_atou32(rvalue
, &rt
);
187 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
188 "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue
);
192 if (STRPTR_IN_SET(section
, "DHCP", "DHCPv4")) {
193 network
->dhcp_route_table
= rt
;
194 network
->dhcp_route_table_set
= true;
195 } else { /* section is IPv6AcceptRA */
196 network
->ipv6_accept_ra_route_table
= rt
;
197 network
->ipv6_accept_ra_route_table_set
= true;
203 int config_parse_iaid(const char *unit
,
204 const char *filename
,
207 unsigned section_line
,
213 Network
*network
= data
;
222 r
= safe_atou32(rvalue
, &iaid
);
224 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
225 "Unable to read IAID, ignoring assignment: %s", rvalue
);
229 network
->iaid
= iaid
;
230 network
->iaid_set
= true;
235 int config_parse_dhcp6_pd_hint(
237 const char *filename
,
240 unsigned section_line
,
247 Network
*network
= data
;
255 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, (union in_addr_union
*) &network
->dhcp6_pd_address
, &network
->dhcp6_pd_length
);
257 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue
);
261 if (network
->dhcp6_pd_length
< 1 || network
->dhcp6_pd_length
> 128) {
262 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid prefix length='%d', ignoring assignment", network
->dhcp6_pd_length
);
263 network
->dhcp6_pd_length
= 0;
270 int config_parse_dhcp6_mud_url(
272 const char *filename
,
275 unsigned section_line
,
282 _cleanup_free_
char *unescaped
= NULL
;
283 Network
*network
= data
;
290 if (isempty(rvalue
)) {
291 network
->dhcp6_mudurl
= mfree(network
->dhcp6_mudurl
);
295 r
= cunescape(rvalue
, 0, &unescaped
);
297 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
298 "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue
);
302 if (!http_url_is_valid(unescaped
) || strlen(unescaped
) > 255) {
303 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
304 "Failed to parse MUD URL '%s', ignoring: %m", rvalue
);
309 return free_and_replace(network
->dhcp6_mudurl
, unescaped
);
312 int config_parse_dhcp_send_option(
314 const char *filename
,
317 unsigned section_line
,
324 _cleanup_(sd_dhcp_option_unrefp
) sd_dhcp_option
*opt4
= NULL
, *old4
= NULL
;
325 _cleanup_(sd_dhcp6_option_unrefp
) sd_dhcp6_option
*opt6
= NULL
, *old6
= NULL
;
326 _cleanup_free_
char *word
= NULL
, *q
= NULL
;
327 OrderedHashmap
**options
= data
;
328 union in_addr_union addr
;
329 DHCPOptionDataType type
;
330 uint8_t u8
, uint8_data
;
331 uint16_t u16
, uint16_data
;
332 uint32_t uint32_data
;
343 if (isempty(rvalue
)) {
344 *options
= ordered_hashmap_free(*options
);
349 r
= extract_first_word(&p
, &word
, ":", 0);
353 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
354 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
358 if (ltype
== AF_INET6
) {
359 r
= safe_atou16(word
, &u16
);
361 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
362 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
365 if (u16
< 1 || u16
>= 65535) {
366 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
367 "Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue
);
371 r
= safe_atou8(word
, &u8
);
373 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
374 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
377 if (u8
< 1 || u8
>= 255) {
378 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
379 "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue
);
385 r
= extract_first_word(&p
, &word
, ":", 0);
389 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
390 "Invalid DHCP option, ignoring assignment: %s", rvalue
);
394 type
= dhcp_option_data_type_from_string(word
);
396 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
397 "Invalid DHCP option data type, ignoring assignment: %s", p
);
402 case DHCP_OPTION_DATA_UINT8
:{
403 r
= safe_atou8(p
, &uint8_data
);
405 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
406 "Failed to parse DHCP uint8 data, ignoring assignment: %s", p
);
411 sz
= sizeof(uint8_t);
414 case DHCP_OPTION_DATA_UINT16
:{
415 r
= safe_atou16(p
, &uint16_data
);
417 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
418 "Failed to parse DHCP uint16 data, ignoring assignment: %s", p
);
422 udata
= &uint16_data
;
423 sz
= sizeof(uint16_t);
426 case DHCP_OPTION_DATA_UINT32
: {
427 r
= safe_atou32(p
, &uint32_data
);
429 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
430 "Failed to parse DHCP uint32 data, ignoring assignment: %s", p
);
434 udata
= &uint32_data
;
435 sz
= sizeof(uint32_t);
439 case DHCP_OPTION_DATA_IPV4ADDRESS
: {
440 r
= in_addr_from_string(AF_INET
, p
, &addr
);
442 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
443 "Failed to parse DHCP ipv4address data, ignoring assignment: %s", p
);
448 sz
= sizeof(addr
.in
.s_addr
);
451 case DHCP_OPTION_DATA_IPV6ADDRESS
: {
452 r
= in_addr_from_string(AF_INET6
, p
, &addr
);
454 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
455 "Failed to parse DHCP ipv6address data, ignoring assignment: %s", p
);
460 sz
= sizeof(addr
.in6
.s6_addr
);
463 case DHCP_OPTION_DATA_STRING
:
464 sz
= cunescape(p
, UNESCAPE_ACCEPT_NUL
, &q
);
466 log_syntax(unit
, LOG_ERR
, filename
, line
, sz
,
467 "Failed to decode DHCP option data, ignoring assignment: %s", p
);
476 if (ltype
== AF_INET6
) {
477 r
= sd_dhcp6_option_new(u16
, udata
, sz
, &opt6
);
479 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
480 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
484 r
= ordered_hashmap_ensure_allocated(options
, &dhcp6_option_hash_ops
);
488 /* Overwrite existing option */
489 old6
= ordered_hashmap_get(*options
, UINT_TO_PTR(u16
));
490 r
= ordered_hashmap_replace(*options
, UINT_TO_PTR(u16
), opt6
);
492 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
493 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
498 r
= sd_dhcp_option_new(u8
, udata
, sz
, &opt4
);
500 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
501 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
505 r
= ordered_hashmap_ensure_allocated(options
, &dhcp_option_hash_ops
);
509 /* Overwrite existing option */
510 old4
= ordered_hashmap_get(*options
, UINT_TO_PTR(u8
));
511 r
= ordered_hashmap_replace(*options
, UINT_TO_PTR(u8
), opt4
);
513 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
514 "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue
);
522 int config_parse_dhcp_request_options(
524 const char *filename
,
527 unsigned section_line
,
534 Network
*network
= data
;
543 if (isempty(rvalue
)) {
544 if (ltype
== AF_INET
)
545 network
->dhcp_request_options
= set_free(network
->dhcp_request_options
);
547 network
->dhcp6_request_options
= set_free(network
->dhcp6_request_options
);
553 _cleanup_free_
char *n
= NULL
;
556 r
= extract_first_word(&p
, &n
, NULL
, 0);
558 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
559 "Failed to parse DHCP request option, ignoring assignment: %s",
566 r
= safe_atou32(n
, &i
);
568 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
569 "DHCP request option is invalid, ignoring assignment: %s", n
);
573 if (i
< 1 || i
>= 255) {
574 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
575 "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n
);
579 if (ltype
== AF_INET
)
580 r
= set_ensure_allocated(&network
->dhcp_request_options
, NULL
);
582 r
= set_ensure_allocated(&network
->dhcp6_request_options
, NULL
);
586 if (ltype
== AF_INET
)
587 r
= set_put(network
->dhcp_request_options
, UINT32_TO_PTR(i
));
589 r
= set_put(network
->dhcp6_request_options
, UINT32_TO_PTR(i
));
591 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
592 "Failed to store DHCP request option '%s', ignoring assignment: %m", n
);
598 DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains
, dhcp_use_domains
, DHCPUseDomains
,
599 "Failed to parse DHCP use domains setting");
601 static const char* const dhcp_use_domains_table
[_DHCP_USE_DOMAINS_MAX
] = {
602 [DHCP_USE_DOMAINS_NO
] = "no",
603 [DHCP_USE_DOMAINS_ROUTE
] = "route",
604 [DHCP_USE_DOMAINS_YES
] = "yes",
607 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains
, DHCPUseDomains
, DHCP_USE_DOMAINS_YES
);
609 static const char * const dhcp_option_data_type_table
[_DHCP_OPTION_DATA_MAX
] = {
610 [DHCP_OPTION_DATA_UINT8
] = "uint8",
611 [DHCP_OPTION_DATA_UINT16
] = "uint16",
612 [DHCP_OPTION_DATA_UINT32
] = "uint32",
613 [DHCP_OPTION_DATA_STRING
] = "string",
614 [DHCP_OPTION_DATA_IPV4ADDRESS
] = "ipv4address",
615 [DHCP_OPTION_DATA_IPV6ADDRESS
] = "ipv6address",
618 DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type
, DHCPOptionDataType
);