1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2013 Intel Corporation. All rights reserved.
7 #include <net/ethernet.h>
8 #include <net/if_arp.h>
11 #include <sys/ioctl.h>
12 #include <linux/if_infiniband.h>
14 #include "sd-dhcp-client.h"
16 #include "alloc-util.h"
17 #include "device-util.h"
18 #include "dhcp-client-id-internal.h"
19 #include "dhcp-client-internal.h"
20 #include "dhcp-lease-internal.h"
21 #include "dhcp-network.h"
22 #include "dhcp-option.h"
23 #include "dhcp-packet.h"
24 #include "dns-domain.h"
25 #include "ether-addr-util.h"
26 #include "event-util.h"
28 #include "hostname-util.h"
29 #include "iovec-util.h"
30 #include "memory-util.h"
31 #include "network-common.h"
32 #include "random-util.h"
34 #include "sort-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
38 #include "time-util.h"
42 #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
44 #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
45 #define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
47 #define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report
48 * transient failure. */
50 struct sd_dhcp_client
{
56 sd_event_source
*timeout_resend
;
65 union sockaddr_union link
;
66 sd_event_source
*receive_message
;
67 bool request_broadcast
;
72 struct hw_addr_data hw_addr
;
73 struct hw_addr_data bcast_addr
;
75 sd_dhcp_client_id client_id
;
77 char *vendor_class_identifier
;
81 usec_t fallback_lease_lifetime
;
88 uint64_t max_attempts
;
89 OrderedHashmap
*extra_options
;
90 OrderedHashmap
*vendor_options
;
91 sd_event_source
*timeout_t1
;
92 sd_event_source
*timeout_t2
;
93 sd_event_source
*timeout_expire
;
94 sd_event_source
*timeout_ipv6_only_mode
;
95 sd_dhcp_client_callback_t callback
;
97 sd_dhcp_client_callback_t state_callback
;
103 bool socket_priority_set
;
107 static const uint8_t default_req_opts
[] = {
108 SD_DHCP_OPTION_SUBNET_MASK
,
109 SD_DHCP_OPTION_ROUTER
,
110 SD_DHCP_OPTION_HOST_NAME
,
111 SD_DHCP_OPTION_DOMAIN_NAME
,
112 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
115 /* RFC7844 section 3:
116 MAY contain the Parameter Request List option.
118 The client intending to protect its privacy SHOULD only request a
119 minimal number of options in the PRL and SHOULD also randomly shuffle
120 the ordering of option codes in the PRL. If this random ordering
121 cannot be implemented, the client MAY order the option codes in the
122 PRL by option code number (lowest to highest).
124 /* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
125 static const uint8_t default_req_opts_anonymize
[] = {
126 SD_DHCP_OPTION_SUBNET_MASK
, /* 1 */
127 SD_DHCP_OPTION_ROUTER
, /* 3 */
128 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
, /* 6 */
129 SD_DHCP_OPTION_DOMAIN_NAME
, /* 15 */
130 SD_DHCP_OPTION_ROUTER_DISCOVERY
, /* 31 */
131 SD_DHCP_OPTION_STATIC_ROUTE
, /* 33 */
132 SD_DHCP_OPTION_VENDOR_SPECIFIC
, /* 43 */
133 SD_DHCP_OPTION_NETBIOS_NAME_SERVER
, /* 44 */
134 SD_DHCP_OPTION_NETBIOS_NODE_TYPE
, /* 46 */
135 SD_DHCP_OPTION_NETBIOS_SCOPE
, /* 47 */
136 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
, /* 121 */
137 SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE
, /* 249 */
138 SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY
, /* 252 */
141 static int client_receive_message_raw(
146 static int client_receive_message_udp(
151 static void client_stop(sd_dhcp_client
*client
, int error
);
153 int dhcp_client_set_state_callback(
154 sd_dhcp_client
*client
,
155 sd_dhcp_client_callback_t cb
,
158 assert_return(client
, -EINVAL
);
160 client
->state_callback
= cb
;
161 client
->state_userdata
= userdata
;
166 int sd_dhcp_client_set_callback(
167 sd_dhcp_client
*client
,
168 sd_dhcp_client_callback_t cb
,
171 assert_return(client
, -EINVAL
);
173 client
->callback
= cb
;
174 client
->userdata
= userdata
;
179 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client
*client
, int broadcast
) {
180 assert_return(client
, -EINVAL
);
181 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
183 client
->request_broadcast
= broadcast
;
188 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
189 assert_return(client
, -EINVAL
);
190 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
194 case SD_DHCP_OPTION_PAD
:
195 case SD_DHCP_OPTION_OVERLOAD
:
196 case SD_DHCP_OPTION_MESSAGE_TYPE
:
197 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST
:
198 case SD_DHCP_OPTION_END
:
205 return set_ensure_put(&client
->req_opts
, NULL
, UINT8_TO_PTR(option
));
208 static int client_request_contains(sd_dhcp_client
*client
, uint8_t option
) {
211 return set_contains(client
->req_opts
, UINT8_TO_PTR(option
));
214 int sd_dhcp_client_set_request_address(
215 sd_dhcp_client
*client
,
216 const struct in_addr
*last_addr
) {
218 assert_return(client
, -EINVAL
);
219 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
222 client
->last_addr
= last_addr
->s_addr
;
224 client
->last_addr
= INADDR_ANY
;
229 int sd_dhcp_client_set_ifindex(sd_dhcp_client
*client
, int ifindex
) {
230 assert_return(client
, -EINVAL
);
231 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
232 assert_return(ifindex
> 0, -EINVAL
);
234 client
->ifindex
= ifindex
;
238 int sd_dhcp_client_set_ifname(sd_dhcp_client
*client
, const char *ifname
) {
239 assert_return(client
, -EINVAL
);
240 assert_return(ifname
, -EINVAL
);
242 if (!ifname_valid_full(ifname
, IFNAME_VALID_ALTERNATIVE
))
245 return free_and_strdup(&client
->ifname
, ifname
);
248 int sd_dhcp_client_get_ifname(sd_dhcp_client
*client
, const char **ret
) {
251 assert_return(client
, -EINVAL
);
253 r
= get_ifname(client
->ifindex
, &client
->ifname
);
258 *ret
= client
->ifname
;
263 int sd_dhcp_client_set_mac(
264 sd_dhcp_client
*client
,
265 const uint8_t *hw_addr
,
266 const uint8_t *bcast_addr
,
270 assert_return(client
, -EINVAL
);
271 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
272 assert_return(IN_SET(arp_type
, ARPHRD_ETHER
, ARPHRD_INFINIBAND
), -EINVAL
);
273 assert_return(hw_addr
, -EINVAL
);
274 assert_return(addr_len
== (arp_type
== ARPHRD_ETHER
? ETH_ALEN
: INFINIBAND_ALEN
), -EINVAL
);
276 client
->arp_type
= arp_type
;
277 hw_addr_set(&client
->hw_addr
, hw_addr
, addr_len
);
278 hw_addr_set(&client
->bcast_addr
, bcast_addr
, bcast_addr
? addr_len
: 0);
283 int sd_dhcp_client_get_client_id(sd_dhcp_client
*client
, const sd_dhcp_client_id
**ret
) {
284 assert_return(client
, -EINVAL
);
285 assert_return(ret
, -EINVAL
);
287 if (!sd_dhcp_client_id_is_set(&client
->client_id
))
290 *ret
= &client
->client_id
;
294 int sd_dhcp_client_set_client_id(
295 sd_dhcp_client
*client
,
300 assert_return(client
, -EINVAL
);
301 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
302 assert_return(data
, -EINVAL
);
303 assert_return(client_id_data_size_is_valid(data_len
), -EINVAL
);
305 /* For hardware types, log debug message about unexpected data length.
307 * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
308 * the last 8 bytes of the address are stable and suitable to put into
309 * the client-id. The caller is advised to account for that. */
310 if ((type
== ARPHRD_ETHER
&& data_len
!= ETH_ALEN
) ||
311 (type
== ARPHRD_INFINIBAND
&& data_len
!= 8))
312 log_dhcp_client(client
,
313 "Changing client ID to hardware type %u with unexpected address length %zu",
316 return sd_dhcp_client_id_set(&client
->client_id
, type
, data
, data_len
);
319 static int dhcp_client_set_iaid_duid(
320 sd_dhcp_client
*client
,
323 sd_dhcp_duid
*duid
) {
328 r
= dhcp_identifier_set_iaid(client
->dev
, &client
->hw_addr
,
329 /* legacy_unstable_byteorder = */ true,
334 iaid
= be32toh(iaid
);
337 return sd_dhcp_client_id_set_iaid_duid(&client
->client_id
, iaid
, duid
);
340 int sd_dhcp_client_set_iaid_duid_llt(
341 sd_dhcp_client
*client
,
349 assert_return(client
, -EINVAL
);
350 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
352 r
= sd_dhcp_duid_set_llt(&duid
, client
->hw_addr
.bytes
, client
->hw_addr
.length
, client
->arp_type
, llt_time
);
356 return dhcp_client_set_iaid_duid(client
, iaid_set
, iaid
, &duid
);
359 int sd_dhcp_client_set_iaid_duid_ll(
360 sd_dhcp_client
*client
,
367 assert_return(client
, -EINVAL
);
368 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
370 r
= sd_dhcp_duid_set_ll(&duid
, client
->hw_addr
.bytes
, client
->hw_addr
.length
, client
->arp_type
);
374 return dhcp_client_set_iaid_duid(client
, iaid_set
, iaid
, &duid
);
377 int sd_dhcp_client_set_iaid_duid_en(
378 sd_dhcp_client
*client
,
385 assert_return(client
, -EINVAL
);
386 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
388 r
= sd_dhcp_duid_set_en(&duid
);
392 return dhcp_client_set_iaid_duid(client
, iaid_set
, iaid
, &duid
);
395 int sd_dhcp_client_set_iaid_duid_uuid(
396 sd_dhcp_client
*client
,
403 assert_return(client
, -EINVAL
);
404 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
406 r
= sd_dhcp_duid_set_uuid(&duid
);
410 return dhcp_client_set_iaid_duid(client
, iaid_set
, iaid
, &duid
);
413 int sd_dhcp_client_set_iaid_duid_raw(
414 sd_dhcp_client
*client
,
418 const uint8_t *duid_data
,
419 size_t duid_data_len
) {
424 assert_return(client
, -EINVAL
);
425 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
426 assert_return(duid_data
|| duid_data_len
== 0, -EINVAL
);
428 r
= sd_dhcp_duid_set(&duid
, duid_type
, duid_data
, duid_data_len
);
432 return dhcp_client_set_iaid_duid(client
, iaid_set
, iaid
, &duid
);
435 int sd_dhcp_client_set_rapid_commit(sd_dhcp_client
*client
, bool rapid_commit
) {
436 assert_return(client
, -EINVAL
);
438 client
->rapid_commit
= !client
->anonymize
&& rapid_commit
;
442 int sd_dhcp_client_set_hostname(
443 sd_dhcp_client
*client
,
444 const char *hostname
) {
446 assert_return(client
, -EINVAL
);
447 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
449 /* Make sure hostnames qualify as DNS and as Linux hostnames */
451 !(hostname_is_valid(hostname
, 0) && dns_name_is_valid(hostname
) > 0))
454 return free_and_strdup(&client
->hostname
, hostname
);
457 int sd_dhcp_client_set_vendor_class_identifier(
458 sd_dhcp_client
*client
,
461 assert_return(client
, -EINVAL
);
462 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
464 return free_and_strdup(&client
->vendor_class_identifier
, vci
);
467 int sd_dhcp_client_set_mud_url(
468 sd_dhcp_client
*client
,
469 const char *mudurl
) {
471 assert_return(client
, -EINVAL
);
472 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
473 assert_return(mudurl
, -EINVAL
);
474 assert_return(strlen(mudurl
) <= 255, -EINVAL
);
475 assert_return(http_url_is_valid(mudurl
), -EINVAL
);
477 return free_and_strdup(&client
->mudurl
, mudurl
);
480 int sd_dhcp_client_set_user_class(
481 sd_dhcp_client
*client
,
482 char * const *user_class
) {
486 assert_return(client
, -EINVAL
);
487 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
488 assert_return(!strv_isempty(user_class
), -EINVAL
);
490 STRV_FOREACH(p
, user_class
) {
491 size_t n
= strlen(*p
);
493 if (n
> 255 || n
== 0)
497 s
= strv_copy(user_class
);
501 return strv_free_and_replace(client
->user_class
, s
);
504 int sd_dhcp_client_set_client_port(
505 sd_dhcp_client
*client
,
508 assert_return(client
, -EINVAL
);
509 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
516 int sd_dhcp_client_set_mtu(sd_dhcp_client
*client
, uint32_t mtu
) {
517 assert_return(client
, -EINVAL
);
518 assert_return(mtu
>= DHCP_MIN_PACKET_SIZE
, -ERANGE
);
520 /* MTU may be changed by the acquired lease. Hence, we cannot require that the client is stopped here.
521 * Please do not add assertion for !sd_dhcp_client_is_running(client) here. */
528 int sd_dhcp_client_set_max_attempts(sd_dhcp_client
*client
, uint64_t max_attempts
) {
529 assert_return(client
, -EINVAL
);
530 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
532 client
->max_attempts
= max_attempts
;
537 int sd_dhcp_client_add_option(sd_dhcp_client
*client
, sd_dhcp_option
*v
) {
540 assert_return(client
, -EINVAL
);
541 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
542 assert_return(v
, -EINVAL
);
544 r
= ordered_hashmap_ensure_put(&client
->extra_options
, &dhcp_option_hash_ops
, UINT_TO_PTR(v
->option
), v
);
548 sd_dhcp_option_ref(v
);
552 int sd_dhcp_client_add_vendor_option(sd_dhcp_client
*client
, sd_dhcp_option
*v
) {
555 assert_return(client
, -EINVAL
);
556 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
557 assert_return(v
, -EINVAL
);
559 r
= ordered_hashmap_ensure_allocated(&client
->vendor_options
, &dhcp_option_hash_ops
);
563 r
= ordered_hashmap_put(client
->vendor_options
, v
, v
);
567 sd_dhcp_option_ref(v
);
572 int sd_dhcp_client_get_lease(sd_dhcp_client
*client
, sd_dhcp_lease
**ret
) {
573 assert_return(client
, -EINVAL
);
576 return -EADDRNOTAVAIL
;
579 *ret
= client
->lease
;
584 int sd_dhcp_client_set_service_type(sd_dhcp_client
*client
, int type
) {
585 assert_return(client
, -EINVAL
);
586 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
588 client
->ip_service_type
= type
;
593 int sd_dhcp_client_set_socket_priority(sd_dhcp_client
*client
, int socket_priority
) {
594 assert_return(client
, -EINVAL
);
595 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
597 client
->socket_priority_set
= true;
598 client
->socket_priority
= socket_priority
;
603 int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client
*client
, uint64_t fallback_lease_lifetime
) {
604 assert_return(client
, -EINVAL
);
605 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
606 assert_return(fallback_lease_lifetime
> 0, -EINVAL
);
608 assert_cc(sizeof(usec_t
) == sizeof(uint64_t));
609 client
->fallback_lease_lifetime
= fallback_lease_lifetime
;
614 static void client_set_state(sd_dhcp_client
*client
, DHCPState state
) {
617 if (client
->state
== state
)
620 log_dhcp_client(client
, "State changed: %s -> %s",
621 dhcp_state_to_string(client
->state
), dhcp_state_to_string(state
));
623 client
->state
= state
;
625 if (client
->state_callback
)
626 client
->state_callback(client
, state
, client
->state_userdata
);
629 int dhcp_client_get_state(sd_dhcp_client
*client
) {
630 assert_return(client
, -EINVAL
);
632 return client
->state
;
635 static int client_notify(sd_dhcp_client
*client
, int event
) {
638 if (client
->callback
)
639 return client
->callback(client
, event
, client
->userdata
);
644 static int client_initialize(sd_dhcp_client
*client
) {
645 assert_return(client
, -EINVAL
);
647 client
->receive_message
= sd_event_source_disable_unref(client
->receive_message
);
649 client
->fd
= safe_close(client
->fd
);
651 (void) event_source_disable(client
->timeout_resend
);
652 (void) event_source_disable(client
->timeout_t1
);
653 (void) event_source_disable(client
->timeout_t2
);
654 (void) event_source_disable(client
->timeout_expire
);
655 (void) event_source_disable(client
->timeout_ipv6_only_mode
);
659 client_set_state(client
, DHCP_STATE_STOPPED
);
662 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
667 static void client_stop(sd_dhcp_client
*client
, int error
) {
671 log_dhcp_client_errno(client
, error
, "STOPPED: %m");
672 else if (error
== SD_DHCP_CLIENT_EVENT_STOP
)
673 log_dhcp_client(client
, "STOPPED");
675 log_dhcp_client(client
, "STOPPED: Unknown event");
677 client_notify(client
, error
);
679 client_initialize(client
);
682 /* RFC2131 section 4.1:
683 * retransmission delays should include -1 to +1 sec of random 'fuzz'. */
684 #define RFC2131_RANDOM_FUZZ \
685 ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC)
687 /* RFC2131 section 4.1:
688 * for retransmission delays, timeout should start at 4s then double
689 * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added.
690 * This assumes the first call will be using attempt 1. */
691 static usec_t
client_compute_request_timeout(usec_t now
, uint64_t attempt
) {
692 usec_t timeout
= (UINT64_C(1) << MIN(attempt
+ 1, UINT64_C(6))) * USEC_PER_SEC
;
694 return usec_sub_signed(usec_add(now
, timeout
), RFC2131_RANDOM_FUZZ
);
697 /* RFC2131 section 4.4.5:
698 * T1 defaults to (0.5 * duration_of_lease).
699 * T2 defaults to (0.875 * duration_of_lease). */
700 #define T1_DEFAULT(lifetime) ((lifetime) / 2)
701 #define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8)
703 /* RFC2131 section 4.4.5:
704 * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state)
705 * and one-half of the remaining lease time (in REBINDING state), down to a minimum
707 * Note that while the default T1/T2 initial times do have random 'fuzz' applied,
708 * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */
709 static usec_t
client_compute_reacquisition_timeout(usec_t now
, usec_t expire
) {
710 return now
+ MAX(usec_sub_unsigned(expire
, now
) / 2, 60 * USEC_PER_SEC
);
713 static int cmp_uint8(const uint8_t *a
, const uint8_t *b
) {
717 static int client_message_init(
718 sd_dhcp_client
*client
,
722 size_t *_optoffset
) {
724 _cleanup_free_ DHCPPacket
*packet
= NULL
;
725 size_t optlen
, optoffset
, size
;
731 assert(client
->start_time
);
735 assert(IN_SET(type
, DHCP_DISCOVER
, DHCP_REQUEST
, DHCP_RELEASE
, DHCP_DECLINE
));
737 optlen
= DHCP_MIN_OPTIONS_SIZE
;
738 size
= sizeof(DHCPPacket
) + optlen
;
740 packet
= malloc0(size
);
744 r
= dhcp_message_init(&packet
->dhcp
, BOOTREQUEST
, client
->xid
, type
,
745 client
->arp_type
, client
->hw_addr
.length
, client
->hw_addr
.bytes
,
750 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
751 refuse to issue an DHCP lease if 'secs' is set to zero */
752 r
= sd_event_now(client
->event
, CLOCK_BOOTTIME
, &time_now
);
755 assert(time_now
>= client
->start_time
);
757 /* seconds between sending first and last DISCOVER
758 * must always be strictly positive to deal with broken servers */
759 secs
= ((time_now
- client
->start_time
) / USEC_PER_SEC
) ?: 1;
760 packet
->dhcp
.secs
= htobe16(secs
);
762 /* RFC2131 section 4.1
763 A client that cannot receive unicast IP datagrams until its protocol
764 software has been configured with an IP address SHOULD set the
765 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
766 DHCPREQUEST messages that client sends. The BROADCAST bit will
767 provide a hint to the DHCP server and BOOTP relay agent to broadcast
768 any messages to the client on the client's subnet.
770 Note: some interfaces needs this to be enabled, but some networks
771 needs this to be disabled as broadcasts are filteretd, so this
772 needs to be configurable */
773 if (client
->request_broadcast
|| client
->arp_type
!= ARPHRD_ETHER
)
774 packet
->dhcp
.flags
= htobe16(0x8000);
776 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
777 Identifier option is not set */
778 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
779 SD_DHCP_OPTION_CLIENT_IDENTIFIER
,
780 client
->client_id
.size
,
781 client
->client_id
.raw
);
785 /* RFC2131 section 3.5:
786 in its initial DHCPDISCOVER or DHCPREQUEST message, a
787 client may provide the server with a list of specific
788 parameters the client is interested in. If the client
789 includes a list of parameters in a DHCPDISCOVER message,
790 it MUST include that list in any subsequent DHCPREQUEST
794 /* RFC7844 section 3:
795 MAY contain the Parameter Request List option. */
796 /* NOTE: in case that there would be an option to do not send
797 * any PRL at all, the size should be checked before sending */
798 if (!set_isempty(client
->req_opts
) && type
!= DHCP_RELEASE
) {
799 _cleanup_free_
uint8_t *opts
= NULL
;
800 size_t n_opts
, i
= 0;
803 n_opts
= set_size(client
->req_opts
);
804 opts
= new(uint8_t, n_opts
);
808 SET_FOREACH(val
, client
->req_opts
)
809 opts
[i
++] = PTR_TO_UINT8(val
);
812 /* For anonymizing the request, let's sort the options. */
813 typesafe_qsort(opts
, n_opts
, cmp_uint8
);
815 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
816 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST
,
822 /* RFC2131 section 3.5:
823 The client SHOULD include the ’maximum DHCP message size’ option to
824 let the server know how large the server may make its DHCP messages.
826 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
827 than the defined default size unless the Maximum Message Size option
830 RFC3442 "Requirements to Avoid Sizing Constraints":
831 Because a full routing table can be quite large, the standard 576
832 octet maximum size for a DHCP message may be too short to contain
833 some legitimate Classless Static Route options. Because of this,
834 clients implementing the Classless Static Route option SHOULD send a
835 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
836 stack is capable of receiving larger IP datagrams. In this case, the
837 client SHOULD set the value of this option to at least the MTU of the
838 interface that the client is configuring. The client MAY set the
839 value of this option higher, up to the size of the largest UDP packet
840 it is prepared to accept. (Note that the value specified in the
841 Maximum DHCP Message Size option is the total maximum packet size,
842 including IP and UDP headers.)
844 /* RFC7844 section 3:
845 SHOULD NOT contain any other option. */
846 if (!client
->anonymize
&& IN_SET(type
, DHCP_DISCOVER
, DHCP_REQUEST
)) {
847 be16_t max_size
= htobe16(MIN(client
->mtu
- DHCP_IP_UDP_SIZE
, (uint32_t) UINT16_MAX
));
848 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
849 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
856 *_optoffset
= optoffset
;
857 *ret
= TAKE_PTR(packet
);
862 static int client_append_fqdn_option(
863 DHCPMessage
*message
,
868 uint8_t buffer
[3 + DHCP_MAX_FQDN_LENGTH
];
871 buffer
[0] = DHCP_FQDN_FLAG_S
| /* Request server to perform A RR DNS updates */
872 DHCP_FQDN_FLAG_E
; /* Canonical wire format */
873 buffer
[1] = 0; /* RCODE1 (deprecated) */
874 buffer
[2] = 0; /* RCODE2 (deprecated) */
876 r
= dns_name_to_wire_format(fqdn
, buffer
+ 3, sizeof(buffer
) - 3, false);
878 r
= dhcp_option_append(message
, optlen
, optoffset
, 0,
879 SD_DHCP_OPTION_FQDN
, 3 + r
, buffer
);
884 static int dhcp_client_send_raw(
885 sd_dhcp_client
*client
,
889 dhcp_packet_append_ip_headers(packet
, INADDR_ANY
, client
->port
,
890 INADDR_BROADCAST
, DHCP_PORT_SERVER
, len
, client
->ip_service_type
);
892 return dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
896 static int client_append_common_discover_request_options(sd_dhcp_client
*client
, DHCPPacket
*packet
, size_t *optoffset
, size_t optlen
) {
902 if (client
->hostname
) {
903 /* According to RFC 4702 "clients that send the Client FQDN option in
904 their messages MUST NOT also send the Host Name option". Just send
905 one of the two depending on the hostname type.
907 if (dns_name_is_single_label(client
->hostname
)) {
908 /* it is unclear from RFC 2131 if client should send hostname in
909 DHCPDISCOVER but dhclient does and so we do as well
911 r
= dhcp_option_append(&packet
->dhcp
, optlen
, optoffset
, 0,
912 SD_DHCP_OPTION_HOST_NAME
,
913 strlen(client
->hostname
), client
->hostname
);
915 r
= client_append_fqdn_option(&packet
->dhcp
, optlen
, optoffset
,
921 if (client
->vendor_class_identifier
) {
922 r
= dhcp_option_append(&packet
->dhcp
, optlen
, optoffset
, 0,
923 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER
,
924 strlen(client
->vendor_class_identifier
),
925 client
->vendor_class_identifier
);
930 if (client
->mudurl
) {
931 r
= dhcp_option_append(&packet
->dhcp
, optlen
, optoffset
, 0,
932 SD_DHCP_OPTION_MUD_URL
,
933 strlen(client
->mudurl
),
939 if (client
->user_class
) {
940 r
= dhcp_option_append(&packet
->dhcp
, optlen
, optoffset
, 0,
941 SD_DHCP_OPTION_USER_CLASS
,
942 strv_length(client
->user_class
),
948 ORDERED_HASHMAP_FOREACH(j
, client
->extra_options
) {
949 r
= dhcp_option_append(&packet
->dhcp
, optlen
, optoffset
, 0,
950 j
->option
, j
->length
, j
->data
);
955 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
956 r
= dhcp_option_append(
957 &packet
->dhcp
, optlen
, optoffset
, 0,
958 SD_DHCP_OPTION_VENDOR_SPECIFIC
,
959 ordered_hashmap_size(client
->vendor_options
), client
->vendor_options
);
968 static int client_send_discover(sd_dhcp_client
*client
) {
969 _cleanup_free_ DHCPPacket
*discover
= NULL
;
970 size_t optoffset
, optlen
;
974 assert(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_SELECTING
));
976 r
= client_message_init(client
, &discover
, DHCP_DISCOVER
,
977 &optlen
, &optoffset
);
981 /* the client may suggest values for the network address
982 and lease time in the DHCPDISCOVER message. The client may include
983 the ’requested IP address’ option to suggest that a particular IP
984 address be assigned, and may include the ’IP address lease time’
985 option to suggest the lease time it would like.
987 /* RFC7844 section 3:
988 SHOULD NOT contain any other option. */
989 if (!client
->anonymize
&& client
->last_addr
!= INADDR_ANY
) {
990 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
991 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
992 4, &client
->last_addr
);
997 if (client
->rapid_commit
) {
998 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
999 SD_DHCP_OPTION_RAPID_COMMIT
, 0, NULL
);
1004 r
= client_append_common_discover_request_options(client
, discover
, &optoffset
, optlen
);
1008 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
1009 SD_DHCP_OPTION_END
, 0, NULL
);
1013 /* We currently ignore:
1014 The client SHOULD wait a random time between one and ten seconds to
1015 desynchronize the use of DHCP at startup.
1017 r
= dhcp_client_send_raw(client
, discover
, sizeof(DHCPPacket
) + optoffset
);
1021 log_dhcp_client(client
, "DISCOVER");
1026 static int client_send_request(sd_dhcp_client
*client
) {
1027 _cleanup_free_ DHCPPacket
*request
= NULL
;
1028 size_t optoffset
, optlen
;
1033 r
= client_message_init(client
, &request
, DHCP_REQUEST
, &optlen
, &optoffset
);
1037 switch (client
->state
) {
1038 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
1039 SELECTING should be REQUESTING)
1042 case DHCP_STATE_REQUESTING
:
1043 /* Client inserts the address of the selected server in ’server
1044 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
1045 filled in with the yiaddr value from the chosen DHCPOFFER.
1048 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1049 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
1050 4, &client
->lease
->server_address
);
1054 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1055 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
1056 4, &client
->lease
->address
);
1062 case DHCP_STATE_INIT_REBOOT
:
1063 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1064 option MUST be filled in with client’s notion of its previously
1065 assigned address. ’ciaddr’ MUST be zero.
1067 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1068 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
1069 4, &client
->last_addr
);
1074 case DHCP_STATE_RENEWING
:
1075 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1076 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1077 client’s IP address.
1080 case DHCP_STATE_REBINDING
:
1081 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1082 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1083 client’s IP address.
1085 This message MUST be broadcast to the 0xffffffff IP broadcast address.
1087 request
->dhcp
.ciaddr
= client
->lease
->address
;
1091 case DHCP_STATE_INIT
:
1092 case DHCP_STATE_SELECTING
:
1093 case DHCP_STATE_REBOOTING
:
1094 case DHCP_STATE_BOUND
:
1095 case DHCP_STATE_STOPPED
:
1100 r
= client_append_common_discover_request_options(client
, request
, &optoffset
, optlen
);
1104 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1105 SD_DHCP_OPTION_END
, 0, NULL
);
1109 if (client
->state
== DHCP_STATE_RENEWING
)
1110 r
= dhcp_network_send_udp_socket(client
->fd
,
1111 client
->lease
->server_address
,
1114 sizeof(DHCPMessage
) + optoffset
);
1116 r
= dhcp_client_send_raw(client
, request
, sizeof(DHCPPacket
) + optoffset
);
1120 switch (client
->state
) {
1122 case DHCP_STATE_REQUESTING
:
1123 log_dhcp_client(client
, "REQUEST (requesting)");
1126 case DHCP_STATE_INIT_REBOOT
:
1127 log_dhcp_client(client
, "REQUEST (init-reboot)");
1130 case DHCP_STATE_RENEWING
:
1131 log_dhcp_client(client
, "REQUEST (renewing)");
1134 case DHCP_STATE_REBINDING
:
1135 log_dhcp_client(client
, "REQUEST (rebinding)");
1139 log_dhcp_client(client
, "REQUEST (invalid)");
1146 static int client_start(sd_dhcp_client
*client
);
1148 static int client_timeout_resend(
1153 sd_dhcp_client
*client
= ASSERT_PTR(userdata
);
1154 DHCP_CLIENT_DONT_DESTROY(client
);
1155 usec_t time_now
, next_timeout
;
1159 assert(client
->event
);
1161 r
= sd_event_now(client
->event
, CLOCK_BOOTTIME
, &time_now
);
1165 switch (client
->state
) {
1167 case DHCP_STATE_RENEWING
:
1168 next_timeout
= client_compute_reacquisition_timeout(time_now
, client
->t2_time
);
1171 case DHCP_STATE_REBINDING
:
1172 next_timeout
= client_compute_reacquisition_timeout(time_now
, client
->expire_time
);
1175 case DHCP_STATE_REBOOTING
:
1176 /* start over as we did not receive a timely ack or nak */
1177 r
= client_initialize(client
);
1181 r
= client_start(client
);
1185 log_dhcp_client(client
, "REBOOTED");
1188 case DHCP_STATE_INIT
:
1189 case DHCP_STATE_INIT_REBOOT
:
1190 case DHCP_STATE_SELECTING
:
1191 case DHCP_STATE_REQUESTING
:
1192 case DHCP_STATE_BOUND
:
1193 if (client
->attempt
>= client
->max_attempts
)
1197 next_timeout
= client_compute_request_timeout(time_now
, client
->attempt
);
1200 case DHCP_STATE_STOPPED
:
1205 assert_not_reached();
1208 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1210 next_timeout
, 10 * USEC_PER_MSEC
,
1211 client_timeout_resend
, client
,
1212 client
->event_priority
, "dhcp4-resend-timer", true);
1216 switch (client
->state
) {
1217 case DHCP_STATE_INIT
:
1218 r
= client_send_discover(client
);
1220 client_set_state(client
, DHCP_STATE_SELECTING
);
1221 client
->attempt
= 0;
1222 } else if (client
->attempt
>= client
->max_attempts
)
1226 case DHCP_STATE_SELECTING
:
1227 r
= client_send_discover(client
);
1228 if (r
< 0 && client
->attempt
>= client
->max_attempts
)
1232 case DHCP_STATE_INIT_REBOOT
:
1233 case DHCP_STATE_REQUESTING
:
1234 case DHCP_STATE_RENEWING
:
1235 case DHCP_STATE_REBINDING
:
1236 r
= client_send_request(client
);
1237 if (r
< 0 && client
->attempt
>= client
->max_attempts
)
1240 if (client
->state
== DHCP_STATE_INIT_REBOOT
)
1241 client_set_state(client
, DHCP_STATE_REBOOTING
);
1244 case DHCP_STATE_REBOOTING
:
1245 case DHCP_STATE_BOUND
:
1248 case DHCP_STATE_STOPPED
:
1254 if (client
->attempt
>= TRANSIENT_FAILURE_ATTEMPTS
)
1255 client_notify(client
, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE
);
1260 client_stop(client
, r
);
1262 /* Errors were dealt with when stopping the client, don't spill
1263 errors into the event loop handler */
1267 static int client_initialize_io_events(
1268 sd_dhcp_client
*client
,
1269 sd_event_io_handler_t io_callback
) {
1274 assert(client
->event
);
1276 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
1277 client
->fd
, EPOLLIN
, io_callback
,
1282 r
= sd_event_source_set_priority(client
->receive_message
,
1283 client
->event_priority
);
1287 r
= sd_event_source_set_description(client
->receive_message
, "dhcp4-receive-message");
1293 client_stop(client
, r
);
1298 static int client_initialize_time_events(sd_dhcp_client
*client
) {
1303 assert(client
->event
);
1305 (void) event_source_disable(client
->timeout_ipv6_only_mode
);
1307 if (client
->start_delay
> 0) {
1308 assert_se(sd_event_now(client
->event
, CLOCK_BOOTTIME
, &usec
) >= 0);
1309 usec
= usec_add(usec
, client
->start_delay
);
1312 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1315 client_timeout_resend
, client
,
1316 client
->event_priority
, "dhcp4-resend-timer", true);
1318 client_stop(client
, r
);
1324 static int client_initialize_events(sd_dhcp_client
*client
, sd_event_io_handler_t io_callback
) {
1325 client_initialize_io_events(client
, io_callback
);
1326 client_initialize_time_events(client
);
1331 static int client_start_delayed(sd_dhcp_client
*client
) {
1334 assert_return(client
, -EINVAL
);
1335 assert_return(client
->event
, -EINVAL
);
1336 assert_return(client
->ifindex
> 0, -EINVAL
);
1337 assert_return(client
->fd
< 0, -EBUSY
);
1338 assert_return(client
->xid
== 0, -EINVAL
);
1339 assert_return(IN_SET(client
->state
, DHCP_STATE_STOPPED
, DHCP_STATE_INIT_REBOOT
), -EBUSY
);
1341 client
->xid
= random_u32();
1343 r
= dhcp_network_bind_raw_socket(client
->ifindex
, &client
->link
, client
->xid
,
1344 &client
->hw_addr
, &client
->bcast_addr
,
1345 client
->arp_type
, client
->port
,
1346 client
->socket_priority_set
, client
->socket_priority
);
1348 client_stop(client
, r
);
1353 client
->start_time
= now(CLOCK_BOOTTIME
);
1355 if (client
->state
== DHCP_STATE_STOPPED
)
1356 client
->state
= DHCP_STATE_INIT
;
1358 return client_initialize_events(client
, client_receive_message_raw
);
1361 static int client_start(sd_dhcp_client
*client
) {
1362 client
->start_delay
= 0;
1363 return client_start_delayed(client
);
1366 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1367 sd_dhcp_client
*client
= userdata
;
1368 DHCP_CLIENT_DONT_DESTROY(client
);
1370 log_dhcp_client(client
, "EXPIRED");
1372 client_notify(client
, SD_DHCP_CLIENT_EVENT_EXPIRED
);
1374 /* lease was lost, start over if not freed or stopped in callback */
1375 if (client
->state
!= DHCP_STATE_STOPPED
) {
1376 client_initialize(client
);
1377 client_start(client
);
1383 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1384 sd_dhcp_client
*client
= ASSERT_PTR(userdata
);
1385 DHCP_CLIENT_DONT_DESTROY(client
);
1388 client
->receive_message
= sd_event_source_disable_unref(client
->receive_message
);
1389 client
->fd
= safe_close(client
->fd
);
1391 client_set_state(client
, DHCP_STATE_REBINDING
);
1392 client
->attempt
= 0;
1394 r
= dhcp_network_bind_raw_socket(client
->ifindex
, &client
->link
, client
->xid
,
1395 &client
->hw_addr
, &client
->bcast_addr
,
1396 client
->arp_type
, client
->port
,
1397 client
->socket_priority_set
, client
->socket_priority
);
1399 client_stop(client
, r
);
1404 return client_initialize_events(client
, client_receive_message_raw
);
1407 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1408 sd_dhcp_client
*client
= userdata
;
1409 DHCP_CLIENT_DONT_DESTROY(client
);
1412 client_set_state(client
, DHCP_STATE_RENEWING
);
1413 else if (client
->state
!= DHCP_STATE_INIT
)
1414 client_set_state(client
, DHCP_STATE_INIT_REBOOT
);
1415 client
->attempt
= 0;
1417 return client_initialize_time_events(client
);
1420 static int client_parse_message(
1421 sd_dhcp_client
*client
,
1422 DHCPMessage
*message
,
1424 sd_dhcp_lease
**ret
) {
1426 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1427 _cleanup_free_
char *error_message
= NULL
;
1434 r
= dhcp_lease_new(&lease
);
1438 if (sd_dhcp_client_id_is_set(&client
->client_id
)) {
1439 r
= dhcp_lease_set_client_id(lease
, &client
->client_id
);
1444 r
= dhcp_option_parse(message
, len
, dhcp_lease_parse_options
, lease
, &error_message
);
1446 return log_dhcp_client_errno(client
, r
, "Failed to parse DHCP options, ignoring: %m");
1448 switch (client
->state
) {
1449 case DHCP_STATE_SELECTING
:
1450 if (r
== DHCP_ACK
) {
1451 if (!client
->rapid_commit
)
1452 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1453 "received unexpected ACK, ignoring.");
1454 if (!lease
->rapid_commit
)
1455 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1456 "received rapid ACK without Rapid Commit option, ignoring.");
1457 } else if (r
== DHCP_OFFER
) {
1458 if (lease
->rapid_commit
) {
1459 /* Some RFC incompliant servers provides an OFFER with a rapid commit option.
1460 * See https://github.com/systemd/systemd/issues/29904.
1461 * Let's support such servers gracefully. */
1462 log_dhcp_client(client
, "received OFFER with Rapid Commit option, ignoring.");
1463 lease
->rapid_commit
= false;
1465 if (lease
->lifetime
== 0 && client
->fallback_lease_lifetime
> 0)
1466 lease
->lifetime
= client
->fallback_lease_lifetime
;
1468 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1469 "received unexpected message, ignoring.");
1473 case DHCP_STATE_REBOOTING
:
1474 case DHCP_STATE_REQUESTING
:
1475 case DHCP_STATE_RENEWING
:
1476 case DHCP_STATE_REBINDING
:
1477 if (r
== DHCP_NAK
) {
1478 if (client
->lease
&& client
->lease
->server_address
!= lease
->server_address
)
1479 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1480 "NAK from unexpected server, ignoring: %s",
1481 strna(error_message
));
1482 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EADDRNOTAVAIL
),
1483 "NAK: %s", strna(error_message
));
1486 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1487 "received message was not an ACK, ignoring.");
1491 assert_not_reached();
1494 lease
->next_server
= message
->siaddr
;
1495 lease
->address
= message
->yiaddr
;
1497 if (lease
->address
== 0 ||
1498 lease
->server_address
== 0 ||
1499 lease
->lifetime
== 0)
1500 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1501 "received lease lacks address, server address or lease lifetime, ignoring.");
1503 r
= dhcp_lease_set_default_subnet_mask(lease
);
1505 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1506 "received lease lacks subnet mask, and a fallback one cannot be generated, ignoring.");
1508 /* RFC 8925 section 3.2
1509 * If the client did not include the IPv6-Only Preferred option code in the Parameter Request List in
1510 * the DHCPDISCOVER or DHCPREQUEST message, it MUST ignore the IPv6-Only Preferred option in any
1511 * messages received from the server. */
1512 if (lease
->ipv6_only_preferred_usec
> 0 &&
1513 !client_request_contains(client
, SD_DHCP_OPTION_IPV6_ONLY_PREFERRED
)) {
1514 log_dhcp_client(client
, "Received message with unrequested IPv6-only preferred option, ignoring the option.");
1515 lease
->ipv6_only_preferred_usec
= 0;
1518 *ret
= TAKE_PTR(lease
);
1522 static int client_handle_offer_or_rapid_ack(sd_dhcp_client
*client
, DHCPMessage
*message
, size_t len
, const triple_timestamp
*timestamp
) {
1523 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1529 r
= client_parse_message(client
, message
, len
, &lease
);
1533 dhcp_lease_set_timestamp(lease
, timestamp
);
1535 dhcp_lease_unref_and_replace(client
->lease
, lease
);
1537 if (client
->lease
->rapid_commit
) {
1538 log_dhcp_client(client
, "ACK");
1539 return SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
;
1542 if (client_notify(client
, SD_DHCP_CLIENT_EVENT_SELECTING
) < 0)
1545 log_dhcp_client(client
, "OFFER");
1549 static int client_enter_requesting_now(sd_dhcp_client
*client
) {
1552 client_set_state(client
, DHCP_STATE_REQUESTING
);
1553 client
->attempt
= 0;
1555 return event_reset_time(client
->event
, &client
->timeout_resend
,
1556 CLOCK_BOOTTIME
, 0, 0,
1557 client_timeout_resend
, client
,
1558 client
->event_priority
, "dhcp4-resend-timer",
1559 /* force_reset = */ true);
1562 static int client_enter_requesting_delayed(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1563 sd_dhcp_client
*client
= ASSERT_PTR(userdata
);
1564 DHCP_CLIENT_DONT_DESTROY(client
);
1567 r
= client_enter_requesting_now(client
);
1569 client_stop(client
, r
);
1574 static int client_enter_requesting(sd_dhcp_client
*client
) {
1576 assert(client
->lease
);
1578 (void) event_source_disable(client
->timeout_resend
);
1580 if (client
->lease
->ipv6_only_preferred_usec
> 0) {
1581 if (client
->ipv6_acquired
) {
1582 log_dhcp_client(client
,
1583 "Received an OFFER with IPv6-only preferred option, and the host already acquired IPv6 connectivity, stopping DHCPv4 client.");
1584 return sd_dhcp_client_stop(client
);
1587 log_dhcp_client(client
,
1588 "Received an OFFER with IPv6-only preferred option, delaying to send REQUEST with %s.",
1589 FORMAT_TIMESPAN(client
->lease
->ipv6_only_preferred_usec
, USEC_PER_SEC
));
1591 return event_reset_time_relative(client
->event
, &client
->timeout_ipv6_only_mode
,
1593 client
->lease
->ipv6_only_preferred_usec
, 0,
1594 client_enter_requesting_delayed
, client
,
1595 client
->event_priority
, "dhcp4-ipv6-only-mode-timer",
1596 /* force_reset = */ true);
1599 return client_enter_requesting_now(client
);
1602 static int client_handle_forcerenew(sd_dhcp_client
*client
, DHCPMessage
*force
, size_t len
) {
1605 r
= dhcp_option_parse(force
, len
, NULL
, NULL
, NULL
);
1606 if (r
!= DHCP_FORCERENEW
)
1610 log_dhcp_client(client
, "FORCERENEW");
1613 /* FIXME: Ignore FORCERENEW requests until we implement RFC3118 (Authentication for DHCP
1614 * Messages) and/or RFC6704 (Forcerenew Nonce Authentication), as unauthenticated FORCERENEW
1615 * requests causes a security issue (TALOS-2020-1142, CVE-2020-13529). */
1616 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(ENOMSG
),
1617 "Received FORCERENEW, ignoring.");
1621 static bool lease_equal(const sd_dhcp_lease
*a
, const sd_dhcp_lease
*b
) {
1622 if (a
->address
!= b
->address
)
1625 if (a
->subnet_mask
!= b
->subnet_mask
)
1628 if (a
->router_size
!= b
->router_size
)
1631 for (size_t i
= 0; i
< a
->router_size
; i
++)
1632 if (a
->router
[i
].s_addr
!= b
->router
[i
].s_addr
)
1638 static int client_handle_ack(sd_dhcp_client
*client
, DHCPMessage
*message
, size_t len
, const triple_timestamp
*timestamp
) {
1639 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1645 r
= client_parse_message(client
, message
, len
, &lease
);
1649 dhcp_lease_set_timestamp(lease
, timestamp
);
1652 r
= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
;
1653 else if (lease_equal(client
->lease
, lease
))
1654 r
= SD_DHCP_CLIENT_EVENT_RENEW
;
1656 r
= SD_DHCP_CLIENT_EVENT_IP_CHANGE
;
1658 dhcp_lease_unref_and_replace(client
->lease
, lease
);
1660 log_dhcp_client(client
, "ACK");
1664 static int client_set_lease_timeouts(sd_dhcp_client
*client
) {
1669 assert(client
->event
);
1670 assert(client
->lease
);
1671 assert(client
->lease
->lifetime
> 0);
1672 assert(triple_timestamp_is_set(&client
->lease
->timestamp
));
1674 /* don't set timers for infinite leases */
1675 if (client
->lease
->lifetime
== USEC_INFINITY
) {
1676 (void) event_source_disable(client
->timeout_t1
);
1677 (void) event_source_disable(client
->timeout_t2
);
1678 (void) event_source_disable(client
->timeout_expire
);
1683 r
= sd_event_now(client
->event
, CLOCK_BOOTTIME
, &time_now
);
1687 /* verify that 0 < t2 < lifetime */
1688 if (client
->lease
->t2
== 0 || client
->lease
->t2
>= client
->lease
->lifetime
)
1689 client
->lease
->t2
= T2_DEFAULT(client
->lease
->lifetime
);
1690 /* verify that 0 < t1 < lifetime */
1691 if (client
->lease
->t1
== 0 || client
->lease
->t1
>= client
->lease
->t2
)
1692 client
->lease
->t1
= T1_DEFAULT(client
->lease
->lifetime
);
1693 /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check
1694 * could not evaluate to false if t1 >= t2; so setting t2 to T2_DEFAULT
1695 * guarantees t1 < t2. */
1696 if (client
->lease
->t1
>= client
->lease
->t2
)
1697 client
->lease
->t2
= T2_DEFAULT(client
->lease
->lifetime
);
1699 assert(client
->lease
->t1
> 0);
1700 assert(client
->lease
->t1
< client
->lease
->t2
);
1701 assert(client
->lease
->t2
< client
->lease
->lifetime
);
1703 r
= sd_dhcp_lease_get_lifetime_timestamp(client
->lease
, CLOCK_BOOTTIME
, &client
->expire_time
);
1706 r
= sd_dhcp_lease_get_t1_timestamp(client
->lease
, CLOCK_BOOTTIME
, &client
->t1_time
);
1709 r
= sd_dhcp_lease_get_t2_timestamp(client
->lease
, CLOCK_BOOTTIME
, &client
->t2_time
);
1713 /* RFC2131 section 4.4.5:
1714 * Times T1 and T2 SHOULD be chosen with some random "fuzz".
1715 * Since the RFC doesn't specify here the exact 'fuzz' to use,
1716 * we use the range from section 4.1: -1 to +1 sec. */
1717 client
->t1_time
= usec_sub_signed(client
->t1_time
, RFC2131_RANDOM_FUZZ
);
1718 client
->t2_time
= usec_sub_signed(client
->t2_time
, RFC2131_RANDOM_FUZZ
);
1720 /* after fuzzing, ensure t2 is still >= t1 */
1721 client
->t2_time
= MAX(client
->t1_time
, client
->t2_time
);
1723 /* arm lifetime timeout */
1724 r
= event_reset_time(client
->event
, &client
->timeout_expire
,
1726 client
->expire_time
, 10 * USEC_PER_MSEC
,
1727 client_timeout_expire
, client
,
1728 client
->event_priority
, "dhcp4-lifetime", true);
1732 /* don't arm earlier timeouts if this has already expired */
1733 if (client
->expire_time
<= time_now
)
1736 log_dhcp_client(client
, "lease expires in %s",
1737 FORMAT_TIMESPAN(client
->expire_time
- time_now
, USEC_PER_SEC
));
1739 /* arm T2 timeout */
1740 r
= event_reset_time(client
->event
, &client
->timeout_t2
,
1742 client
->t2_time
, 10 * USEC_PER_MSEC
,
1743 client_timeout_t2
, client
,
1744 client
->event_priority
, "dhcp4-t2-timeout", true);
1748 /* don't arm earlier timeout if this has already expired */
1749 if (client
->t2_time
<= time_now
)
1752 log_dhcp_client(client
, "T2 expires in %s",
1753 FORMAT_TIMESPAN(client
->t2_time
- time_now
, USEC_PER_SEC
));
1755 /* arm T1 timeout */
1756 r
= event_reset_time(client
->event
, &client
->timeout_t1
,
1758 client
->t1_time
, 10 * USEC_PER_MSEC
,
1759 client_timeout_t1
, client
,
1760 client
->event_priority
, "dhcp4-t1-timer", true);
1764 if (client
->t1_time
> time_now
)
1765 log_dhcp_client(client
, "T1 expires in %s",
1766 FORMAT_TIMESPAN(client
->t1_time
- time_now
, USEC_PER_SEC
));
1771 static int client_enter_bound_now(sd_dhcp_client
*client
, int notify_event
) {
1776 if (IN_SET(client
->state
, DHCP_STATE_REQUESTING
, DHCP_STATE_REBOOTING
))
1777 notify_event
= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
;
1779 client_set_state(client
, DHCP_STATE_BOUND
);
1780 client
->attempt
= 0;
1782 client
->last_addr
= client
->lease
->address
;
1784 r
= client_set_lease_timeouts(client
);
1786 log_dhcp_client_errno(client
, r
, "could not set lease timeouts: %m");
1788 r
= dhcp_network_bind_udp_socket(client
->ifindex
, client
->lease
->address
, client
->port
, client
->ip_service_type
);
1790 return log_dhcp_client_errno(client
, r
, "could not bind UDP socket: %m");
1792 client
->receive_message
= sd_event_source_disable_unref(client
->receive_message
);
1793 close_and_replace(client
->fd
, r
);
1794 client_initialize_io_events(client
, client_receive_message_udp
);
1796 client_notify(client
, notify_event
);
1801 static int client_enter_bound_delayed(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1802 sd_dhcp_client
*client
= ASSERT_PTR(userdata
);
1803 DHCP_CLIENT_DONT_DESTROY(client
);
1806 r
= client_enter_bound_now(client
, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
);
1808 client_stop(client
, r
);
1813 static int client_enter_bound(sd_dhcp_client
*client
, int notify_event
) {
1815 assert(client
->lease
);
1817 client
->start_delay
= 0;
1818 (void) event_source_disable(client
->timeout_resend
);
1820 /* RFC 8925 section 3.2
1821 * If the client is in the INIT-REBOOT state, it SHOULD stop the DHCPv4 configuration process or
1822 * disable the IPv4 stack completely for V6ONLY_WAIT seconds or until the network attachment event,
1823 * whichever happens first.
1825 * In the below, the condition uses REBOOTING, instead of INIT-REBOOT, as the client state has
1826 * already transitioned from INIT-REBOOT to REBOOTING after sending a DHCPREQUEST message. */
1827 if (client
->state
== DHCP_STATE_REBOOTING
&& client
->lease
->ipv6_only_preferred_usec
> 0) {
1828 if (client
->ipv6_acquired
) {
1829 log_dhcp_client(client
,
1830 "Received an ACK with IPv6-only preferred option, and the host already acquired IPv6 connectivity, stopping DHCPv4 client.");
1831 return sd_dhcp_client_stop(client
);
1834 log_dhcp_client(client
,
1835 "Received an ACK with IPv6-only preferred option, delaying to enter bound state with %s.",
1836 FORMAT_TIMESPAN(client
->lease
->ipv6_only_preferred_usec
, USEC_PER_SEC
));
1838 return event_reset_time_relative(client
->event
, &client
->timeout_ipv6_only_mode
,
1840 client
->lease
->ipv6_only_preferred_usec
, 0,
1841 client_enter_bound_delayed
, client
,
1842 client
->event_priority
, "dhcp4-ipv6-only-mode",
1843 /* force_reset = */ true);
1846 return client_enter_bound_now(client
, notify_event
);
1849 static int client_restart(sd_dhcp_client
*client
) {
1853 client_notify(client
, SD_DHCP_CLIENT_EVENT_EXPIRED
);
1855 r
= client_initialize(client
);
1859 r
= client_start_delayed(client
);
1863 log_dhcp_client(client
, "REBOOT in %s", FORMAT_TIMESPAN(client
->start_delay
, USEC_PER_SEC
));
1865 client
->start_delay
= CLAMP(client
->start_delay
* 2,
1866 RESTART_AFTER_NAK_MIN_USEC
, RESTART_AFTER_NAK_MAX_USEC
);
1870 static int client_verify_message_header(sd_dhcp_client
*client
, DHCPMessage
*message
, size_t len
) {
1871 const uint8_t *expected_chaddr
= NULL
;
1872 uint8_t expected_hlen
= 0;
1877 if (len
< sizeof(DHCPMessage
))
1878 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EBADMSG
),
1879 "Too small to be a DHCP message, ignoring.");
1881 if (be32toh(message
->magic
) != DHCP_MAGIC_COOKIE
)
1882 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EBADMSG
),
1883 "Not a DHCP message, ignoring.");
1885 if (message
->op
!= BOOTREPLY
)
1886 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EBADMSG
),
1887 "Not a BOOTREPLY message, ignoring.");
1889 if (message
->htype
!= client
->arp_type
)
1890 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EBADMSG
),
1891 "Packet type does not match client type, ignoring.");
1893 if (client
->arp_type
== ARPHRD_ETHER
) {
1894 expected_hlen
= ETH_ALEN
;
1895 expected_chaddr
= client
->hw_addr
.bytes
;
1898 if (message
->hlen
!= expected_hlen
)
1899 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EBADMSG
),
1900 "Received packet hlen (%u) does not match expected (%u), ignoring.",
1901 message
->hlen
, expected_hlen
);
1903 if (memcmp_safe(message
->chaddr
, expected_chaddr
, expected_hlen
))
1904 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EBADMSG
),
1905 "Received chaddr does not match expected, ignoring.");
1907 if (client
->state
!= DHCP_STATE_BOUND
&&
1908 be32toh(message
->xid
) != client
->xid
)
1909 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1910 so ignore the xid in this case */
1911 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EBADMSG
),
1912 "Received xid (%u) does not match expected (%u), ignoring.",
1913 be32toh(message
->xid
), client
->xid
);
1918 static int client_handle_message(sd_dhcp_client
*client
, DHCPMessage
*message
, size_t len
, const triple_timestamp
*timestamp
) {
1919 DHCP_CLIENT_DONT_DESTROY(client
);
1926 if (client_verify_message_header(client
, message
, len
) < 0)
1929 switch (client
->state
) {
1930 case DHCP_STATE_SELECTING
:
1932 r
= client_handle_offer_or_rapid_ack(client
, message
, len
, timestamp
);
1933 if (ERRNO_IS_NEG_RESOURCE(r
))
1935 if (r
== -EADDRNOTAVAIL
)
1936 /* got a rapid NAK, let's restart the client */
1937 return client_restart(client
);
1939 return 0; /* invalid message, let's ignore it */
1941 if (client
->lease
->rapid_commit
)
1942 /* got a successful rapid commit */
1943 return client_enter_bound(client
, r
);
1945 return client_enter_requesting(client
);
1947 case DHCP_STATE_REBOOTING
:
1948 case DHCP_STATE_REQUESTING
:
1949 case DHCP_STATE_RENEWING
:
1950 case DHCP_STATE_REBINDING
:
1952 r
= client_handle_ack(client
, message
, len
, timestamp
);
1953 if (ERRNO_IS_NEG_RESOURCE(r
))
1955 if (r
== -EADDRNOTAVAIL
)
1956 /* got a NAK, let's restart the client */
1957 return client_restart(client
);
1959 return 0; /* invalid message, let's ignore it */
1961 return client_enter_bound(client
, r
);
1963 case DHCP_STATE_BOUND
:
1964 r
= client_handle_forcerenew(client
, message
, len
);
1965 if (ERRNO_IS_NEG_RESOURCE(r
))
1968 return 0; /* invalid message, let's ignore it */
1970 return client_timeout_t1(NULL
, 0, client
);
1972 case DHCP_STATE_INIT
:
1973 case DHCP_STATE_INIT_REBOOT
:
1974 log_dhcp_client(client
, "Unexpectedly receive message without sending any requests, ignoring.");
1978 assert_not_reached();
1984 static int client_receive_message_udp(
1990 sd_dhcp_client
*client
= ASSERT_PTR(userdata
);
1991 _cleanup_free_ DHCPMessage
*message
= NULL
;
1992 ssize_t len
, buflen
;
1993 /* This needs to be initialized with zero. See #20741. */
1994 CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL
) control
= {};
1996 struct msghdr msg
= {
1999 .msg_control
= &control
,
2000 .msg_controllen
= sizeof(control
),
2006 buflen
= next_datagram_size_fd(fd
);
2007 if (ERRNO_IS_NEG_TRANSIENT(buflen
) || ERRNO_IS_NEG_DISCONNECT(buflen
))
2010 log_dhcp_client_errno(client
, buflen
, "Failed to determine datagram size to read, ignoring: %m");
2014 message
= malloc0(buflen
);
2018 iov
= IOVEC_MAKE(message
, buflen
);
2020 len
= recvmsg_safe(fd
, &msg
, MSG_DONTWAIT
);
2021 if (ERRNO_IS_NEG_TRANSIENT(len
) || ERRNO_IS_NEG_DISCONNECT(len
))
2024 log_dhcp_client_errno(client
, len
, "Could not receive message from UDP socket, ignoring: %m");
2028 log_dhcp_client(client
, "Received message from UDP socket, processing.");
2029 r
= client_handle_message(client
, message
, len
, TRIPLE_TIMESTAMP_FROM_CMSG(&msg
));
2031 client_stop(client
, r
);
2036 static int client_receive_message_raw(
2042 sd_dhcp_client
*client
= ASSERT_PTR(userdata
);
2043 _cleanup_free_ DHCPPacket
*packet
= NULL
;
2044 /* This needs to be initialized with zero. See #20741. */
2045 CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL
+
2046 CMSG_SPACE(sizeof(struct tpacket_auxdata
))) control
= {};
2047 struct iovec iov
= {};
2048 struct msghdr msg
= {
2051 .msg_control
= &control
,
2052 .msg_controllen
= sizeof(control
),
2054 bool checksum
= true;
2055 ssize_t buflen
, len
;
2060 buflen
= next_datagram_size_fd(fd
);
2061 if (ERRNO_IS_NEG_TRANSIENT(buflen
) || ERRNO_IS_NEG_DISCONNECT(buflen
))
2064 log_dhcp_client_errno(client
, buflen
, "Failed to determine datagram size to read, ignoring: %m");
2068 packet
= malloc0(buflen
);
2072 iov
= IOVEC_MAKE(packet
, buflen
);
2074 len
= recvmsg_safe(fd
, &msg
, 0);
2075 if (ERRNO_IS_NEG_TRANSIENT(len
) || ERRNO_IS_NEG_DISCONNECT(len
))
2078 log_dhcp_client_errno(client
, len
, "Could not receive message from raw socket, ignoring: %m");
2082 struct tpacket_auxdata
*aux
= CMSG_FIND_DATA(&msg
, SOL_PACKET
, PACKET_AUXDATA
, struct tpacket_auxdata
);
2084 checksum
= !(aux
->tp_status
& TP_STATUS_CSUMNOTREADY
);
2086 if (dhcp_packet_verify_headers(packet
, len
, checksum
, client
->port
) < 0)
2089 len
-= DHCP_IP_UDP_SIZE
;
2091 log_dhcp_client(client
, "Received message from RAW socket, processing.");
2092 r
= client_handle_message(client
, &packet
->dhcp
, len
, TRIPLE_TIMESTAMP_FROM_CMSG(&msg
));
2094 client_stop(client
, r
);
2099 int sd_dhcp_client_send_renew(sd_dhcp_client
*client
) {
2100 assert_return(client
, -EINVAL
);
2101 assert_return(sd_dhcp_client_is_running(client
), -ESTALE
);
2102 assert_return(client
->fd
>= 0, -EINVAL
);
2104 if (client
->state
!= DHCP_STATE_BOUND
)
2107 assert(client
->lease
);
2109 client
->start_delay
= 0;
2110 client
->attempt
= 1;
2111 client_set_state(client
, DHCP_STATE_RENEWING
);
2113 return client_initialize_time_events(client
);
2116 int sd_dhcp_client_is_running(sd_dhcp_client
*client
) {
2120 return client
->state
!= DHCP_STATE_STOPPED
;
2123 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
2126 assert_return(client
, -EINVAL
);
2128 /* Note, do not reset the flag in client_initialize(), as it is also called on expire. */
2129 client
->ipv6_acquired
= false;
2131 r
= client_initialize(client
);
2135 /* If no client identifier exists, construct an RFC 4361-compliant one */
2136 if (!sd_dhcp_client_id_is_set(&client
->client_id
)) {
2137 r
= sd_dhcp_client_set_iaid_duid_en(client
, /* iaid_set = */ false, /* iaid = */ 0);
2142 /* RFC7844 section 3.3:
2143 SHOULD perform a complete four-way handshake, starting with a
2144 DHCPDISCOVER, to obtain a new address lease. If the client can
2145 ascertain that this is exactly the same network to which it was
2146 previously connected, and if the link-layer address did not change,
2147 the client MAY issue a DHCPREQUEST to try to reclaim the current
2149 if (client
->last_addr
&& !client
->anonymize
)
2150 client_set_state(client
, DHCP_STATE_INIT_REBOOT
);
2152 r
= client_start(client
);
2154 log_dhcp_client(client
, "STARTED on ifindex %i", client
->ifindex
);
2159 int sd_dhcp_client_send_release(sd_dhcp_client
*client
) {
2160 assert_return(client
, -EINVAL
);
2161 assert_return(sd_dhcp_client_is_running(client
), -ESTALE
);
2162 assert_return(client
->lease
, -EUNATCH
);
2164 _cleanup_free_ DHCPPacket
*release
= NULL
;
2165 size_t optoffset
, optlen
;
2168 r
= client_message_init(client
, &release
, DHCP_RELEASE
, &optlen
, &optoffset
);
2172 /* Fill up release IP and MAC */
2173 release
->dhcp
.ciaddr
= client
->lease
->address
;
2174 memcpy(&release
->dhcp
.chaddr
, client
->hw_addr
.bytes
, client
->hw_addr
.length
);
2176 r
= dhcp_option_append(&release
->dhcp
, optlen
, &optoffset
, 0,
2177 SD_DHCP_OPTION_END
, 0, NULL
);
2181 r
= dhcp_network_send_udp_socket(client
->fd
,
2182 client
->lease
->server_address
,
2185 sizeof(DHCPMessage
) + optoffset
);
2189 log_dhcp_client(client
, "RELEASE");
2194 int sd_dhcp_client_send_decline(sd_dhcp_client
*client
) {
2195 assert_return(client
, -EINVAL
);
2196 assert_return(sd_dhcp_client_is_running(client
), -ESTALE
);
2197 assert_return(client
->lease
, -EUNATCH
);
2199 _cleanup_free_ DHCPPacket
*release
= NULL
;
2200 size_t optoffset
, optlen
;
2203 r
= client_message_init(client
, &release
, DHCP_DECLINE
, &optlen
, &optoffset
);
2207 release
->dhcp
.ciaddr
= client
->lease
->address
;
2208 memcpy(&release
->dhcp
.chaddr
, client
->hw_addr
.bytes
, client
->hw_addr
.length
);
2210 r
= dhcp_option_append(&release
->dhcp
, optlen
, &optoffset
, 0,
2211 SD_DHCP_OPTION_END
, 0, NULL
);
2215 r
= dhcp_network_send_udp_socket(client
->fd
,
2216 client
->lease
->server_address
,
2219 sizeof(DHCPMessage
) + optoffset
);
2223 log_dhcp_client(client
, "DECLINE");
2225 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
2227 if (client
->state
!= DHCP_STATE_STOPPED
) {
2228 r
= sd_dhcp_client_start(client
);
2236 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
2240 DHCP_CLIENT_DONT_DESTROY(client
);
2242 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
2247 int sd_dhcp_client_set_ipv6_connectivity(sd_dhcp_client
*client
, int have
) {
2251 /* We have already received a message with IPv6-Only preferred option, and are waiting for IPv6
2252 * connectivity or timeout, let's stop the client. */
2253 if (have
&& sd_event_source_get_enabled(client
->timeout_ipv6_only_mode
, NULL
) > 0)
2254 return sd_dhcp_client_stop(client
);
2256 /* Otherwise, save that the host already has IPv6 connectivity. */
2257 client
->ipv6_acquired
= have
;
2261 int sd_dhcp_client_interrupt_ipv6_only_mode(sd_dhcp_client
*client
) {
2262 assert_return(client
, -EINVAL
);
2263 assert_return(sd_dhcp_client_is_running(client
), -ESTALE
);
2264 assert_return(client
->fd
>= 0, -EINVAL
);
2266 if (sd_event_source_get_enabled(client
->timeout_ipv6_only_mode
, NULL
) <= 0)
2269 client_initialize(client
);
2270 return client_start(client
);
2273 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
, int64_t priority
) {
2276 assert_return(client
, -EINVAL
);
2277 assert_return(!client
->event
, -EBUSY
);
2278 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
2281 client
->event
= sd_event_ref(event
);
2283 r
= sd_event_default(&client
->event
);
2288 client
->event_priority
= priority
;
2293 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
2294 assert_return(client
, -EINVAL
);
2295 assert_return(!sd_dhcp_client_is_running(client
), -EBUSY
);
2297 client
->event
= sd_event_unref(client
->event
);
2302 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
2303 assert_return(client
, NULL
);
2305 return client
->event
;
2308 int sd_dhcp_client_attach_device(sd_dhcp_client
*client
, sd_device
*dev
) {
2309 assert_return(client
, -EINVAL
);
2311 return device_unref_and_replace(client
->dev
, dev
);
2314 static sd_dhcp_client
*dhcp_client_free(sd_dhcp_client
*client
) {
2318 log_dhcp_client(client
, "FREE");
2320 client_initialize(client
);
2322 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
2323 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
2324 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
2325 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
2327 sd_dhcp_client_detach_event(client
);
2329 sd_device_unref(client
->dev
);
2331 set_free(client
->req_opts
);
2332 free(client
->hostname
);
2333 free(client
->vendor_class_identifier
);
2334 free(client
->mudurl
);
2335 client
->user_class
= strv_free(client
->user_class
);
2336 ordered_hashmap_free(client
->extra_options
);
2337 ordered_hashmap_free(client
->vendor_options
);
2338 free(client
->ifname
);
2339 return mfree(client
);
2342 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client
, sd_dhcp_client
, dhcp_client_free
);
2344 int sd_dhcp_client_new(sd_dhcp_client
**ret
, int anonymize
) {
2345 const uint8_t *opts
;
2349 assert_return(ret
, -EINVAL
);
2351 _cleanup_(sd_dhcp_client_unrefp
) sd_dhcp_client
*client
= new(sd_dhcp_client
, 1);
2355 *client
= (sd_dhcp_client
) {
2357 .state
= DHCP_STATE_STOPPED
,
2360 .mtu
= DHCP_MIN_PACKET_SIZE
,
2361 .port
= DHCP_PORT_CLIENT
,
2362 .anonymize
= !!anonymize
,
2363 .max_attempts
= UINT64_MAX
,
2364 .ip_service_type
= -1,
2366 /* NOTE: this could be moved to a function. */
2368 n_opts
= ELEMENTSOF(default_req_opts_anonymize
);
2369 opts
= default_req_opts_anonymize
;
2371 n_opts
= ELEMENTSOF(default_req_opts
);
2372 opts
= default_req_opts
;
2375 for (size_t i
= 0; i
< n_opts
; i
++) {
2376 r
= sd_dhcp_client_set_request_option(client
, opts
[i
]);
2381 *ret
= TAKE_PTR(client
);
2386 static const char* const dhcp_state_table
[_DHCP_STATE_MAX
] = {
2387 [DHCP_STATE_STOPPED
] = "stopped",
2388 [DHCP_STATE_INIT
] = "initialization",
2389 [DHCP_STATE_SELECTING
] = "selecting",
2390 [DHCP_STATE_INIT_REBOOT
] = "init-reboot",
2391 [DHCP_STATE_REBOOTING
] = "rebooting",
2392 [DHCP_STATE_REQUESTING
] = "requesting",
2393 [DHCP_STATE_BOUND
] = "bound",
2394 [DHCP_STATE_RENEWING
] = "renewing",
2395 [DHCP_STATE_REBINDING
] = "rebinding",
2398 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dhcp_state
, DHCPState
);