1 /* SPDX-License-Identifier: LGPL-2.1+ */
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"
18 #include "dhcp-identifier.h"
19 #include "dhcp-internal.h"
20 #include "dhcp-lease-internal.h"
21 #include "dhcp-protocol.h"
22 #include "dns-domain.h"
23 #include "event-util.h"
24 #include "hostname-util.h"
26 #include "memory-util.h"
27 #include "random-util.h"
28 #include "string-util.h"
32 #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
33 #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
35 #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
36 #define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
38 struct sd_dhcp_client
{
44 sd_event_source
*timeout_resend
;
48 union sockaddr_union link
;
49 sd_event_source
*receive_message
;
50 bool request_broadcast
;
52 size_t req_opts_allocated
;
56 uint8_t mac_addr
[MAX_MAC_ADDR_LEN
];
63 /* 0: Generic (non-LL) (RFC 2132) */
64 uint8_t data
[MAX_CLIENT_ID_LEN
];
67 /* 1: Ethernet Link-Layer (RFC 2132) */
68 uint8_t haddr
[ETH_ALEN
];
71 /* 2 - 254: ARP/Link-Layer (RFC 2132) */
75 /* 255: Node-specific (RFC 4361) */
80 uint8_t data
[MAX_CLIENT_ID_LEN
];
86 char *vendor_class_identifier
;
93 uint64_t max_attempts
;
94 OrderedHashmap
*extra_options
;
95 OrderedHashmap
*vendor_options
;
97 sd_event_source
*timeout_t1
;
98 sd_event_source
*timeout_t2
;
99 sd_event_source
*timeout_expire
;
100 sd_dhcp_client_callback_t callback
;
102 sd_dhcp_lease
*lease
;
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_DISCOVER
, /* 31 */
131 SD_DHCP_OPTION_STATIC_ROUTE
, /* 33 */
132 SD_DHCP_OPTION_VENDOR_SPECIFIC
, /* 43 */
133 SD_DHCP_OPTION_NETBIOS_NAMESERVER
, /* 44 */
134 SD_DHCP_OPTION_NETBIOS_NODETYPE
, /* 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 sd_dhcp_client_set_callback(
154 sd_dhcp_client
*client
,
155 sd_dhcp_client_callback_t cb
,
158 assert_return(client
, -EINVAL
);
160 client
->callback
= cb
;
161 client
->userdata
= userdata
;
166 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client
*client
, int broadcast
) {
167 assert_return(client
, -EINVAL
);
169 client
->request_broadcast
= !!broadcast
;
174 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
177 assert_return(client
, -EINVAL
);
178 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
), -EBUSY
);
182 case SD_DHCP_OPTION_PAD
:
183 case SD_DHCP_OPTION_OVERLOAD
:
184 case SD_DHCP_OPTION_MESSAGE_TYPE
:
185 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST
:
186 case SD_DHCP_OPTION_END
:
193 for (i
= 0; i
< client
->req_opts_size
; i
++)
194 if (client
->req_opts
[i
] == option
)
197 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
198 client
->req_opts_size
+ 1))
201 client
->req_opts
[client
->req_opts_size
++] = option
;
206 int sd_dhcp_client_set_request_address(
207 sd_dhcp_client
*client
,
208 const struct in_addr
*last_addr
) {
210 assert_return(client
, -EINVAL
);
211 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
), -EBUSY
);
214 client
->last_addr
= last_addr
->s_addr
;
216 client
->last_addr
= INADDR_ANY
;
221 int sd_dhcp_client_set_ifindex(sd_dhcp_client
*client
, int ifindex
) {
223 assert_return(client
, -EINVAL
);
224 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
), -EBUSY
);
225 assert_return(ifindex
> 0, -EINVAL
);
227 client
->ifindex
= ifindex
;
231 int sd_dhcp_client_set_mac(
232 sd_dhcp_client
*client
,
237 DHCP_CLIENT_DONT_DESTROY(client
);
238 bool need_restart
= false;
241 assert_return(client
, -EINVAL
);
242 assert_return(addr
, -EINVAL
);
243 assert_return(addr_len
> 0 && addr_len
<= MAX_MAC_ADDR_LEN
, -EINVAL
);
244 assert_return(arp_type
> 0, -EINVAL
);
246 if (arp_type
== ARPHRD_ETHER
)
247 assert_return(addr_len
== ETH_ALEN
, -EINVAL
);
248 else if (arp_type
== ARPHRD_INFINIBAND
)
249 assert_return(addr_len
== INFINIBAND_ALEN
, -EINVAL
);
253 if (client
->mac_addr_len
== addr_len
&&
254 memcmp(&client
->mac_addr
, addr
, addr_len
) == 0)
257 if (!IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
)) {
258 log_dhcp_client(client
, "Changing MAC address on running DHCP client, restarting");
260 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
263 memcpy(&client
->mac_addr
, addr
, addr_len
);
264 client
->mac_addr_len
= addr_len
;
265 client
->arp_type
= arp_type
;
267 if (need_restart
&& client
->state
!= DHCP_STATE_STOPPED
) {
268 r
= sd_dhcp_client_start(client
);
270 return log_dhcp_client_errno(client
, r
, "Failed to restart DHCPv4 client: %m");
276 int sd_dhcp_client_get_client_id(
277 sd_dhcp_client
*client
,
279 const uint8_t **data
,
282 assert_return(client
, -EINVAL
);
283 assert_return(type
, -EINVAL
);
284 assert_return(data
, -EINVAL
);
285 assert_return(data_len
, -EINVAL
);
290 if (client
->client_id_len
) {
291 *type
= client
->client_id
.type
;
292 *data
= client
->client_id
.raw
.data
;
293 *data_len
= client
->client_id_len
- sizeof(client
->client_id
.type
);
299 int sd_dhcp_client_set_client_id(
300 sd_dhcp_client
*client
,
305 DHCP_CLIENT_DONT_DESTROY(client
);
306 bool need_restart
= false;
309 assert_return(client
, -EINVAL
);
310 assert_return(data
, -EINVAL
);
311 assert_return(data_len
> 0 && data_len
<= MAX_CLIENT_ID_LEN
, -EINVAL
);
313 if (client
->client_id_len
== data_len
+ sizeof(client
->client_id
.type
) &&
314 client
->client_id
.type
== type
&&
315 memcmp(&client
->client_id
.raw
.data
, data
, data_len
) == 0)
318 /* For hardware types, log debug message about unexpected data length.
320 * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
321 * last last 8 bytes of the address are stable and suitable to put into
322 * the client-id. The caller is advised to account for that. */
323 if ((type
== ARPHRD_ETHER
&& data_len
!= ETH_ALEN
) ||
324 (type
== ARPHRD_INFINIBAND
&& data_len
!= 8))
325 log_dhcp_client(client
, "Changing client ID to hardware type %u with "
326 "unexpected address length %zu",
329 if (!IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
)) {
330 log_dhcp_client(client
, "Changing client ID on running DHCP "
331 "client, restarting");
333 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
336 client
->client_id
.type
= type
;
337 memcpy(&client
->client_id
.raw
.data
, data
, data_len
);
338 client
->client_id_len
= data_len
+ sizeof (client
->client_id
.type
);
340 if (need_restart
&& client
->state
!= DHCP_STATE_STOPPED
) {
341 r
= sd_dhcp_client_start(client
);
343 return log_dhcp_client_errno(client
, r
, "Failed to restart DHCPv4 client: %m");
350 * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
351 * without further modification. Otherwise, if duid_type is supported, DUID
352 * is set based on that type. Otherwise, an error is returned.
354 static int dhcp_client_set_iaid_duid_internal(
355 sd_dhcp_client
*client
,
364 DHCP_CLIENT_DONT_DESTROY(client
);
368 assert_return(client
, -EINVAL
);
369 assert_return(duid_len
== 0 || duid
, -EINVAL
);
372 r
= dhcp_validate_duid_len(duid_type
, duid_len
, true);
374 return log_dhcp_client_errno(client
, r
, "Failed to validate length of DUID: %m");
377 zero(client
->client_id
);
378 client
->client_id
.type
= 255;
382 client
->client_id
.ns
.iaid
= htobe32(iaid
);
384 r
= dhcp_identifier_set_iaid(client
->ifindex
, client
->mac_addr
,
385 client
->mac_addr_len
,
387 &client
->client_id
.ns
.iaid
);
389 return log_dhcp_client_errno(client
, r
, "Failed to set IAID: %m");
394 client
->client_id
.ns
.duid
.type
= htobe16(duid_type
);
395 memcpy(&client
->client_id
.ns
.duid
.raw
.data
, duid
, duid_len
);
396 len
= sizeof(client
->client_id
.ns
.duid
.type
) + duid_len
;
400 if (client
->mac_addr_len
== 0)
401 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to set DUID-LLT, MAC address is not set.");
403 r
= dhcp_identifier_set_duid_llt(&client
->client_id
.ns
.duid
, llt_time
, client
->mac_addr
, client
->mac_addr_len
, client
->arp_type
, &len
);
405 return log_dhcp_client_errno(client
, r
, "Failed to set DUID-LLT: %m");
408 r
= dhcp_identifier_set_duid_en(&client
->client_id
.ns
.duid
, &len
);
410 return log_dhcp_client_errno(client
, r
, "Failed to set DUID-EN: %m");
413 if (client
->mac_addr_len
== 0)
414 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EOPNOTSUPP
), "Failed to set DUID-LL, MAC address is not set.");
416 r
= dhcp_identifier_set_duid_ll(&client
->client_id
.ns
.duid
, client
->mac_addr
, client
->mac_addr_len
, client
->arp_type
, &len
);
418 return log_dhcp_client_errno(client
, r
, "Failed to set DUID-LL: %m");
421 r
= dhcp_identifier_set_duid_uuid(&client
->client_id
.ns
.duid
, &len
);
423 return log_dhcp_client_errno(client
, r
, "Failed to set DUID-UUID: %m");
426 return log_dhcp_client_errno(client
, SYNTHETIC_ERRNO(EINVAL
), "Invalid DUID type");
429 client
->client_id_len
= sizeof(client
->client_id
.type
) + len
+
430 (iaid_append
? sizeof(client
->client_id
.ns
.iaid
) : 0);
432 if (!IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
)) {
433 log_dhcp_client(client
, "Configured %sDUID, restarting.", iaid_append
? "IAID+" : "");
434 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
435 r
= sd_dhcp_client_start(client
);
437 return log_dhcp_client_errno(client
, r
, "Failed to restart DHCPv4 client: %m");
443 int sd_dhcp_client_set_iaid_duid(
444 sd_dhcp_client
*client
,
450 return dhcp_client_set_iaid_duid_internal(client
, true, iaid_set
, iaid
, duid_type
, duid
, duid_len
, 0);
453 int sd_dhcp_client_set_iaid_duid_llt(
454 sd_dhcp_client
*client
,
458 return dhcp_client_set_iaid_duid_internal(client
, true, iaid_set
, iaid
, DUID_TYPE_LLT
, NULL
, 0, llt_time
);
461 int sd_dhcp_client_set_duid(
462 sd_dhcp_client
*client
,
466 return dhcp_client_set_iaid_duid_internal(client
, false, false, 0, duid_type
, duid
, duid_len
, 0);
469 int sd_dhcp_client_set_duid_llt(
470 sd_dhcp_client
*client
,
472 return dhcp_client_set_iaid_duid_internal(client
, false, false, 0, DUID_TYPE_LLT
, NULL
, 0, llt_time
);
475 int sd_dhcp_client_set_hostname(
476 sd_dhcp_client
*client
,
477 const char *hostname
) {
479 assert_return(client
, -EINVAL
);
481 /* Make sure hostnames qualify as DNS and as Linux hostnames */
483 !(hostname_is_valid(hostname
, false) && dns_name_is_valid(hostname
) > 0))
486 return free_and_strdup(&client
->hostname
, hostname
);
489 int sd_dhcp_client_set_vendor_class_identifier(
490 sd_dhcp_client
*client
,
493 assert_return(client
, -EINVAL
);
495 return free_and_strdup(&client
->vendor_class_identifier
, vci
);
498 int sd_dhcp_client_set_mud_url(
499 sd_dhcp_client
*client
,
500 const char *mudurl
) {
502 assert_return(client
, -EINVAL
);
503 assert_return(mudurl
, -EINVAL
);
504 assert_return(strlen(mudurl
) <= 255, -EINVAL
);
505 assert_return(http_url_is_valid(mudurl
), -EINVAL
);
507 return free_and_strdup(&client
->mudurl
, mudurl
);
510 int sd_dhcp_client_set_user_class(
511 sd_dhcp_client
*client
,
512 const char* const* user_class
) {
514 _cleanup_strv_free_
char **s
= NULL
;
517 STRV_FOREACH(p
, (char **) user_class
)
518 if (strlen(*p
) > 255)
519 return -ENAMETOOLONG
;
521 s
= strv_copy((char **) user_class
);
525 client
->user_class
= TAKE_PTR(s
);
530 int sd_dhcp_client_set_client_port(
531 sd_dhcp_client
*client
,
534 assert_return(client
, -EINVAL
);
541 int sd_dhcp_client_set_mtu(sd_dhcp_client
*client
, uint32_t mtu
) {
542 assert_return(client
, -EINVAL
);
543 assert_return(mtu
>= DHCP_DEFAULT_MIN_SIZE
, -ERANGE
);
550 int sd_dhcp_client_set_max_attempts(sd_dhcp_client
*client
, uint64_t max_attempts
) {
551 assert_return(client
, -EINVAL
);
553 client
->max_attempts
= max_attempts
;
558 int sd_dhcp_client_add_option(sd_dhcp_client
*client
, sd_dhcp_option
*v
) {
561 assert_return(client
, -EINVAL
);
562 assert_return(v
, -EINVAL
);
564 r
= ordered_hashmap_ensure_allocated(&client
->extra_options
, &dhcp_option_hash_ops
);
568 r
= ordered_hashmap_put(client
->extra_options
, UINT_TO_PTR(v
->option
), v
);
572 sd_dhcp_option_ref(v
);
576 int sd_dhcp_client_add_vendor_option(sd_dhcp_client
*client
, sd_dhcp_option
*v
) {
579 assert_return(client
, -EINVAL
);
580 assert_return(v
, -EINVAL
);
582 r
= ordered_hashmap_ensure_allocated(&client
->vendor_options
, &dhcp_option_hash_ops
);
586 r
= ordered_hashmap_put(client
->vendor_options
, v
, v
);
590 sd_dhcp_option_ref(v
);
595 int sd_dhcp_client_get_lease(sd_dhcp_client
*client
, sd_dhcp_lease
**ret
) {
596 assert_return(client
, -EINVAL
);
598 if (!IN_SET(client
->state
, DHCP_STATE_SELECTING
, DHCP_STATE_BOUND
, DHCP_STATE_RENEWING
, DHCP_STATE_REBINDING
))
599 return -EADDRNOTAVAIL
;
602 *ret
= client
->lease
;
607 int sd_dhcp_client_set_service_type(sd_dhcp_client
*client
, int type
) {
608 assert_return(client
, -EINVAL
);
610 client
->ip_service_type
= type
;
615 static int client_notify(sd_dhcp_client
*client
, int event
) {
618 if (client
->callback
)
619 return client
->callback(client
, event
, client
->userdata
);
624 static int client_initialize(sd_dhcp_client
*client
) {
625 assert_return(client
, -EINVAL
);
627 client
->receive_message
= sd_event_source_unref(client
->receive_message
);
629 client
->fd
= asynchronous_close(client
->fd
);
631 (void) event_source_disable(client
->timeout_resend
);
632 (void) event_source_disable(client
->timeout_t1
);
633 (void) event_source_disable(client
->timeout_t2
);
634 (void) event_source_disable(client
->timeout_expire
);
638 client
->state
= DHCP_STATE_INIT
;
641 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
646 static void client_stop(sd_dhcp_client
*client
, int error
) {
650 log_dhcp_client_errno(client
, error
, "STOPPED: %m");
651 else if (error
== SD_DHCP_CLIENT_EVENT_STOP
)
652 log_dhcp_client(client
, "STOPPED");
654 log_dhcp_client(client
, "STOPPED: Unknown event");
656 client_notify(client
, error
);
658 client_initialize(client
);
661 static int client_message_init(
662 sd_dhcp_client
*client
,
666 size_t *_optoffset
) {
668 _cleanup_free_ DHCPPacket
*packet
= NULL
;
669 size_t optlen
, optoffset
, size
;
676 assert(client
->start_time
);
680 assert(IN_SET(type
, DHCP_DISCOVER
, DHCP_REQUEST
, DHCP_RELEASE
, DHCP_DECLINE
));
682 optlen
= DHCP_MIN_OPTIONS_SIZE
;
683 size
= sizeof(DHCPPacket
) + optlen
;
685 packet
= malloc0(size
);
689 r
= dhcp_message_init(&packet
->dhcp
, BOOTREQUEST
, client
->xid
, type
,
690 client
->arp_type
, optlen
, &optoffset
);
694 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
695 refuse to issue an DHCP lease if 'secs' is set to zero */
696 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
699 assert(time_now
>= client
->start_time
);
701 /* seconds between sending first and last DISCOVER
702 * must always be strictly positive to deal with broken servers */
703 secs
= ((time_now
- client
->start_time
) / USEC_PER_SEC
) ? : 1;
704 packet
->dhcp
.secs
= htobe16(secs
);
706 /* RFC2132 section 4.1
707 A client that cannot receive unicast IP datagrams until its protocol
708 software has been configured with an IP address SHOULD set the
709 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
710 DHCPREQUEST messages that client sends. The BROADCAST bit will
711 provide a hint to the DHCP server and BOOTP relay agent to broadcast
712 any messages to the client on the client's subnet.
714 Note: some interfaces needs this to be enabled, but some networks
715 needs this to be disabled as broadcasts are filteretd, so this
716 needs to be configurable */
717 if (client
->request_broadcast
|| client
->arp_type
!= ARPHRD_ETHER
)
718 packet
->dhcp
.flags
= htobe16(0x8000);
720 /* RFC2132 section 4.1.1:
721 The client MUST include its hardware address in the ’chaddr’ field, if
722 necessary for delivery of DHCP reply messages. Non-Ethernet
723 interfaces will leave 'chaddr' empty and use the client identifier
724 instead (eg, RFC 4390 section 2.1).
726 if (client
->arp_type
== ARPHRD_ETHER
)
727 memcpy(&packet
->dhcp
.chaddr
, &client
->mac_addr
, ETH_ALEN
);
729 /* If no client identifier exists, construct an RFC 4361-compliant one */
730 if (client
->client_id_len
== 0) {
733 client
->client_id
.type
= 255;
735 r
= dhcp_identifier_set_iaid(client
->ifindex
, client
->mac_addr
, client
->mac_addr_len
,
736 true, &client
->client_id
.ns
.iaid
);
740 r
= dhcp_identifier_set_duid_en(&client
->client_id
.ns
.duid
, &duid_len
);
744 client
->client_id_len
= sizeof(client
->client_id
.type
) + sizeof(client
->client_id
.ns
.iaid
) + duid_len
;
747 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
748 Identifier option is not set */
749 if (client
->client_id_len
) {
750 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
751 SD_DHCP_OPTION_CLIENT_IDENTIFIER
,
752 client
->client_id_len
,
758 /* RFC2131 section 3.5:
759 in its initial DHCPDISCOVER or DHCPREQUEST message, a
760 client may provide the server with a list of specific
761 parameters the client is interested in. If the client
762 includes a list of parameters in a DHCPDISCOVER message,
763 it MUST include that list in any subsequent DHCPREQUEST
767 /* RFC7844 section 3:
768 MAY contain the Parameter Request List option. */
769 /* NOTE: in case that there would be an option to do not send
770 * any PRL at all, the size should be checked before sending */
771 if (client
->req_opts_size
> 0 && type
!= DHCP_RELEASE
) {
772 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
773 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST
,
774 client
->req_opts_size
, client
->req_opts
);
779 /* RFC2131 section 3.5:
780 The client SHOULD include the ’maximum DHCP message size’ option to
781 let the server know how large the server may make its DHCP messages.
783 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
784 than the defined default size unless the Maximum Message Size option
787 RFC3442 "Requirements to Avoid Sizing Constraints":
788 Because a full routing table can be quite large, the standard 576
789 octet maximum size for a DHCP message may be too short to contain
790 some legitimate Classless Static Route options. Because of this,
791 clients implementing the Classless Static Route option SHOULD send a
792 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
793 stack is capable of receiving larger IP datagrams. In this case, the
794 client SHOULD set the value of this option to at least the MTU of the
795 interface that the client is configuring. The client MAY set the
796 value of this option higher, up to the size of the largest UDP packet
797 it is prepared to accept. (Note that the value specified in the
798 Maximum DHCP Message Size option is the total maximum packet size,
799 including IP and UDP headers.)
801 /* RFC7844 section 3:
802 SHOULD NOT contain any other option. */
803 if (!client
->anonymize
&& type
!= DHCP_RELEASE
) {
804 max_size
= htobe16(size
);
805 r
= dhcp_option_append(&packet
->dhcp
, client
->mtu
, &optoffset
, 0,
806 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
813 *_optoffset
= optoffset
;
814 *ret
= TAKE_PTR(packet
);
819 static int client_append_fqdn_option(
820 DHCPMessage
*message
,
825 uint8_t buffer
[3 + DHCP_MAX_FQDN_LENGTH
];
828 buffer
[0] = DHCP_FQDN_FLAG_S
| /* Request server to perform A RR DNS updates */
829 DHCP_FQDN_FLAG_E
; /* Canonical wire format */
830 buffer
[1] = 0; /* RCODE1 (deprecated) */
831 buffer
[2] = 0; /* RCODE2 (deprecated) */
833 r
= dns_name_to_wire_format(fqdn
, buffer
+ 3, sizeof(buffer
) - 3, false);
835 r
= dhcp_option_append(message
, optlen
, optoffset
, 0,
836 SD_DHCP_OPTION_FQDN
, 3 + r
, buffer
);
841 static int dhcp_client_send_raw(
842 sd_dhcp_client
*client
,
846 dhcp_packet_append_ip_headers(packet
, INADDR_ANY
, client
->port
,
847 INADDR_BROADCAST
, DHCP_PORT_SERVER
, len
, client
->ip_service_type
);
849 return dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
853 static int client_send_discover(sd_dhcp_client
*client
) {
854 _cleanup_free_ DHCPPacket
*discover
= NULL
;
855 size_t optoffset
, optlen
;
861 assert(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_SELECTING
));
863 r
= client_message_init(client
, &discover
, DHCP_DISCOVER
,
864 &optlen
, &optoffset
);
868 /* the client may suggest values for the network address
869 and lease time in the DHCPDISCOVER message. The client may include
870 the ’requested IP address’ option to suggest that a particular IP
871 address be assigned, and may include the ’IP address lease time’
872 option to suggest the lease time it would like.
874 /* RFC7844 section 3:
875 SHOULD NOT contain any other option. */
876 if (!client
->anonymize
&& client
->last_addr
!= INADDR_ANY
) {
877 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
878 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
879 4, &client
->last_addr
);
884 if (client
->hostname
) {
885 /* According to RFC 4702 "clients that send the Client FQDN option in
886 their messages MUST NOT also send the Host Name option". Just send
887 one of the two depending on the hostname type.
889 if (dns_name_is_single_label(client
->hostname
)) {
890 /* it is unclear from RFC 2131 if client should send hostname in
891 DHCPDISCOVER but dhclient does and so we do as well
893 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
894 SD_DHCP_OPTION_HOST_NAME
,
895 strlen(client
->hostname
), client
->hostname
);
897 r
= client_append_fqdn_option(&discover
->dhcp
, optlen
, &optoffset
,
903 if (client
->vendor_class_identifier
) {
904 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
905 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER
,
906 strlen(client
->vendor_class_identifier
),
907 client
->vendor_class_identifier
);
912 if (client
->mudurl
) {
913 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
914 SD_DHCP_OPTION_MUD_URL
,
915 strlen(client
->mudurl
),
921 if (client
->user_class
) {
922 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
923 SD_DHCP_OPTION_USER_CLASS
,
924 strv_length(client
->user_class
),
930 ORDERED_HASHMAP_FOREACH(j
, client
->extra_options
, i
) {
931 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
932 j
->option
, j
->length
, j
->data
);
937 if (!ordered_hashmap_isempty(client
->vendor_options
)) {
938 r
= dhcp_option_append(
939 &discover
->dhcp
, optlen
, &optoffset
, 0,
940 SD_DHCP_OPTION_VENDOR_SPECIFIC
,
941 ordered_hashmap_size(client
->vendor_options
), client
->vendor_options
);
946 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
947 SD_DHCP_OPTION_END
, 0, NULL
);
951 /* We currently ignore:
952 The client SHOULD wait a random time between one and ten seconds to
953 desynchronize the use of DHCP at startup.
955 r
= dhcp_client_send_raw(client
, discover
, sizeof(DHCPPacket
) + optoffset
);
959 log_dhcp_client(client
, "DISCOVER");
964 static int client_send_request(sd_dhcp_client
*client
) {
965 _cleanup_free_ DHCPPacket
*request
= NULL
;
966 size_t optoffset
, optlen
;
971 r
= client_message_init(client
, &request
, DHCP_REQUEST
, &optlen
, &optoffset
);
975 switch (client
->state
) {
976 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
977 SELECTING should be REQUESTING)
980 case DHCP_STATE_REQUESTING
:
981 /* Client inserts the address of the selected server in ’server
982 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
983 filled in with the yiaddr value from the chosen DHCPOFFER.
986 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
987 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
988 4, &client
->lease
->server_address
);
992 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
993 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
994 4, &client
->lease
->address
);
1000 case DHCP_STATE_INIT_REBOOT
:
1001 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1002 option MUST be filled in with client’s notion of its previously
1003 assigned address. ’ciaddr’ MUST be zero.
1005 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1006 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
1007 4, &client
->last_addr
);
1012 case DHCP_STATE_RENEWING
:
1013 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1014 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1015 client’s IP address.
1018 case DHCP_STATE_REBINDING
:
1019 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1020 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1021 client’s IP address.
1023 This message MUST be broadcast to the 0xffffffff IP broadcast address.
1025 request
->dhcp
.ciaddr
= client
->lease
->address
;
1029 case DHCP_STATE_INIT
:
1030 case DHCP_STATE_SELECTING
:
1031 case DHCP_STATE_REBOOTING
:
1032 case DHCP_STATE_BOUND
:
1033 case DHCP_STATE_STOPPED
:
1037 if (client
->hostname
) {
1038 if (dns_name_is_single_label(client
->hostname
))
1039 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1040 SD_DHCP_OPTION_HOST_NAME
,
1041 strlen(client
->hostname
), client
->hostname
);
1043 r
= client_append_fqdn_option(&request
->dhcp
, optlen
, &optoffset
,
1049 if (client
->vendor_class_identifier
) {
1050 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1051 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER
,
1052 strlen(client
->vendor_class_identifier
),
1053 client
->vendor_class_identifier
);
1058 if (client
->mudurl
) {
1059 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1060 SD_DHCP_OPTION_MUD_URL
,
1061 strlen(client
->mudurl
),
1068 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
1069 SD_DHCP_OPTION_END
, 0, NULL
);
1073 if (client
->state
== DHCP_STATE_RENEWING
)
1074 r
= dhcp_network_send_udp_socket(client
->fd
,
1075 client
->lease
->server_address
,
1078 sizeof(DHCPMessage
) + optoffset
);
1080 r
= dhcp_client_send_raw(client
, request
, sizeof(DHCPPacket
) + optoffset
);
1084 switch (client
->state
) {
1086 case DHCP_STATE_REQUESTING
:
1087 log_dhcp_client(client
, "REQUEST (requesting)");
1090 case DHCP_STATE_INIT_REBOOT
:
1091 log_dhcp_client(client
, "REQUEST (init-reboot)");
1094 case DHCP_STATE_RENEWING
:
1095 log_dhcp_client(client
, "REQUEST (renewing)");
1098 case DHCP_STATE_REBINDING
:
1099 log_dhcp_client(client
, "REQUEST (rebinding)");
1103 log_dhcp_client(client
, "REQUEST (invalid)");
1110 static int client_start(sd_dhcp_client
*client
);
1112 static int client_timeout_resend(
1117 sd_dhcp_client
*client
= userdata
;
1118 DHCP_CLIENT_DONT_DESTROY(client
);
1119 usec_t next_timeout
= 0;
1126 assert(client
->event
);
1128 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
1132 switch (client
->state
) {
1134 case DHCP_STATE_RENEWING
:
1136 time_left
= (client
->lease
->t2
- client
->lease
->t1
) / 2;
1140 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
1144 case DHCP_STATE_REBINDING
:
1146 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
) / 2;
1150 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
1153 case DHCP_STATE_REBOOTING
:
1154 /* start over as we did not receive a timely ack or nak */
1155 r
= client_initialize(client
);
1159 r
= client_start(client
);
1163 log_dhcp_client(client
, "REBOOTED");
1167 case DHCP_STATE_INIT
:
1168 case DHCP_STATE_INIT_REBOOT
:
1169 case DHCP_STATE_SELECTING
:
1170 case DHCP_STATE_REQUESTING
:
1171 case DHCP_STATE_BOUND
:
1173 if (client
->attempt
< client
->max_attempts
)
1178 next_timeout
= time_now
+ ((UINT64_C(1) << MIN(client
->attempt
, (uint64_t) 6)) - 1) * USEC_PER_SEC
;
1182 case DHCP_STATE_STOPPED
:
1187 next_timeout
+= (random_u32() & 0x1fffff);
1189 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1190 clock_boottime_or_monotonic(),
1191 next_timeout
, 10 * USEC_PER_MSEC
,
1192 client_timeout_resend
, client
,
1193 client
->event_priority
, "dhcp4-resend-timer", true);
1197 switch (client
->state
) {
1198 case DHCP_STATE_INIT
:
1199 r
= client_send_discover(client
);
1201 client
->state
= DHCP_STATE_SELECTING
;
1202 client
->attempt
= 0;
1203 } else if (client
->attempt
>= client
->max_attempts
)
1208 case DHCP_STATE_SELECTING
:
1209 r
= client_send_discover(client
);
1210 if (r
< 0 && client
->attempt
>= client
->max_attempts
)
1215 case DHCP_STATE_INIT_REBOOT
:
1216 case DHCP_STATE_REQUESTING
:
1217 case DHCP_STATE_RENEWING
:
1218 case DHCP_STATE_REBINDING
:
1219 r
= client_send_request(client
);
1220 if (r
< 0 && client
->attempt
>= client
->max_attempts
)
1223 if (client
->state
== DHCP_STATE_INIT_REBOOT
)
1224 client
->state
= DHCP_STATE_REBOOTING
;
1226 client
->request_sent
= time_now
;
1230 case DHCP_STATE_REBOOTING
:
1231 case DHCP_STATE_BOUND
:
1235 case DHCP_STATE_STOPPED
:
1243 client_stop(client
, r
);
1245 /* Errors were dealt with when stopping the client, don't spill
1246 errors into the event loop handler */
1250 static int client_initialize_io_events(
1251 sd_dhcp_client
*client
,
1252 sd_event_io_handler_t io_callback
) {
1257 assert(client
->event
);
1259 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
1260 client
->fd
, EPOLLIN
, io_callback
,
1265 r
= sd_event_source_set_priority(client
->receive_message
,
1266 client
->event_priority
);
1270 r
= sd_event_source_set_description(client
->receive_message
, "dhcp4-receive-message");
1276 client_stop(client
, r
);
1281 static int client_initialize_time_events(sd_dhcp_client
*client
) {
1286 assert(client
->event
);
1288 if (client
->start_delay
> 0) {
1289 assert_se(sd_event_now(client
->event
, clock_boottime_or_monotonic(), &usec
) >= 0);
1290 usec
+= client
->start_delay
;
1293 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1294 clock_boottime_or_monotonic(),
1296 client_timeout_resend
, client
,
1297 client
->event_priority
, "dhcp4-resend-timer", true);
1299 client_stop(client
, r
);
1305 static int client_initialize_events(sd_dhcp_client
*client
, sd_event_io_handler_t io_callback
) {
1306 client_initialize_io_events(client
, io_callback
);
1307 client_initialize_time_events(client
);
1312 static int client_start_delayed(sd_dhcp_client
*client
) {
1315 assert_return(client
, -EINVAL
);
1316 assert_return(client
->event
, -EINVAL
);
1317 assert_return(client
->ifindex
> 0, -EINVAL
);
1318 assert_return(client
->fd
< 0, -EBUSY
);
1319 assert_return(client
->xid
== 0, -EINVAL
);
1320 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_INIT_REBOOT
), -EBUSY
);
1322 client
->xid
= random_u32();
1324 r
= dhcp_network_bind_raw_socket(client
->ifindex
, &client
->link
,
1325 client
->xid
, client
->mac_addr
,
1326 client
->mac_addr_len
, client
->arp_type
, client
->port
);
1328 client_stop(client
, r
);
1333 if (IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_INIT_REBOOT
))
1334 client
->start_time
= now(clock_boottime_or_monotonic());
1336 return client_initialize_events(client
, client_receive_message_raw
);
1339 static int client_start(sd_dhcp_client
*client
) {
1340 client
->start_delay
= 0;
1341 return client_start_delayed(client
);
1344 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1345 sd_dhcp_client
*client
= userdata
;
1346 DHCP_CLIENT_DONT_DESTROY(client
);
1348 log_dhcp_client(client
, "EXPIRED");
1350 client_notify(client
, SD_DHCP_CLIENT_EVENT_EXPIRED
);
1352 /* lease was lost, start over if not freed or stopped in callback */
1353 if (client
->state
!= DHCP_STATE_STOPPED
) {
1354 client_initialize(client
);
1355 client_start(client
);
1361 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1362 sd_dhcp_client
*client
= userdata
;
1363 DHCP_CLIENT_DONT_DESTROY(client
);
1368 client
->receive_message
= sd_event_source_unref(client
->receive_message
);
1369 client
->fd
= asynchronous_close(client
->fd
);
1371 client
->state
= DHCP_STATE_REBINDING
;
1372 client
->attempt
= 0;
1374 r
= dhcp_network_bind_raw_socket(client
->ifindex
, &client
->link
,
1375 client
->xid
, client
->mac_addr
,
1376 client
->mac_addr_len
, client
->arp_type
,
1379 client_stop(client
, r
);
1384 return client_initialize_events(client
, client_receive_message_raw
);
1387 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1388 sd_dhcp_client
*client
= userdata
;
1389 DHCP_CLIENT_DONT_DESTROY(client
);
1391 client
->state
= DHCP_STATE_RENEWING
;
1392 client
->attempt
= 0;
1394 return client_initialize_time_events(client
);
1397 static int client_handle_offer(sd_dhcp_client
*client
, DHCPMessage
*offer
, size_t len
) {
1398 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1401 r
= dhcp_lease_new(&lease
);
1405 if (client
->client_id_len
) {
1406 r
= dhcp_lease_set_client_id(lease
,
1407 (uint8_t *) &client
->client_id
,
1408 client
->client_id_len
);
1413 r
= dhcp_option_parse(offer
, len
, dhcp_lease_parse_options
, lease
, NULL
);
1414 if (r
!= DHCP_OFFER
) {
1415 log_dhcp_client(client
, "received message was not an OFFER, ignoring");
1419 lease
->next_server
= offer
->siaddr
;
1420 lease
->address
= offer
->yiaddr
;
1422 if (lease
->address
== 0 ||
1423 lease
->server_address
== 0 ||
1424 lease
->lifetime
== 0) {
1425 log_dhcp_client(client
, "received lease lacks address, server address or lease lifetime, ignoring");
1429 if (!lease
->have_subnet_mask
) {
1430 r
= dhcp_lease_set_default_subnet_mask(lease
);
1432 log_dhcp_client(client
,
1433 "received lease lacks subnet mask, "
1434 "and a fallback one cannot be generated, ignoring");
1439 sd_dhcp_lease_unref(client
->lease
);
1440 client
->lease
= TAKE_PTR(lease
);
1442 if (client_notify(client
, SD_DHCP_CLIENT_EVENT_SELECTING
) < 0)
1445 log_dhcp_client(client
, "OFFER");
1450 static int client_handle_forcerenew(sd_dhcp_client
*client
, DHCPMessage
*force
, size_t len
) {
1453 r
= dhcp_option_parse(force
, len
, NULL
, NULL
, NULL
);
1454 if (r
!= DHCP_FORCERENEW
)
1457 log_dhcp_client(client
, "FORCERENEW");
1462 static bool lease_equal(const sd_dhcp_lease
*a
, const sd_dhcp_lease
*b
) {
1463 if (a
->address
!= b
->address
)
1466 if (a
->subnet_mask
!= b
->subnet_mask
)
1469 if (a
->router_size
!= b
->router_size
)
1472 for (size_t i
= 0; i
< a
->router_size
; i
++)
1473 if (a
->router
[i
].s_addr
!= b
->router
[i
].s_addr
)
1479 static int client_handle_ack(sd_dhcp_client
*client
, DHCPMessage
*ack
, size_t len
) {
1480 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1481 _cleanup_free_
char *error_message
= NULL
;
1484 r
= dhcp_lease_new(&lease
);
1488 if (client
->client_id_len
) {
1489 r
= dhcp_lease_set_client_id(lease
,
1490 (uint8_t *) &client
->client_id
,
1491 client
->client_id_len
);
1496 r
= dhcp_option_parse(ack
, len
, dhcp_lease_parse_options
, lease
, &error_message
);
1497 if (r
== DHCP_NAK
) {
1498 log_dhcp_client(client
, "NAK: %s", strna(error_message
));
1499 return -EADDRNOTAVAIL
;
1502 if (r
!= DHCP_ACK
) {
1503 log_dhcp_client(client
, "received message was not an ACK, ignoring");
1507 lease
->next_server
= ack
->siaddr
;
1509 lease
->address
= ack
->yiaddr
;
1511 if (lease
->address
== INADDR_ANY
||
1512 lease
->server_address
== INADDR_ANY
||
1513 lease
->lifetime
== 0) {
1514 log_dhcp_client(client
, "received lease lacks address, server "
1515 "address or lease lifetime, ignoring");
1519 if (lease
->subnet_mask
== INADDR_ANY
) {
1520 r
= dhcp_lease_set_default_subnet_mask(lease
);
1522 log_dhcp_client(client
,
1523 "received lease lacks subnet mask, "
1524 "and a fallback one cannot be generated, ignoring");
1529 r
= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
;
1530 if (client
->lease
) {
1531 if (lease_equal(client
->lease
, lease
))
1532 r
= SD_DHCP_CLIENT_EVENT_RENEW
;
1534 r
= SD_DHCP_CLIENT_EVENT_IP_CHANGE
;
1536 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
1539 client
->lease
= TAKE_PTR(lease
);
1541 log_dhcp_client(client
, "ACK");
1546 static uint64_t client_compute_timeout(sd_dhcp_client
*client
, uint32_t lifetime
, double factor
) {
1548 assert(client
->request_sent
);
1549 assert(lifetime
> 0);
1556 return client
->request_sent
+ (lifetime
* USEC_PER_SEC
* factor
) +
1557 + (random_u32() & 0x1fffff);
1560 static int client_set_lease_timeouts(sd_dhcp_client
*client
) {
1562 uint64_t lifetime_timeout
;
1563 uint64_t t2_timeout
;
1564 uint64_t t1_timeout
;
1565 char time_string
[FORMAT_TIMESPAN_MAX
];
1569 assert(client
->event
);
1570 assert(client
->lease
);
1571 assert(client
->lease
->lifetime
);
1573 /* don't set timers for infinite leases */
1574 if (client
->lease
->lifetime
== 0xffffffff) {
1575 (void) event_source_disable(client
->timeout_t1
);
1576 (void) event_source_disable(client
->timeout_t2
);
1577 (void) event_source_disable(client
->timeout_expire
);
1582 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
1585 assert(client
->request_sent
<= time_now
);
1587 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1588 lifetime_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 1);
1589 if (client
->lease
->t1
> 0 && client
->lease
->t2
> 0) {
1590 /* both T1 and T2 are given */
1591 if (client
->lease
->t1
< client
->lease
->t2
&&
1592 client
->lease
->t2
< client
->lease
->lifetime
) {
1593 /* they are both valid */
1594 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
1595 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
1598 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1599 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1600 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1601 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1603 } else if (client
->lease
->t2
> 0 && client
->lease
->t2
< client
->lease
->lifetime
) {
1604 /* only T2 is given, and it is valid */
1605 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
1606 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1607 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1608 if (t2_timeout
<= t1_timeout
) {
1609 /* the computed T1 would be invalid, so discard T2 */
1610 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1611 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1613 } else if (client
->lease
->t1
> 0 && client
->lease
->t1
< client
->lease
->lifetime
) {
1614 /* only T1 is given, and it is valid */
1615 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
1616 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1617 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1618 if (t2_timeout
<= t1_timeout
) {
1619 /* the computed T2 would be invalid, so discard T1 */
1620 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1621 client
->lease
->t2
= client
->lease
->lifetime
/ 2;
1624 /* fall back to the default timeouts */
1625 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1626 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1627 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1628 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1631 /* arm lifetime timeout */
1632 r
= event_reset_time(client
->event
, &client
->timeout_expire
,
1633 clock_boottime_or_monotonic(),
1634 lifetime_timeout
, 10 * USEC_PER_MSEC
,
1635 client_timeout_expire
, client
,
1636 client
->event_priority
, "dhcp4-lifetime", true);
1640 log_dhcp_client(client
, "lease expires in %s",
1641 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, lifetime_timeout
- time_now
, USEC_PER_SEC
));
1643 /* don't arm earlier timeouts if this has already expired */
1644 if (lifetime_timeout
<= time_now
)
1647 /* arm T2 timeout */
1648 r
= event_reset_time(client
->event
, &client
->timeout_t2
,
1649 clock_boottime_or_monotonic(),
1650 t2_timeout
, 10 * USEC_PER_MSEC
,
1651 client_timeout_t2
, client
,
1652 client
->event_priority
, "dhcp4-t2-timeout", true);
1656 log_dhcp_client(client
, "T2 expires in %s",
1657 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, t2_timeout
- time_now
, USEC_PER_SEC
));
1659 /* don't arm earlier timeout if this has already expired */
1660 if (t2_timeout
<= time_now
)
1663 /* arm T1 timeout */
1664 r
= event_reset_time(client
->event
, &client
->timeout_t1
,
1665 clock_boottime_or_monotonic(),
1666 t1_timeout
, 10 * USEC_PER_MSEC
,
1667 client_timeout_t1
, client
,
1668 client
->event_priority
, "dhcp4-t1-timer", true);
1672 log_dhcp_client(client
, "T1 expires in %s",
1673 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, t1_timeout
- time_now
, USEC_PER_SEC
));
1678 static int client_handle_message(sd_dhcp_client
*client
, DHCPMessage
*message
, int len
) {
1679 DHCP_CLIENT_DONT_DESTROY(client
);
1680 char time_string
[FORMAT_TIMESPAN_MAX
];
1681 int r
= 0, notify_event
= 0;
1684 assert(client
->event
);
1687 switch (client
->state
) {
1688 case DHCP_STATE_SELECTING
:
1690 r
= client_handle_offer(client
, message
, len
);
1693 client
->state
= DHCP_STATE_REQUESTING
;
1694 client
->attempt
= 0;
1696 r
= event_reset_time(client
->event
, &client
->timeout_resend
,
1697 clock_boottime_or_monotonic(),
1699 client_timeout_resend
, client
,
1700 client
->event_priority
, "dhcp4-resend-timer", true);
1703 } else if (r
== -ENOMSG
)
1704 /* invalid message, let's ignore it */
1709 case DHCP_STATE_REBOOTING
:
1710 case DHCP_STATE_REQUESTING
:
1711 case DHCP_STATE_RENEWING
:
1712 case DHCP_STATE_REBINDING
:
1714 r
= client_handle_ack(client
, message
, len
);
1716 client
->start_delay
= 0;
1717 (void) event_source_disable(client
->timeout_resend
);
1718 client
->receive_message
=
1719 sd_event_source_unref(client
->receive_message
);
1720 client
->fd
= asynchronous_close(client
->fd
);
1722 if (IN_SET(client
->state
, DHCP_STATE_REQUESTING
,
1723 DHCP_STATE_REBOOTING
))
1724 notify_event
= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
;
1725 else if (r
!= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
)
1728 client
->state
= DHCP_STATE_BOUND
;
1729 client
->attempt
= 0;
1731 client
->last_addr
= client
->lease
->address
;
1733 r
= client_set_lease_timeouts(client
);
1735 log_dhcp_client(client
, "could not set lease timeouts");
1739 r
= dhcp_network_bind_udp_socket(client
->ifindex
, client
->lease
->address
, client
->port
, client
->ip_service_type
);
1741 log_dhcp_client(client
, "could not bind UDP socket");
1747 client_initialize_io_events(client
, client_receive_message_udp
);
1750 client_notify(client
, notify_event
);
1751 if (client
->state
== DHCP_STATE_STOPPED
)
1755 } else if (r
== -EADDRNOTAVAIL
) {
1756 /* got a NAK, let's restart the client */
1757 client_notify(client
, SD_DHCP_CLIENT_EVENT_EXPIRED
);
1759 r
= client_initialize(client
);
1763 r
= client_start_delayed(client
);
1767 log_dhcp_client(client
, "REBOOT in %s", format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
1768 client
->start_delay
, USEC_PER_SEC
));
1770 client
->start_delay
= CLAMP(client
->start_delay
* 2,
1771 RESTART_AFTER_NAK_MIN_USEC
, RESTART_AFTER_NAK_MAX_USEC
);
1774 } else if (r
== -ENOMSG
)
1775 /* invalid message, let's ignore it */
1780 case DHCP_STATE_BOUND
:
1781 r
= client_handle_forcerenew(client
, message
, len
);
1783 r
= client_timeout_t1(NULL
, 0, client
);
1786 } else if (r
== -ENOMSG
)
1787 /* invalid message, let's ignore it */
1792 case DHCP_STATE_INIT
:
1793 case DHCP_STATE_INIT_REBOOT
:
1797 case DHCP_STATE_STOPPED
:
1804 client_stop(client
, r
);
1809 static int client_receive_message_udp(
1815 sd_dhcp_client
*client
= userdata
;
1816 _cleanup_free_ DHCPMessage
*message
= NULL
;
1817 const uint8_t *expected_chaddr
= NULL
;
1818 uint8_t expected_hlen
= 0;
1819 ssize_t len
, buflen
;
1824 buflen
= next_datagram_size_fd(fd
);
1825 if (buflen
== -ENETDOWN
) {
1826 /* the link is down. Don't return an error or the I/O event
1827 source will be disconnected and we won't be able to receive
1828 packets again when the link comes back. */
1834 message
= malloc0(buflen
);
1838 len
= recv(fd
, message
, buflen
, 0);
1840 /* see comment above for why we shouldn't error out on ENETDOWN. */
1841 if (IN_SET(errno
, EAGAIN
, EINTR
, ENETDOWN
))
1844 return log_dhcp_client_errno(client
, errno
,
1845 "Could not receive message from UDP socket: %m");
1847 if ((size_t) len
< sizeof(DHCPMessage
)) {
1848 log_dhcp_client(client
, "Too small to be a DHCP message: ignoring");
1852 if (be32toh(message
->magic
) != DHCP_MAGIC_COOKIE
) {
1853 log_dhcp_client(client
, "Not a DHCP message: ignoring");
1857 if (message
->op
!= BOOTREPLY
) {
1858 log_dhcp_client(client
, "Not a BOOTREPLY message: ignoring");
1862 if (message
->htype
!= client
->arp_type
) {
1863 log_dhcp_client(client
, "Packet type does not match client type");
1867 if (client
->arp_type
== ARPHRD_ETHER
) {
1868 expected_hlen
= ETH_ALEN
;
1869 expected_chaddr
= &client
->mac_addr
[0];
1872 if (message
->hlen
!= expected_hlen
) {
1873 log_dhcp_client(client
, "Unexpected packet hlen %d", message
->hlen
);
1877 if (expected_hlen
> 0 && memcmp(&message
->chaddr
[0], expected_chaddr
, expected_hlen
)) {
1878 log_dhcp_client(client
, "Received chaddr does not match expected: ignoring");
1882 if (client
->state
!= DHCP_STATE_BOUND
&&
1883 be32toh(message
->xid
) != client
->xid
) {
1884 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1885 so ignore the xid in this case */
1886 log_dhcp_client(client
, "Received xid (%u) does not match expected (%u): ignoring",
1887 be32toh(message
->xid
), client
->xid
);
1891 return client_handle_message(client
, message
, len
);
1894 static int client_receive_message_raw(
1900 sd_dhcp_client
*client
= userdata
;
1901 _cleanup_free_ DHCPPacket
*packet
= NULL
;
1902 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct tpacket_auxdata
))];
1903 struct iovec iov
= {};
1904 struct msghdr msg
= {
1907 .msg_control
= cmsgbuf
,
1908 .msg_controllen
= sizeof(cmsgbuf
),
1910 struct cmsghdr
*cmsg
;
1911 bool checksum
= true;
1912 ssize_t buflen
, len
;
1918 buflen
= next_datagram_size_fd(fd
);
1919 if (buflen
== -ENETDOWN
)
1924 packet
= malloc0(buflen
);
1928 iov
= IOVEC_MAKE(packet
, buflen
);
1930 len
= recvmsg_safe(fd
, &msg
, 0);
1931 if (IN_SET(len
, -EAGAIN
, -EINTR
, -ENETDOWN
))
1934 return log_dhcp_client_errno(client
, len
,
1935 "Could not receive message from raw socket: %m");
1937 if ((size_t) len
< sizeof(DHCPPacket
))
1940 cmsg
= cmsg_find(&msg
, SOL_PACKET
, PACKET_AUXDATA
, CMSG_LEN(sizeof(struct tpacket_auxdata
)));
1942 struct tpacket_auxdata
*aux
= (struct tpacket_auxdata
*) CMSG_DATA(cmsg
);
1943 checksum
= !(aux
->tp_status
& TP_STATUS_CSUMNOTREADY
);
1946 r
= dhcp_packet_verify_headers(packet
, len
, checksum
, client
->port
);
1950 len
-= DHCP_IP_UDP_SIZE
;
1952 return client_handle_message(client
, &packet
->dhcp
, len
);
1955 int sd_dhcp_client_send_renew(sd_dhcp_client
*client
) {
1956 assert_return(client
, -EINVAL
);
1957 assert_return(client
->fd
>= 0, -EINVAL
);
1959 client
->start_delay
= 0;
1960 client
->attempt
= 1;
1961 client
->state
= DHCP_STATE_RENEWING
;
1963 return client_initialize_time_events(client
);
1966 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
1969 assert_return(client
, -EINVAL
);
1971 r
= client_initialize(client
);
1975 /* RFC7844 section 3.3:
1976 SHOULD perform a complete four-way handshake, starting with a
1977 DHCPDISCOVER, to obtain a new address lease. If the client can
1978 ascertain that this is exactly the same network to which it was
1979 previously connected, and if the link-layer address did not change,
1980 the client MAY issue a DHCPREQUEST to try to reclaim the current
1982 if (client
->last_addr
&& !client
->anonymize
)
1983 client
->state
= DHCP_STATE_INIT_REBOOT
;
1985 r
= client_start(client
);
1987 log_dhcp_client(client
, "STARTED on ifindex %i", client
->ifindex
);
1992 int sd_dhcp_client_send_release(sd_dhcp_client
*client
) {
1993 assert_return(client
, -EINVAL
);
1994 assert_return(client
->state
!= DHCP_STATE_STOPPED
, -ESTALE
);
1995 assert_return(client
->lease
, -EUNATCH
);
1997 _cleanup_free_ DHCPPacket
*release
= NULL
;
1998 size_t optoffset
, optlen
;
2001 r
= client_message_init(client
, &release
, DHCP_RELEASE
, &optlen
, &optoffset
);
2005 /* Fill up release IP and MAC */
2006 release
->dhcp
.ciaddr
= client
->lease
->address
;
2007 memcpy(&release
->dhcp
.chaddr
, &client
->mac_addr
, client
->mac_addr_len
);
2009 r
= dhcp_option_append(&release
->dhcp
, optlen
, &optoffset
, 0,
2010 SD_DHCP_OPTION_END
, 0, NULL
);
2014 r
= dhcp_network_send_udp_socket(client
->fd
,
2015 client
->lease
->server_address
,
2018 sizeof(DHCPMessage
) + optoffset
);
2022 log_dhcp_client(client
, "RELEASE");
2027 int sd_dhcp_client_send_decline(sd_dhcp_client
*client
) {
2028 assert_return(client
, -EINVAL
);
2029 assert_return(client
->state
!= DHCP_STATE_STOPPED
, -ESTALE
);
2030 assert_return(client
->lease
, -EUNATCH
);
2032 _cleanup_free_ DHCPPacket
*release
= NULL
;
2033 size_t optoffset
, optlen
;
2036 r
= client_message_init(client
, &release
, DHCP_DECLINE
, &optlen
, &optoffset
);
2040 release
->dhcp
.ciaddr
= client
->lease
->address
;
2041 memcpy(&release
->dhcp
.chaddr
, &client
->mac_addr
, client
->mac_addr_len
);
2043 r
= dhcp_option_append(&release
->dhcp
, optlen
, &optoffset
, 0,
2044 SD_DHCP_OPTION_END
, 0, NULL
);
2048 r
= dhcp_network_send_udp_socket(client
->fd
,
2049 client
->lease
->server_address
,
2052 sizeof(DHCPMessage
) + optoffset
);
2056 log_dhcp_client(client
, "DECLINE");
2058 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
2060 if (client
->state
!= DHCP_STATE_STOPPED
) {
2061 r
= sd_dhcp_client_start(client
);
2069 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
2070 DHCP_CLIENT_DONT_DESTROY(client
);
2072 assert_return(client
, -EINVAL
);
2074 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
2075 client
->state
= DHCP_STATE_STOPPED
;
2080 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
, int64_t priority
) {
2083 assert_return(client
, -EINVAL
);
2084 assert_return(!client
->event
, -EBUSY
);
2087 client
->event
= sd_event_ref(event
);
2089 r
= sd_event_default(&client
->event
);
2094 client
->event_priority
= priority
;
2099 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
2100 assert_return(client
, -EINVAL
);
2102 client
->event
= sd_event_unref(client
->event
);
2107 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
2108 assert_return(client
, NULL
);
2110 return client
->event
;
2113 static sd_dhcp_client
*dhcp_client_free(sd_dhcp_client
*client
) {
2117 log_dhcp_client(client
, "FREE");
2119 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
2120 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
2121 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
2122 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
2124 client_initialize(client
);
2126 sd_dhcp_client_detach_event(client
);
2128 sd_dhcp_lease_unref(client
->lease
);
2130 free(client
->req_opts
);
2131 free(client
->hostname
);
2132 free(client
->vendor_class_identifier
);
2133 free(client
->mudurl
);
2134 client
->user_class
= strv_free(client
->user_class
);
2135 ordered_hashmap_free(client
->extra_options
);
2136 ordered_hashmap_free(client
->vendor_options
);
2137 return mfree(client
);
2140 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client
, sd_dhcp_client
, dhcp_client_free
);
2142 int sd_dhcp_client_new(sd_dhcp_client
**ret
, int anonymize
) {
2143 assert_return(ret
, -EINVAL
);
2145 _cleanup_(sd_dhcp_client_unrefp
) sd_dhcp_client
*client
= new(sd_dhcp_client
, 1);
2149 *client
= (sd_dhcp_client
) {
2151 .state
= DHCP_STATE_INIT
,
2154 .mtu
= DHCP_DEFAULT_MIN_SIZE
,
2155 .port
= DHCP_PORT_CLIENT
,
2156 .anonymize
= !!anonymize
,
2157 .max_attempts
= (uint64_t) -1,
2158 .ip_service_type
= -1,
2160 /* NOTE: this could be moved to a function. */
2162 client
->req_opts_size
= ELEMENTSOF(default_req_opts_anonymize
);
2163 client
->req_opts
= memdup(default_req_opts_anonymize
, client
->req_opts_size
);
2165 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
2166 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
2168 if (!client
->req_opts
)
2171 *ret
= TAKE_PTR(client
);