1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright (C) 2013 Intel Corporation. All rights reserved.
7 #include <net/ethernet.h>
8 #include <net/if_arp.h>
12 #include <sys/ioctl.h>
13 #include <linux/if_infiniband.h>
15 #include "sd-dhcp-client.h"
17 #include "alloc-util.h"
19 #include "dhcp-identifier.h"
20 #include "dhcp-internal.h"
21 #include "dhcp-lease-internal.h"
22 #include "dhcp-protocol.h"
23 #include "dns-domain.h"
24 #include "hostname-util.h"
25 #include "random-util.h"
26 #include "string-util.h"
30 #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
31 #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
33 #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
34 #define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
36 struct sd_dhcp_client
{
42 sd_event_source
*timeout_resend
;
46 union sockaddr_union link
;
47 sd_event_source
*receive_message
;
48 bool request_broadcast
;
50 size_t req_opts_allocated
;
54 uint8_t mac_addr
[MAX_MAC_ADDR_LEN
];
61 /* 0: Generic (non-LL) (RFC 2132) */
62 uint8_t data
[MAX_CLIENT_ID_LEN
];
65 /* 1: Ethernet Link-Layer (RFC 2132) */
66 uint8_t haddr
[ETH_ALEN
];
69 /* 2 - 254: ARP/Link-Layer (RFC 2132) */
73 /* 255: Node-specific (RFC 4361) */
78 uint8_t data
[MAX_CLIENT_ID_LEN
];
84 char *vendor_class_identifier
;
91 sd_event_source
*timeout_t1
;
92 sd_event_source
*timeout_t2
;
93 sd_event_source
*timeout_expire
;
94 sd_dhcp_client_callback_t callback
;
100 static const uint8_t default_req_opts
[] = {
101 SD_DHCP_OPTION_SUBNET_MASK
,
102 SD_DHCP_OPTION_ROUTER
,
103 SD_DHCP_OPTION_HOST_NAME
,
104 SD_DHCP_OPTION_DOMAIN_NAME
,
105 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
,
108 /* RFC7844 section 3:
109 MAY contain the Parameter Request List option.
111 The client intending to protect its privacy SHOULD only request a
112 minimal number of options in the PRL and SHOULD also randomly shuffle
113 the ordering of option codes in the PRL. If this random ordering
114 cannot be implemented, the client MAY order the option codes in the
115 PRL by option code number (lowest to highest).
117 /* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
118 static const uint8_t default_req_opts_anonymize
[] = {
119 SD_DHCP_OPTION_SUBNET_MASK
, /* 1 */
120 SD_DHCP_OPTION_ROUTER
, /* 3 */
121 SD_DHCP_OPTION_DOMAIN_NAME_SERVER
, /* 6 */
122 SD_DHCP_OPTION_DOMAIN_NAME
, /* 15 */
123 SD_DHCP_OPTION_ROUTER_DISCOVER
, /* 31 */
124 SD_DHCP_OPTION_STATIC_ROUTE
, /* 33 */
125 SD_DHCP_OPTION_VENDOR_SPECIFIC
, /* 43 */
126 SD_DHCP_OPTION_NETBIOS_NAMESERVER
, /* 44 */
127 SD_DHCP_OPTION_NETBIOS_NODETYPE
, /* 46 */
128 SD_DHCP_OPTION_NETBIOS_SCOPE
, /* 47 */
129 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
, /* 121 */
130 SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE
, /* 249 */
131 SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY
, /* 252 */
134 static int client_receive_message_raw(
139 static int client_receive_message_udp(
144 static void client_stop(sd_dhcp_client
*client
, int error
);
146 int sd_dhcp_client_set_callback(
147 sd_dhcp_client
*client
,
148 sd_dhcp_client_callback_t cb
,
151 assert_return(client
, -EINVAL
);
153 client
->callback
= cb
;
154 client
->userdata
= userdata
;
159 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client
*client
, int broadcast
) {
160 assert_return(client
, -EINVAL
);
162 client
->request_broadcast
= !!broadcast
;
167 int sd_dhcp_client_set_request_option(sd_dhcp_client
*client
, uint8_t option
) {
170 assert_return(client
, -EINVAL
);
171 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
), -EBUSY
);
175 case SD_DHCP_OPTION_PAD
:
176 case SD_DHCP_OPTION_OVERLOAD
:
177 case SD_DHCP_OPTION_MESSAGE_TYPE
:
178 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST
:
179 case SD_DHCP_OPTION_END
:
186 for (i
= 0; i
< client
->req_opts_size
; i
++)
187 if (client
->req_opts
[i
] == option
)
190 if (!GREEDY_REALLOC(client
->req_opts
, client
->req_opts_allocated
,
191 client
->req_opts_size
+ 1))
194 client
->req_opts
[client
->req_opts_size
++] = option
;
199 int sd_dhcp_client_set_request_address(
200 sd_dhcp_client
*client
,
201 const struct in_addr
*last_addr
) {
203 assert_return(client
, -EINVAL
);
204 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
), -EBUSY
);
207 client
->last_addr
= last_addr
->s_addr
;
209 client
->last_addr
= INADDR_ANY
;
214 int sd_dhcp_client_set_ifindex(sd_dhcp_client
*client
, int ifindex
) {
216 assert_return(client
, -EINVAL
);
217 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
), -EBUSY
);
218 assert_return(ifindex
> 0, -EINVAL
);
220 client
->ifindex
= ifindex
;
224 int sd_dhcp_client_set_mac(
225 sd_dhcp_client
*client
,
230 DHCP_CLIENT_DONT_DESTROY(client
);
231 bool need_restart
= false;
233 assert_return(client
, -EINVAL
);
234 assert_return(addr
, -EINVAL
);
235 assert_return(addr_len
> 0 && addr_len
<= MAX_MAC_ADDR_LEN
, -EINVAL
);
236 assert_return(arp_type
> 0, -EINVAL
);
238 if (arp_type
== ARPHRD_ETHER
)
239 assert_return(addr_len
== ETH_ALEN
, -EINVAL
);
240 else if (arp_type
== ARPHRD_INFINIBAND
)
241 assert_return(addr_len
== INFINIBAND_ALEN
, -EINVAL
);
245 if (client
->mac_addr_len
== addr_len
&&
246 memcmp(&client
->mac_addr
, addr
, addr_len
) == 0)
249 if (!IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
)) {
250 log_dhcp_client(client
, "Changing MAC address on running DHCP client, restarting");
252 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
255 memcpy(&client
->mac_addr
, addr
, addr_len
);
256 client
->mac_addr_len
= addr_len
;
257 client
->arp_type
= arp_type
;
259 if (need_restart
&& client
->state
!= DHCP_STATE_STOPPED
)
260 sd_dhcp_client_start(client
);
265 int sd_dhcp_client_get_client_id(
266 sd_dhcp_client
*client
,
268 const uint8_t **data
,
271 assert_return(client
, -EINVAL
);
272 assert_return(type
, -EINVAL
);
273 assert_return(data
, -EINVAL
);
274 assert_return(data_len
, -EINVAL
);
279 if (client
->client_id_len
) {
280 *type
= client
->client_id
.type
;
281 *data
= client
->client_id
.raw
.data
;
282 *data_len
= client
->client_id_len
- sizeof(client
->client_id
.type
);
288 int sd_dhcp_client_set_client_id(
289 sd_dhcp_client
*client
,
294 DHCP_CLIENT_DONT_DESTROY(client
);
295 bool need_restart
= false;
297 assert_return(client
, -EINVAL
);
298 assert_return(data
, -EINVAL
);
299 assert_return(data_len
> 0 && data_len
<= MAX_CLIENT_ID_LEN
, -EINVAL
);
304 if (data_len
!= ETH_ALEN
)
308 case ARPHRD_INFINIBAND
:
309 if (data_len
!= INFINIBAND_ALEN
)
317 if (client
->client_id_len
== data_len
+ sizeof(client
->client_id
.type
) &&
318 client
->client_id
.type
== type
&&
319 memcmp(&client
->client_id
.raw
.data
, data
, data_len
) == 0)
322 if (!IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
)) {
323 log_dhcp_client(client
, "Changing client ID on running DHCP "
324 "client, restarting");
326 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
329 client
->client_id
.type
= type
;
330 memcpy(&client
->client_id
.raw
.data
, data
, data_len
);
331 client
->client_id_len
= data_len
+ sizeof (client
->client_id
.type
);
333 if (need_restart
&& client
->state
!= DHCP_STATE_STOPPED
)
334 sd_dhcp_client_start(client
);
340 * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
341 * without further modification. Otherwise, if duid_type is supported, DUID
342 * is set based on that type. Otherwise, an error is returned.
344 static int dhcp_client_set_iaid_duid(
345 sd_dhcp_client
*client
,
352 DHCP_CLIENT_DONT_DESTROY(client
);
356 assert_return(client
, -EINVAL
);
357 assert_return(duid_len
== 0 || duid
!= NULL
, -EINVAL
);
360 r
= dhcp_validate_duid_len(duid_type
, duid_len
);
365 zero(client
->client_id
);
366 client
->client_id
.type
= 255;
369 /* If IAID is not configured, generate it. */
371 r
= dhcp_identifier_set_iaid(client
->ifindex
, client
->mac_addr
,
372 client
->mac_addr_len
,
373 &client
->client_id
.ns
.iaid
);
377 client
->client_id
.ns
.iaid
= htobe32(iaid
);
381 client
->client_id
.ns
.duid
.type
= htobe16(duid_type
);
382 memcpy(&client
->client_id
.ns
.duid
.raw
.data
, duid
, duid_len
);
383 len
= sizeof(client
->client_id
.ns
.duid
.type
) + duid_len
;
384 } else if (duid_type
== DUID_TYPE_EN
) {
385 r
= dhcp_identifier_set_duid_en(&client
->client_id
.ns
.duid
, &len
);
391 client
->client_id_len
= sizeof(client
->client_id
.type
) + len
+
392 (append_iaid
? sizeof(client
->client_id
.ns
.iaid
) : 0);
394 if (!IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_STOPPED
)) {
395 log_dhcp_client(client
, "Configured IAID+DUID, restarting.");
396 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
397 sd_dhcp_client_start(client
);
403 int sd_dhcp_client_set_iaid_duid(
404 sd_dhcp_client
*client
,
409 return dhcp_client_set_iaid_duid(client
, iaid
, true, duid_type
, duid
, duid_len
);
412 int sd_dhcp_client_set_duid(
413 sd_dhcp_client
*client
,
417 return dhcp_client_set_iaid_duid(client
, 0, false, duid_type
, duid
, duid_len
);
420 int sd_dhcp_client_set_hostname(
421 sd_dhcp_client
*client
,
422 const char *hostname
) {
424 assert_return(client
, -EINVAL
);
426 /* Make sure hostnames qualify as DNS and as Linux hostnames */
428 !(hostname_is_valid(hostname
, false) && dns_name_is_valid(hostname
) > 0))
431 return free_and_strdup(&client
->hostname
, hostname
);
434 int sd_dhcp_client_set_vendor_class_identifier(
435 sd_dhcp_client
*client
,
438 assert_return(client
, -EINVAL
);
440 return free_and_strdup(&client
->vendor_class_identifier
, vci
);
443 int sd_dhcp_client_set_user_class(
444 sd_dhcp_client
*client
,
445 const char* const* user_class
) {
447 _cleanup_strv_free_
char **s
= NULL
;
450 STRV_FOREACH(p
, (char **) user_class
)
451 if (strlen(*p
) > 255)
452 return -ENAMETOOLONG
;
454 s
= strv_copy((char **) user_class
);
458 client
->user_class
= TAKE_PTR(s
);
463 int sd_dhcp_client_set_client_port(
464 sd_dhcp_client
*client
,
467 assert_return(client
, -EINVAL
);
474 int sd_dhcp_client_set_mtu(sd_dhcp_client
*client
, uint32_t mtu
) {
475 assert_return(client
, -EINVAL
);
476 assert_return(mtu
>= DHCP_DEFAULT_MIN_SIZE
, -ERANGE
);
483 int sd_dhcp_client_get_lease(sd_dhcp_client
*client
, sd_dhcp_lease
**ret
) {
484 assert_return(client
, -EINVAL
);
486 if (!IN_SET(client
->state
, DHCP_STATE_BOUND
, DHCP_STATE_RENEWING
, DHCP_STATE_REBINDING
))
487 return -EADDRNOTAVAIL
;
490 *ret
= client
->lease
;
495 static void client_notify(sd_dhcp_client
*client
, int event
) {
498 if (client
->callback
)
499 client
->callback(client
, event
, client
->userdata
);
502 static int client_initialize(sd_dhcp_client
*client
) {
503 assert_return(client
, -EINVAL
);
505 client
->receive_message
= sd_event_source_unref(client
->receive_message
);
507 client
->fd
= asynchronous_close(client
->fd
);
509 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
511 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
512 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
513 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
517 client
->state
= DHCP_STATE_INIT
;
520 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
525 static void client_stop(sd_dhcp_client
*client
, int error
) {
529 log_dhcp_client(client
, "STOPPED: %s", strerror(-error
));
530 else if (error
== SD_DHCP_CLIENT_EVENT_STOP
)
531 log_dhcp_client(client
, "STOPPED");
533 log_dhcp_client(client
, "STOPPED: Unknown event");
535 client_notify(client
, error
);
537 client_initialize(client
);
540 static int client_message_init(
541 sd_dhcp_client
*client
,
545 size_t *_optoffset
) {
547 _cleanup_free_ DHCPPacket
*packet
= NULL
;
548 size_t optlen
, optoffset
, size
;
555 assert(client
->start_time
);
559 assert(IN_SET(type
, DHCP_DISCOVER
, DHCP_REQUEST
));
561 optlen
= DHCP_MIN_OPTIONS_SIZE
;
562 size
= sizeof(DHCPPacket
) + optlen
;
564 packet
= malloc0(size
);
568 r
= dhcp_message_init(&packet
->dhcp
, BOOTREQUEST
, client
->xid
, type
,
569 client
->arp_type
, optlen
, &optoffset
);
573 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
574 refuse to issue an DHCP lease if 'secs' is set to zero */
575 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
578 assert(time_now
>= client
->start_time
);
580 /* seconds between sending first and last DISCOVER
581 * must always be strictly positive to deal with broken servers */
582 secs
= ((time_now
- client
->start_time
) / USEC_PER_SEC
) ? : 1;
583 packet
->dhcp
.secs
= htobe16(secs
);
585 /* RFC2132 section 4.1
586 A client that cannot receive unicast IP datagrams until its protocol
587 software has been configured with an IP address SHOULD set the
588 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
589 DHCPREQUEST messages that client sends. The BROADCAST bit will
590 provide a hint to the DHCP server and BOOTP relay agent to broadcast
591 any messages to the client on the client's subnet.
593 Note: some interfaces needs this to be enabled, but some networks
594 needs this to be disabled as broadcasts are filteretd, so this
595 needs to be configurable */
596 if (client
->request_broadcast
|| client
->arp_type
!= ARPHRD_ETHER
)
597 packet
->dhcp
.flags
= htobe16(0x8000);
599 /* RFC2132 section 4.1.1:
600 The client MUST include its hardware address in the ’chaddr’ field, if
601 necessary for delivery of DHCP reply messages. Non-Ethernet
602 interfaces will leave 'chaddr' empty and use the client identifier
603 instead (eg, RFC 4390 section 2.1).
605 if (client
->arp_type
== ARPHRD_ETHER
)
606 memcpy(&packet
->dhcp
.chaddr
, &client
->mac_addr
, ETH_ALEN
);
608 /* If no client identifier exists, construct an RFC 4361-compliant one */
609 if (client
->client_id_len
== 0) {
612 client
->client_id
.type
= 255;
614 r
= dhcp_identifier_set_iaid(client
->ifindex
, client
->mac_addr
, client
->mac_addr_len
, &client
->client_id
.ns
.iaid
);
618 r
= dhcp_identifier_set_duid_en(&client
->client_id
.ns
.duid
, &duid_len
);
622 client
->client_id_len
= sizeof(client
->client_id
.type
) + sizeof(client
->client_id
.ns
.iaid
) + duid_len
;
625 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
626 Identifier option is not set */
627 if (client
->client_id_len
) {
628 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
629 SD_DHCP_OPTION_CLIENT_IDENTIFIER
,
630 client
->client_id_len
,
636 /* RFC2131 section 3.5:
637 in its initial DHCPDISCOVER or DHCPREQUEST message, a
638 client may provide the server with a list of specific
639 parameters the client is interested in. If the client
640 includes a list of parameters in a DHCPDISCOVER message,
641 it MUST include that list in any subsequent DHCPREQUEST
645 /* RFC7844 section 3:
646 MAY contain the Parameter Request List option. */
647 /* NOTE: in case that there would be an option to do not send
648 * any PRL at all, the size should be checked before sending */
649 if (client
->req_opts_size
> 0) {
650 r
= dhcp_option_append(&packet
->dhcp
, optlen
, &optoffset
, 0,
651 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST
,
652 client
->req_opts_size
, client
->req_opts
);
657 /* RFC2131 section 3.5:
658 The client SHOULD include the ’maximum DHCP message size’ option to
659 let the server know how large the server may make its DHCP messages.
661 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
662 than the defined default size unless the Maximum Messge Size option
665 RFC3442 "Requirements to Avoid Sizing Constraints":
666 Because a full routing table can be quite large, the standard 576
667 octet maximum size for a DHCP message may be too short to contain
668 some legitimate Classless Static Route options. Because of this,
669 clients implementing the Classless Static Route option SHOULD send a
670 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
671 stack is capable of receiving larger IP datagrams. In this case, the
672 client SHOULD set the value of this option to at least the MTU of the
673 interface that the client is configuring. The client MAY set the
674 value of this option higher, up to the size of the largest UDP packet
675 it is prepared to accept. (Note that the value specified in the
676 Maximum DHCP Message Size option is the total maximum packet size,
677 including IP and UDP headers.)
679 /* RFC7844 section 3:
680 SHOULD NOT contain any other option. */
681 if (!client
->anonymize
) {
682 max_size
= htobe16(size
);
683 r
= dhcp_option_append(&packet
->dhcp
, client
->mtu
, &optoffset
, 0,
684 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE
,
691 *_optoffset
= optoffset
;
692 *ret
= TAKE_PTR(packet
);
697 static int client_append_fqdn_option(
698 DHCPMessage
*message
,
703 uint8_t buffer
[3 + DHCP_MAX_FQDN_LENGTH
];
706 buffer
[0] = DHCP_FQDN_FLAG_S
| /* Request server to perform A RR DNS updates */
707 DHCP_FQDN_FLAG_E
; /* Canonical wire format */
708 buffer
[1] = 0; /* RCODE1 (deprecated) */
709 buffer
[2] = 0; /* RCODE2 (deprecated) */
711 r
= dns_name_to_wire_format(fqdn
, buffer
+ 3, sizeof(buffer
) - 3, false);
713 r
= dhcp_option_append(message
, optlen
, optoffset
, 0,
714 SD_DHCP_OPTION_FQDN
, 3 + r
, buffer
);
719 static int dhcp_client_send_raw(
720 sd_dhcp_client
*client
,
724 dhcp_packet_append_ip_headers(packet
, INADDR_ANY
, client
->port
,
725 INADDR_BROADCAST
, DHCP_PORT_SERVER
, len
);
727 return dhcp_network_send_raw_socket(client
->fd
, &client
->link
,
731 static int client_send_discover(sd_dhcp_client
*client
) {
732 _cleanup_free_ DHCPPacket
*discover
= NULL
;
733 size_t optoffset
, optlen
;
737 assert(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_SELECTING
));
739 r
= client_message_init(client
, &discover
, DHCP_DISCOVER
,
740 &optlen
, &optoffset
);
744 /* the client may suggest values for the network address
745 and lease time in the DHCPDISCOVER message. The client may include
746 the ’requested IP address’ option to suggest that a particular IP
747 address be assigned, and may include the ’IP address lease time’
748 option to suggest the lease time it would like.
750 if (client
->last_addr
!= INADDR_ANY
) {
751 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
752 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
753 4, &client
->last_addr
);
758 if (client
->hostname
) {
759 /* According to RFC 4702 "clients that send the Client FQDN option in
760 their messages MUST NOT also send the Host Name option". Just send
761 one of the two depending on the hostname type.
763 if (dns_name_is_single_label(client
->hostname
)) {
764 /* it is unclear from RFC 2131 if client should send hostname in
765 DHCPDISCOVER but dhclient does and so we do as well
767 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
768 SD_DHCP_OPTION_HOST_NAME
,
769 strlen(client
->hostname
), client
->hostname
);
771 r
= client_append_fqdn_option(&discover
->dhcp
, optlen
, &optoffset
,
777 if (client
->vendor_class_identifier
) {
778 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
779 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER
,
780 strlen(client
->vendor_class_identifier
),
781 client
->vendor_class_identifier
);
786 if (client
->user_class
) {
787 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
788 SD_DHCP_OPTION_USER_CLASS
,
789 strv_length(client
->user_class
),
795 r
= dhcp_option_append(&discover
->dhcp
, optlen
, &optoffset
, 0,
796 SD_DHCP_OPTION_END
, 0, NULL
);
800 /* We currently ignore:
801 The client SHOULD wait a random time between one and ten seconds to
802 desynchronize the use of DHCP at startup.
804 r
= dhcp_client_send_raw(client
, discover
, sizeof(DHCPPacket
) + optoffset
);
808 log_dhcp_client(client
, "DISCOVER");
813 static int client_send_request(sd_dhcp_client
*client
) {
814 _cleanup_free_ DHCPPacket
*request
= NULL
;
815 size_t optoffset
, optlen
;
820 r
= client_message_init(client
, &request
, DHCP_REQUEST
, &optlen
, &optoffset
);
824 switch (client
->state
) {
825 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
826 SELECTING should be REQUESTING)
829 case DHCP_STATE_REQUESTING
:
830 /* Client inserts the address of the selected server in ’server
831 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
832 filled in with the yiaddr value from the chosen DHCPOFFER.
835 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
836 SD_DHCP_OPTION_SERVER_IDENTIFIER
,
837 4, &client
->lease
->server_address
);
841 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
842 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
843 4, &client
->lease
->address
);
849 case DHCP_STATE_INIT_REBOOT
:
850 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
851 option MUST be filled in with client’s notion of its previously
852 assigned address. ’ciaddr’ MUST be zero.
854 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
855 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS
,
856 4, &client
->last_addr
);
861 case DHCP_STATE_RENEWING
:
862 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
863 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
864 client’s IP address.
867 case DHCP_STATE_REBINDING
:
868 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
869 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
870 client’s IP address.
872 This message MUST be broadcast to the 0xffffffff IP broadcast address.
874 request
->dhcp
.ciaddr
= client
->lease
->address
;
878 case DHCP_STATE_INIT
:
879 case DHCP_STATE_SELECTING
:
880 case DHCP_STATE_REBOOTING
:
881 case DHCP_STATE_BOUND
:
882 case DHCP_STATE_STOPPED
:
886 if (client
->hostname
) {
887 if (dns_name_is_single_label(client
->hostname
))
888 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
889 SD_DHCP_OPTION_HOST_NAME
,
890 strlen(client
->hostname
), client
->hostname
);
892 r
= client_append_fqdn_option(&request
->dhcp
, optlen
, &optoffset
,
898 if (client
->vendor_class_identifier
) {
899 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
900 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER
,
901 strlen(client
->vendor_class_identifier
),
902 client
->vendor_class_identifier
);
907 r
= dhcp_option_append(&request
->dhcp
, optlen
, &optoffset
, 0,
908 SD_DHCP_OPTION_END
, 0, NULL
);
912 if (client
->state
== DHCP_STATE_RENEWING
) {
913 r
= dhcp_network_send_udp_socket(client
->fd
,
914 client
->lease
->server_address
,
917 sizeof(DHCPMessage
) + optoffset
);
919 r
= dhcp_client_send_raw(client
, request
, sizeof(DHCPPacket
) + optoffset
);
924 switch (client
->state
) {
926 case DHCP_STATE_REQUESTING
:
927 log_dhcp_client(client
, "REQUEST (requesting)");
930 case DHCP_STATE_INIT_REBOOT
:
931 log_dhcp_client(client
, "REQUEST (init-reboot)");
934 case DHCP_STATE_RENEWING
:
935 log_dhcp_client(client
, "REQUEST (renewing)");
938 case DHCP_STATE_REBINDING
:
939 log_dhcp_client(client
, "REQUEST (rebinding)");
943 log_dhcp_client(client
, "REQUEST (invalid)");
950 static int client_start(sd_dhcp_client
*client
);
952 static int client_timeout_resend(
957 sd_dhcp_client
*client
= userdata
;
958 DHCP_CLIENT_DONT_DESTROY(client
);
959 usec_t next_timeout
= 0;
966 assert(client
->event
);
968 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
972 switch (client
->state
) {
974 case DHCP_STATE_RENEWING
:
976 time_left
= (client
->lease
->t2
- client
->lease
->t1
) / 2;
980 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
984 case DHCP_STATE_REBINDING
:
986 time_left
= (client
->lease
->lifetime
- client
->lease
->t2
) / 2;
990 next_timeout
= time_now
+ time_left
* USEC_PER_SEC
;
993 case DHCP_STATE_REBOOTING
:
994 /* start over as we did not receive a timely ack or nak */
995 r
= client_initialize(client
);
999 r
= client_start(client
);
1003 log_dhcp_client(client
, "REBOOTED");
1007 case DHCP_STATE_INIT
:
1008 case DHCP_STATE_INIT_REBOOT
:
1009 case DHCP_STATE_SELECTING
:
1010 case DHCP_STATE_REQUESTING
:
1011 case DHCP_STATE_BOUND
:
1013 if (client
->attempt
< 64)
1014 client
->attempt
*= 2;
1016 next_timeout
= time_now
+ (client
->attempt
- 1) * USEC_PER_SEC
;
1020 case DHCP_STATE_STOPPED
:
1025 next_timeout
+= (random_u32() & 0x1fffff);
1027 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
1029 r
= sd_event_add_time(client
->event
,
1030 &client
->timeout_resend
,
1031 clock_boottime_or_monotonic(),
1032 next_timeout
, 10 * USEC_PER_MSEC
,
1033 client_timeout_resend
, client
);
1037 r
= sd_event_source_set_priority(client
->timeout_resend
,
1038 client
->event_priority
);
1042 r
= sd_event_source_set_description(client
->timeout_resend
, "dhcp4-resend-timer");
1046 switch (client
->state
) {
1047 case DHCP_STATE_INIT
:
1048 r
= client_send_discover(client
);
1050 client
->state
= DHCP_STATE_SELECTING
;
1051 client
->attempt
= 1;
1053 if (client
->attempt
>= 64)
1059 case DHCP_STATE_SELECTING
:
1060 r
= client_send_discover(client
);
1061 if (r
< 0 && client
->attempt
>= 64)
1066 case DHCP_STATE_INIT_REBOOT
:
1067 case DHCP_STATE_REQUESTING
:
1068 case DHCP_STATE_RENEWING
:
1069 case DHCP_STATE_REBINDING
:
1070 r
= client_send_request(client
);
1071 if (r
< 0 && client
->attempt
>= 64)
1074 if (client
->state
== DHCP_STATE_INIT_REBOOT
)
1075 client
->state
= DHCP_STATE_REBOOTING
;
1077 client
->request_sent
= time_now
;
1081 case DHCP_STATE_REBOOTING
:
1082 case DHCP_STATE_BOUND
:
1086 case DHCP_STATE_STOPPED
:
1094 client_stop(client
, r
);
1096 /* Errors were dealt with when stopping the client, don't spill
1097 errors into the event loop handler */
1101 static int client_initialize_io_events(
1102 sd_dhcp_client
*client
,
1103 sd_event_io_handler_t io_callback
) {
1108 assert(client
->event
);
1110 r
= sd_event_add_io(client
->event
, &client
->receive_message
,
1111 client
->fd
, EPOLLIN
, io_callback
,
1116 r
= sd_event_source_set_priority(client
->receive_message
,
1117 client
->event_priority
);
1121 r
= sd_event_source_set_description(client
->receive_message
, "dhcp4-receive-message");
1127 client_stop(client
, r
);
1132 static int client_initialize_time_events(sd_dhcp_client
*client
) {
1137 assert(client
->event
);
1139 client
->timeout_resend
= sd_event_source_unref(client
->timeout_resend
);
1141 if (client
->start_delay
) {
1142 assert_se(sd_event_now(client
->event
, clock_boottime_or_monotonic(), &usec
) >= 0);
1143 usec
+= client
->start_delay
;
1146 r
= sd_event_add_time(client
->event
,
1147 &client
->timeout_resend
,
1148 clock_boottime_or_monotonic(),
1150 client_timeout_resend
, client
);
1154 r
= sd_event_source_set_priority(client
->timeout_resend
,
1155 client
->event_priority
);
1159 r
= sd_event_source_set_description(client
->timeout_resend
, "dhcp4-resend-timer");
1165 client_stop(client
, r
);
1171 static int client_initialize_events(sd_dhcp_client
*client
, sd_event_io_handler_t io_callback
) {
1172 client_initialize_io_events(client
, io_callback
);
1173 client_initialize_time_events(client
);
1178 static int client_start_delayed(sd_dhcp_client
*client
) {
1181 assert_return(client
, -EINVAL
);
1182 assert_return(client
->event
, -EINVAL
);
1183 assert_return(client
->ifindex
> 0, -EINVAL
);
1184 assert_return(client
->fd
< 0, -EBUSY
);
1185 assert_return(client
->xid
== 0, -EINVAL
);
1186 assert_return(IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_INIT_REBOOT
), -EBUSY
);
1188 client
->xid
= random_u32();
1190 r
= dhcp_network_bind_raw_socket(client
->ifindex
, &client
->link
,
1191 client
->xid
, client
->mac_addr
,
1192 client
->mac_addr_len
, client
->arp_type
, client
->port
);
1194 client_stop(client
, r
);
1199 if (IN_SET(client
->state
, DHCP_STATE_INIT
, DHCP_STATE_INIT_REBOOT
))
1200 client
->start_time
= now(clock_boottime_or_monotonic());
1202 return client_initialize_events(client
, client_receive_message_raw
);
1205 static int client_start(sd_dhcp_client
*client
) {
1206 client
->start_delay
= 0;
1207 return client_start_delayed(client
);
1210 static int client_timeout_expire(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1211 sd_dhcp_client
*client
= userdata
;
1212 DHCP_CLIENT_DONT_DESTROY(client
);
1214 log_dhcp_client(client
, "EXPIRED");
1216 client_notify(client
, SD_DHCP_CLIENT_EVENT_EXPIRED
);
1218 /* lease was lost, start over if not freed or stopped in callback */
1219 if (client
->state
!= DHCP_STATE_STOPPED
) {
1220 client_initialize(client
);
1221 client_start(client
);
1227 static int client_timeout_t2(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1228 sd_dhcp_client
*client
= userdata
;
1229 DHCP_CLIENT_DONT_DESTROY(client
);
1234 client
->receive_message
= sd_event_source_unref(client
->receive_message
);
1235 client
->fd
= asynchronous_close(client
->fd
);
1237 client
->state
= DHCP_STATE_REBINDING
;
1238 client
->attempt
= 1;
1240 r
= dhcp_network_bind_raw_socket(client
->ifindex
, &client
->link
,
1241 client
->xid
, client
->mac_addr
,
1242 client
->mac_addr_len
, client
->arp_type
,
1245 client_stop(client
, r
);
1250 return client_initialize_events(client
, client_receive_message_raw
);
1253 static int client_timeout_t1(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1254 sd_dhcp_client
*client
= userdata
;
1255 DHCP_CLIENT_DONT_DESTROY(client
);
1257 client
->state
= DHCP_STATE_RENEWING
;
1258 client
->attempt
= 1;
1260 return client_initialize_time_events(client
);
1263 static int client_handle_offer(sd_dhcp_client
*client
, DHCPMessage
*offer
, size_t len
) {
1264 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1267 r
= dhcp_lease_new(&lease
);
1271 if (client
->client_id_len
) {
1272 r
= dhcp_lease_set_client_id(lease
,
1273 (uint8_t *) &client
->client_id
,
1274 client
->client_id_len
);
1279 r
= dhcp_option_parse(offer
, len
, dhcp_lease_parse_options
, lease
, NULL
);
1280 if (r
!= DHCP_OFFER
) {
1281 log_dhcp_client(client
, "received message was not an OFFER, ignoring");
1285 lease
->next_server
= offer
->siaddr
;
1286 lease
->address
= offer
->yiaddr
;
1288 if (lease
->address
== 0 ||
1289 lease
->server_address
== 0 ||
1290 lease
->lifetime
== 0) {
1291 log_dhcp_client(client
, "received lease lacks address, server address or lease lifetime, ignoring");
1295 if (!lease
->have_subnet_mask
) {
1296 r
= dhcp_lease_set_default_subnet_mask(lease
);
1298 log_dhcp_client(client
,
1299 "received lease lacks subnet mask, "
1300 "and a fallback one cannot be generated, ignoring");
1305 sd_dhcp_lease_unref(client
->lease
);
1306 client
->lease
= TAKE_PTR(lease
);
1308 log_dhcp_client(client
, "OFFER");
1313 static int client_handle_forcerenew(sd_dhcp_client
*client
, DHCPMessage
*force
, size_t len
) {
1316 r
= dhcp_option_parse(force
, len
, NULL
, NULL
, NULL
);
1317 if (r
!= DHCP_FORCERENEW
)
1320 log_dhcp_client(client
, "FORCERENEW");
1325 static int client_handle_ack(sd_dhcp_client
*client
, DHCPMessage
*ack
, size_t len
) {
1326 _cleanup_(sd_dhcp_lease_unrefp
) sd_dhcp_lease
*lease
= NULL
;
1327 _cleanup_free_
char *error_message
= NULL
;
1330 r
= dhcp_lease_new(&lease
);
1334 if (client
->client_id_len
) {
1335 r
= dhcp_lease_set_client_id(lease
,
1336 (uint8_t *) &client
->client_id
,
1337 client
->client_id_len
);
1342 r
= dhcp_option_parse(ack
, len
, dhcp_lease_parse_options
, lease
, &error_message
);
1343 if (r
== DHCP_NAK
) {
1344 log_dhcp_client(client
, "NAK: %s", strna(error_message
));
1345 return -EADDRNOTAVAIL
;
1348 if (r
!= DHCP_ACK
) {
1349 log_dhcp_client(client
, "received message was not an ACK, ignoring");
1353 lease
->next_server
= ack
->siaddr
;
1355 lease
->address
= ack
->yiaddr
;
1357 if (lease
->address
== INADDR_ANY
||
1358 lease
->server_address
== INADDR_ANY
||
1359 lease
->lifetime
== 0) {
1360 log_dhcp_client(client
, "received lease lacks address, server "
1361 "address or lease lifetime, ignoring");
1365 if (lease
->subnet_mask
== INADDR_ANY
) {
1366 r
= dhcp_lease_set_default_subnet_mask(lease
);
1368 log_dhcp_client(client
,
1369 "received lease lacks subnet mask, "
1370 "and a fallback one cannot be generated, ignoring");
1375 r
= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
;
1376 if (client
->lease
) {
1377 if (client
->lease
->address
!= lease
->address
||
1378 client
->lease
->subnet_mask
!= lease
->subnet_mask
||
1379 client
->lease
->router
!= lease
->router
) {
1380 r
= SD_DHCP_CLIENT_EVENT_IP_CHANGE
;
1382 r
= SD_DHCP_CLIENT_EVENT_RENEW
;
1384 client
->lease
= sd_dhcp_lease_unref(client
->lease
);
1387 client
->lease
= TAKE_PTR(lease
);
1389 log_dhcp_client(client
, "ACK");
1394 static uint64_t client_compute_timeout(sd_dhcp_client
*client
, uint32_t lifetime
, double factor
) {
1396 assert(client
->request_sent
);
1397 assert(lifetime
> 0);
1404 return client
->request_sent
+ (lifetime
* USEC_PER_SEC
* factor
) +
1405 + (random_u32() & 0x1fffff);
1408 static int client_set_lease_timeouts(sd_dhcp_client
*client
) {
1410 uint64_t lifetime_timeout
;
1411 uint64_t t2_timeout
;
1412 uint64_t t1_timeout
;
1413 char time_string
[FORMAT_TIMESPAN_MAX
];
1417 assert(client
->event
);
1418 assert(client
->lease
);
1419 assert(client
->lease
->lifetime
);
1421 client
->timeout_t1
= sd_event_source_unref(client
->timeout_t1
);
1422 client
->timeout_t2
= sd_event_source_unref(client
->timeout_t2
);
1423 client
->timeout_expire
= sd_event_source_unref(client
->timeout_expire
);
1425 /* don't set timers for infinite leases */
1426 if (client
->lease
->lifetime
== 0xffffffff)
1429 r
= sd_event_now(client
->event
, clock_boottime_or_monotonic(), &time_now
);
1432 assert(client
->request_sent
<= time_now
);
1434 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1435 lifetime_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 1);
1436 if (client
->lease
->t1
> 0 && client
->lease
->t2
> 0) {
1437 /* both T1 and T2 are given */
1438 if (client
->lease
->t1
< client
->lease
->t2
&&
1439 client
->lease
->t2
< client
->lease
->lifetime
) {
1440 /* they are both valid */
1441 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
1442 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
1445 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1446 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1447 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1448 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1450 } else if (client
->lease
->t2
> 0 && client
->lease
->t2
< client
->lease
->lifetime
) {
1451 /* only T2 is given, and it is valid */
1452 t2_timeout
= client_compute_timeout(client
, client
->lease
->t2
, 1);
1453 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1454 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1455 if (t2_timeout
<= t1_timeout
) {
1456 /* the computed T1 would be invalid, so discard T2 */
1457 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1458 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1460 } else if (client
->lease
->t1
> 0 && client
->lease
->t1
< client
->lease
->lifetime
) {
1461 /* only T1 is given, and it is valid */
1462 t1_timeout
= client_compute_timeout(client
, client
->lease
->t1
, 1);
1463 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1464 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1465 if (t2_timeout
<= t1_timeout
) {
1466 /* the computed T2 would be invalid, so discard T1 */
1467 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1468 client
->lease
->t2
= client
->lease
->lifetime
/ 2;
1471 /* fall back to the default timeouts */
1472 t1_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 0.5);
1473 client
->lease
->t1
= client
->lease
->lifetime
/ 2;
1474 t2_timeout
= client_compute_timeout(client
, client
->lease
->lifetime
, 7.0 / 8.0);
1475 client
->lease
->t2
= (client
->lease
->lifetime
* 7) / 8;
1478 /* arm lifetime timeout */
1479 r
= sd_event_add_time(client
->event
, &client
->timeout_expire
,
1480 clock_boottime_or_monotonic(),
1481 lifetime_timeout
, 10 * USEC_PER_MSEC
,
1482 client_timeout_expire
, client
);
1486 r
= sd_event_source_set_priority(client
->timeout_expire
,
1487 client
->event_priority
);
1491 r
= sd_event_source_set_description(client
->timeout_expire
, "dhcp4-lifetime");
1495 log_dhcp_client(client
, "lease expires in %s",
1496 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, lifetime_timeout
- time_now
, USEC_PER_SEC
));
1498 /* don't arm earlier timeouts if this has already expired */
1499 if (lifetime_timeout
<= time_now
)
1502 /* arm T2 timeout */
1503 r
= sd_event_add_time(client
->event
,
1504 &client
->timeout_t2
,
1505 clock_boottime_or_monotonic(),
1508 client_timeout_t2
, client
);
1512 r
= sd_event_source_set_priority(client
->timeout_t2
,
1513 client
->event_priority
);
1517 r
= sd_event_source_set_description(client
->timeout_t2
, "dhcp4-t2-timeout");
1521 log_dhcp_client(client
, "T2 expires in %s",
1522 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, t2_timeout
- time_now
, USEC_PER_SEC
));
1524 /* don't arm earlier timeout if this has already expired */
1525 if (t2_timeout
<= time_now
)
1528 /* arm T1 timeout */
1529 r
= sd_event_add_time(client
->event
,
1530 &client
->timeout_t1
,
1531 clock_boottime_or_monotonic(),
1532 t1_timeout
, 10 * USEC_PER_MSEC
,
1533 client_timeout_t1
, client
);
1537 r
= sd_event_source_set_priority(client
->timeout_t1
,
1538 client
->event_priority
);
1542 r
= sd_event_source_set_description(client
->timeout_t1
, "dhcp4-t1-timer");
1546 log_dhcp_client(client
, "T1 expires in %s",
1547 format_timespan(time_string
, FORMAT_TIMESPAN_MAX
, t1_timeout
- time_now
, USEC_PER_SEC
));
1552 static int client_handle_message(sd_dhcp_client
*client
, DHCPMessage
*message
, int len
) {
1553 DHCP_CLIENT_DONT_DESTROY(client
);
1554 char time_string
[FORMAT_TIMESPAN_MAX
];
1555 int r
= 0, notify_event
= 0;
1558 assert(client
->event
);
1561 switch (client
->state
) {
1562 case DHCP_STATE_SELECTING
:
1564 r
= client_handle_offer(client
, message
, len
);
1567 client
->timeout_resend
=
1568 sd_event_source_unref(client
->timeout_resend
);
1570 client
->state
= DHCP_STATE_REQUESTING
;
1571 client
->attempt
= 1;
1573 r
= sd_event_add_time(client
->event
,
1574 &client
->timeout_resend
,
1575 clock_boottime_or_monotonic(),
1577 client_timeout_resend
, client
);
1581 r
= sd_event_source_set_priority(client
->timeout_resend
,
1582 client
->event_priority
);
1586 r
= sd_event_source_set_description(client
->timeout_resend
, "dhcp4-resend-timer");
1589 } else if (r
== -ENOMSG
)
1590 /* invalid message, let's ignore it */
1595 case DHCP_STATE_REBOOTING
:
1596 case DHCP_STATE_REQUESTING
:
1597 case DHCP_STATE_RENEWING
:
1598 case DHCP_STATE_REBINDING
:
1600 r
= client_handle_ack(client
, message
, len
);
1602 client
->start_delay
= 0;
1603 client
->timeout_resend
=
1604 sd_event_source_unref(client
->timeout_resend
);
1605 client
->receive_message
=
1606 sd_event_source_unref(client
->receive_message
);
1607 client
->fd
= asynchronous_close(client
->fd
);
1609 if (IN_SET(client
->state
, DHCP_STATE_REQUESTING
,
1610 DHCP_STATE_REBOOTING
))
1611 notify_event
= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
;
1612 else if (r
!= SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
)
1615 client
->state
= DHCP_STATE_BOUND
;
1616 client
->attempt
= 1;
1618 client
->last_addr
= client
->lease
->address
;
1620 r
= client_set_lease_timeouts(client
);
1622 log_dhcp_client(client
, "could not set lease timeouts");
1626 r
= dhcp_network_bind_udp_socket(client
->ifindex
, client
->lease
->address
, client
->port
);
1628 log_dhcp_client(client
, "could not bind UDP socket");
1634 client_initialize_io_events(client
, client_receive_message_udp
);
1637 client_notify(client
, notify_event
);
1638 if (client
->state
== DHCP_STATE_STOPPED
)
1642 } else if (r
== -EADDRNOTAVAIL
) {
1643 /* got a NAK, let's restart the client */
1644 client
->timeout_resend
=
1645 sd_event_source_unref(client
->timeout_resend
);
1647 r
= client_initialize(client
);
1651 r
= client_start_delayed(client
);
1655 log_dhcp_client(client
, "REBOOT in %s", format_timespan(time_string
, FORMAT_TIMESPAN_MAX
,
1656 client
->start_delay
, USEC_PER_SEC
));
1658 client
->start_delay
= CLAMP(client
->start_delay
* 2,
1659 RESTART_AFTER_NAK_MIN_USEC
, RESTART_AFTER_NAK_MAX_USEC
);
1662 } else if (r
== -ENOMSG
)
1663 /* invalid message, let's ignore it */
1668 case DHCP_STATE_BOUND
:
1669 r
= client_handle_forcerenew(client
, message
, len
);
1671 r
= client_timeout_t1(NULL
, 0, client
);
1674 } else if (r
== -ENOMSG
)
1675 /* invalid message, let's ignore it */
1680 case DHCP_STATE_INIT
:
1681 case DHCP_STATE_INIT_REBOOT
:
1685 case DHCP_STATE_STOPPED
:
1692 client_stop(client
, r
);
1697 static int client_receive_message_udp(
1703 sd_dhcp_client
*client
= userdata
;
1704 _cleanup_free_ DHCPMessage
*message
= NULL
;
1705 const struct ether_addr zero_mac
= {};
1706 const struct ether_addr
*expected_chaddr
= NULL
;
1707 uint8_t expected_hlen
= 0;
1708 ssize_t len
, buflen
;
1713 buflen
= next_datagram_size_fd(fd
);
1717 message
= malloc0(buflen
);
1721 len
= recv(fd
, message
, buflen
, 0);
1723 if (IN_SET(errno
, EAGAIN
, EINTR
))
1726 return log_dhcp_client_errno(client
, errno
,
1727 "Could not receive message from UDP socket: %m");
1729 if ((size_t) len
< sizeof(DHCPMessage
)) {
1730 log_dhcp_client(client
, "Too small to be a DHCP message: ignoring");
1734 if (be32toh(message
->magic
) != DHCP_MAGIC_COOKIE
) {
1735 log_dhcp_client(client
, "Not a DHCP message: ignoring");
1739 if (message
->op
!= BOOTREPLY
) {
1740 log_dhcp_client(client
, "Not a BOOTREPLY message: ignoring");
1744 if (message
->htype
!= client
->arp_type
) {
1745 log_dhcp_client(client
, "Packet type does not match client type");
1749 if (client
->arp_type
== ARPHRD_ETHER
) {
1750 expected_hlen
= ETH_ALEN
;
1751 expected_chaddr
= (const struct ether_addr
*) &client
->mac_addr
;
1753 /* Non-Ethernet links expect zero chaddr */
1755 expected_chaddr
= &zero_mac
;
1758 if (message
->hlen
!= expected_hlen
) {
1759 log_dhcp_client(client
, "Unexpected packet hlen %d", message
->hlen
);
1763 if (memcmp(&message
->chaddr
[0], expected_chaddr
, ETH_ALEN
)) {
1764 log_dhcp_client(client
, "Received chaddr does not match expected: ignoring");
1768 if (client
->state
!= DHCP_STATE_BOUND
&&
1769 be32toh(message
->xid
) != client
->xid
) {
1770 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1771 so ignore the xid in this case */
1772 log_dhcp_client(client
, "Received xid (%u) does not match expected (%u): ignoring",
1773 be32toh(message
->xid
), client
->xid
);
1777 return client_handle_message(client
, message
, len
);
1780 static int client_receive_message_raw(
1786 sd_dhcp_client
*client
= userdata
;
1787 _cleanup_free_ DHCPPacket
*packet
= NULL
;
1788 uint8_t cmsgbuf
[CMSG_LEN(sizeof(struct tpacket_auxdata
))];
1789 struct iovec iov
= {};
1790 struct msghdr msg
= {
1793 .msg_control
= cmsgbuf
,
1794 .msg_controllen
= sizeof(cmsgbuf
),
1796 struct cmsghdr
*cmsg
;
1797 bool checksum
= true;
1798 ssize_t buflen
, len
;
1804 buflen
= next_datagram_size_fd(fd
);
1808 packet
= malloc0(buflen
);
1812 iov
.iov_base
= packet
;
1813 iov
.iov_len
= buflen
;
1815 len
= recvmsg(fd
, &msg
, 0);
1817 if (IN_SET(errno
, EAGAIN
, EINTR
))
1820 return log_dhcp_client_errno(client
, errno
,
1821 "Could not receive message from raw socket: %m");
1822 } else if ((size_t)len
< sizeof(DHCPPacket
))
1825 CMSG_FOREACH(cmsg
, &msg
) {
1826 if (cmsg
->cmsg_level
== SOL_PACKET
&&
1827 cmsg
->cmsg_type
== PACKET_AUXDATA
&&
1828 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct tpacket_auxdata
))) {
1829 struct tpacket_auxdata
*aux
= (struct tpacket_auxdata
*)CMSG_DATA(cmsg
);
1831 checksum
= !(aux
->tp_status
& TP_STATUS_CSUMNOTREADY
);
1836 r
= dhcp_packet_verify_headers(packet
, len
, checksum
, client
->port
);
1840 len
-= DHCP_IP_UDP_SIZE
;
1842 return client_handle_message(client
, &packet
->dhcp
, len
);
1845 int sd_dhcp_client_start(sd_dhcp_client
*client
) {
1848 assert_return(client
, -EINVAL
);
1850 r
= client_initialize(client
);
1854 /* RFC7844 section 3.3:
1855 SHOULD perform a complete four-way handshake, starting with a
1856 DHCPDISCOVER, to obtain a new address lease. If the client can
1857 ascertain that this is exactly the same network to which it was
1858 previously connected, and if the link-layer address did not change,
1859 the client MAY issue a DHCPREQUEST to try to reclaim the current
1861 if (client
->last_addr
&& !client
->anonymize
)
1862 client
->state
= DHCP_STATE_INIT_REBOOT
;
1864 r
= client_start(client
);
1866 log_dhcp_client(client
, "STARTED on ifindex %i", client
->ifindex
);
1871 int sd_dhcp_client_stop(sd_dhcp_client
*client
) {
1872 DHCP_CLIENT_DONT_DESTROY(client
);
1874 assert_return(client
, -EINVAL
);
1876 client_stop(client
, SD_DHCP_CLIENT_EVENT_STOP
);
1877 client
->state
= DHCP_STATE_STOPPED
;
1882 int sd_dhcp_client_attach_event(sd_dhcp_client
*client
, sd_event
*event
, int64_t priority
) {
1885 assert_return(client
, -EINVAL
);
1886 assert_return(!client
->event
, -EBUSY
);
1889 client
->event
= sd_event_ref(event
);
1891 r
= sd_event_default(&client
->event
);
1896 client
->event_priority
= priority
;
1901 int sd_dhcp_client_detach_event(sd_dhcp_client
*client
) {
1902 assert_return(client
, -EINVAL
);
1904 client
->event
= sd_event_unref(client
->event
);
1909 sd_event
*sd_dhcp_client_get_event(sd_dhcp_client
*client
) {
1910 assert_return(client
, NULL
);
1912 return client
->event
;
1915 sd_dhcp_client
*sd_dhcp_client_ref(sd_dhcp_client
*client
) {
1920 assert(client
->n_ref
>= 1);
1926 sd_dhcp_client
*sd_dhcp_client_unref(sd_dhcp_client
*client
) {
1931 assert(client
->n_ref
>= 1);
1934 if (client
->n_ref
> 0)
1937 log_dhcp_client(client
, "FREE");
1939 client_initialize(client
);
1941 client
->receive_message
= sd_event_source_unref(client
->receive_message
);
1943 sd_dhcp_client_detach_event(client
);
1945 sd_dhcp_lease_unref(client
->lease
);
1947 free(client
->req_opts
);
1948 free(client
->hostname
);
1949 free(client
->vendor_class_identifier
);
1950 client
->user_class
= strv_free(client
->user_class
);
1951 return mfree(client
);
1954 int sd_dhcp_client_new(sd_dhcp_client
**ret
, int anonymize
) {
1955 _cleanup_(sd_dhcp_client_unrefp
) sd_dhcp_client
*client
= NULL
;
1957 assert_return(ret
, -EINVAL
);
1959 client
= new0(sd_dhcp_client
, 1);
1964 client
->state
= DHCP_STATE_INIT
;
1965 client
->ifindex
= -1;
1967 client
->attempt
= 1;
1968 client
->mtu
= DHCP_DEFAULT_MIN_SIZE
;
1969 client
->port
= DHCP_PORT_CLIENT
;
1971 client
->anonymize
= !!anonymize
;
1972 /* NOTE: this could be moved to a function. */
1974 client
->req_opts_size
= ELEMENTSOF(default_req_opts_anonymize
);
1975 client
->req_opts
= memdup(default_req_opts_anonymize
, client
->req_opts_size
);
1977 client
->req_opts_size
= ELEMENTSOF(default_req_opts
);
1978 client
->req_opts
= memdup(default_req_opts
, client
->req_opts_size
);
1980 if (!client
->req_opts
)
1983 *ret
= TAKE_PTR(client
);