]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-client.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
011feef8 2/***
810adae9 3 Copyright © 2013 Intel Corporation. All rights reserved.
011feef8
PF
4***/
5
1cf40697 6#include <linux/if_infiniband.h>
3b7ca119 7#include <net/if_arp.h>
07630cea 8#include <stdio.h>
011feef8 9
07630cea 10#include "sd-dhcp-client.h"
011feef8 11
b5efdb8a 12#include "alloc-util.h"
be615f7c 13#include "device-util.h"
6efa51f8 14#include "dhcp-client-id-internal.h"
8664ded7 15#include "dhcp-client-internal.h"
fe8db0c5 16#include "dhcp-lease-internal.h"
9bcbb614 17#include "dhcp-network.h"
8664ded7
YW
18#include "dhcp-option.h"
19#include "dhcp-packet.h"
23873e25 20#include "dns-domain.h"
5cdf13c7 21#include "errno-util.h"
7e5c25b2 22#include "ether-addr-util.h"
a3fa4287 23#include "event-util.h"
5a8775bb 24#include "fd-util.h"
23873e25 25#include "hostname-util.h"
bd1ae178 26#include "iovec-util.h"
0a970718 27#include "memory-util.h"
61a9fa8f 28#include "network-common.h"
07630cea 29#include "random-util.h"
4081756a 30#include "set.h"
5cdf13c7 31#include "socket-util.h"
4081756a 32#include "sort-util.h"
8320db40 33#include "string-table.h"
07630cea 34#include "string-util.h"
af1c0de0 35#include "strv.h"
3d75a443 36#include "time-util.h"
d11d4a64 37#include "web-util.h"
011feef8 38
dd168445 39#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
76253e73 40
1d1a3e0a
BG
41#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
42#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
43
fb536bc5
ZJS
44#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report
45 * transient failure. */
46
011feef8 47struct sd_dhcp_client {
3733eec3 48 unsigned n_ref;
e5b04c8d 49
011feef8 50 DHCPState state;
d3d8ac2f 51 sd_event *event;
b25ef18b 52 int event_priority;
d3d8ac2f 53 sd_event_source *timeout_resend;
be615f7c 54
2f8e7633 55 int ifindex;
61a9fa8f 56 char *ifname;
be615f7c
YW
57
58 sd_device *dev;
59
8c00042c 60 int fd;
9faed222 61 uint16_t port;
ea932bd3 62 uint16_t server_port;
8c00042c
PF
63 union sockaddr_union link;
64 sd_event_source *receive_message;
f5de5b00 65 bool request_broadcast;
4081756a 66 Set *req_opts;
db3d2358 67 bool anonymize;
808b65a0 68 bool rapid_commit;
3b349af6 69 be32_t last_addr;
7e5c25b2
YW
70 struct hw_addr_data hw_addr;
71 struct hw_addr_data bcast_addr;
76253e73 72 uint16_t arp_type;
00ebe011 73 sd_dhcp_client_id client_id;
4cc7a82c 74 char *hostname;
edb85f0d 75 char *vendor_class_identifier;
d11d4a64 76 char *mudurl;
af1c0de0 77 char **user_class;
324f8187 78 uint32_t mtu;
5fde4d37 79 usec_t fallback_lease_lifetime;
46a66b79 80 uint32_t xid;
d3d8ac2f 81 usec_t start_time;
0c3c5978
DS
82 usec_t t1_time;
83 usec_t t2_time;
84 usec_t expire_time;
6ff84614
AB
85 uint64_t discover_attempt;
86 uint64_t request_attempt;
87 uint64_t max_discover_attempts;
88 uint64_t max_request_attempts;
7354900d
DW
89 OrderedHashmap *extra_options;
90 OrderedHashmap *vendor_options;
51debc1e
PF
91 sd_event_source *timeout_t1;
92 sd_event_source *timeout_t2;
93 sd_event_source *timeout_expire;
a91b888f 94 sd_event_source *timeout_ipv6_only_mode;
45aa74c7 95 sd_dhcp_client_callback_t callback;
751246ee 96 void *userdata;
fd9b7f5b 97 sd_dhcp_client_callback_t state_callback;
98 void *state_userdata;
a6cc569e 99 sd_dhcp_lease *lease;
1d1a3e0a 100 usec_t start_delay;
afe42aef 101 int ip_service_type;
ea577968 102 int socket_priority;
103 bool socket_priority_set;
a91b888f 104 bool ipv6_acquired;
4ad29bad 105 bool bootp;
011feef8
PF
106};
107
108static const uint8_t default_req_opts[] = {
22805d92
BG
109 SD_DHCP_OPTION_SUBNET_MASK,
110 SD_DHCP_OPTION_ROUTER,
111 SD_DHCP_OPTION_HOST_NAME,
112 SD_DHCP_OPTION_DOMAIN_NAME,
113 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
011feef8
PF
114};
115
db3d2358 116/* RFC7844 section 3:
117 MAY contain the Parameter Request List option.
118 RFC7844 section 3.6:
119 The client intending to protect its privacy SHOULD only request a
120 minimal number of options in the PRL and SHOULD also randomly shuffle
121 the ordering of option codes in the PRL. If this random ordering
122 cannot be implemented, the client MAY order the option codes in the
123 PRL by option code number (lowest to highest).
124*/
125/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
126static const uint8_t default_req_opts_anonymize[] = {
75924885
YW
127 SD_DHCP_OPTION_SUBNET_MASK, /* 1 */
128 SD_DHCP_OPTION_ROUTER, /* 3 */
129 SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */
130 SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */
3cb62efe 131 SD_DHCP_OPTION_ROUTER_DISCOVERY, /* 31 */
75924885
YW
132 SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */
133 SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */
3cb62efe
YW
134 SD_DHCP_OPTION_NETBIOS_NAME_SERVER, /* 44 */
135 SD_DHCP_OPTION_NETBIOS_NODE_TYPE, /* 46 */
75924885
YW
136 SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */
137 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */
138 SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */
139 SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */
db3d2358 140};
141
4b558378
ZJS
142static int client_receive_message_raw(
143 sd_event_source *s,
144 int fd,
145 uint32_t revents,
146 void *userdata);
147static int client_receive_message_udp(
148 sd_event_source *s,
149 int fd,
150 uint32_t revents,
151 void *userdata);
574cc928 152static void client_stop(sd_dhcp_client *client, int error);
6ff84614 153static int client_restart(sd_dhcp_client *client);
aba26854 154
fd9b7f5b 155int dhcp_client_set_state_callback(
156 sd_dhcp_client *client,
157 sd_dhcp_client_callback_t cb,
158 void *userdata) {
159
160 assert_return(client, -EINVAL);
161
162 client->state_callback = cb;
163 client->state_userdata = userdata;
164
165 return 0;
166}
167
4b558378
ZJS
168int sd_dhcp_client_set_callback(
169 sd_dhcp_client *client,
170 sd_dhcp_client_callback_t cb,
171 void *userdata) {
45aa74c7 172
751246ee
PF
173 assert_return(client, -EINVAL);
174
45aa74c7 175 client->callback = cb;
751246ee
PF
176 client->userdata = userdata;
177
178 return 0;
179}
180
f5de5b00
TG
181int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
182 assert_return(client, -EINVAL);
11352286 183 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
f5de5b00 184
2f092762 185 client->request_broadcast = broadcast;
f5de5b00
TG
186
187 return 0;
188}
189
5ee482df 190int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
011feef8 191 assert_return(client, -EINVAL);
11352286 192 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
011feef8 193
79893116 194 switch (option) {
a1140666 195
22805d92
BG
196 case SD_DHCP_OPTION_PAD:
197 case SD_DHCP_OPTION_OVERLOAD:
198 case SD_DHCP_OPTION_MESSAGE_TYPE:
199 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
200 case SD_DHCP_OPTION_END:
011feef8
PF
201 return -EINVAL;
202
203 default:
5c9feb2d 204 ;
011feef8
PF
205 }
206
4081756a 207 return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option));
011feef8
PF
208}
209
a91b888f
YW
210static int client_request_contains(sd_dhcp_client *client, uint8_t option) {
211 assert(client);
212
213 return set_contains(client->req_opts, UINT8_TO_PTR(option));
214}
215
4b558378
ZJS
216int sd_dhcp_client_set_request_address(
217 sd_dhcp_client *client,
218 const struct in_addr *last_addr) {
a1140666 219
011feef8 220 assert_return(client, -EINVAL);
11352286 221 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
011feef8
PF
222
223 if (last_addr)
224 client->last_addr = last_addr->s_addr;
225 else
226 client->last_addr = INADDR_ANY;
227
228 return 0;
229}
230
2f8e7633 231int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
2f8e7633 232 assert_return(client, -EINVAL);
11352286 233 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
2f8e7633 234 assert_return(ifindex > 0, -EINVAL);
011feef8 235
2f8e7633 236 client->ifindex = ifindex;
011feef8
PF
237 return 0;
238}
239
61a9fa8f
YW
240int sd_dhcp_client_set_ifname(sd_dhcp_client *client, const char *ifname) {
241 assert_return(client, -EINVAL);
242 assert_return(ifname, -EINVAL);
243
244 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
245 return -EINVAL;
246
247 return free_and_strdup(&client->ifname, ifname);
248}
249
5977b71f
YW
250int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret) {
251 int r;
252
253 assert_return(client, -EINVAL);
61a9fa8f 254
5977b71f
YW
255 r = get_ifname(client->ifindex, &client->ifname);
256 if (r < 0)
257 return r;
258
259 if (ret)
260 *ret = client->ifname;
261
262 return 0;
61a9fa8f
YW
263}
264
4b558378
ZJS
265int sd_dhcp_client_set_mac(
266 sd_dhcp_client *client,
7e5c25b2 267 const uint8_t *hw_addr,
14b66dbc 268 const uint8_t *bcast_addr,
4b558378
ZJS
269 size_t addr_len,
270 uint16_t arp_type) {
271
46a66b79 272 assert_return(client, -EINVAL);
7fddb970 273 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
4bc7a54d
DL
274 assert_return(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND, ARPHRD_RAWIP, ARPHRD_NONE), -EINVAL);
275
276 static const uint8_t default_eth_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
277 default_eth_hwaddr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
278
279 switch (arp_type) {
280 case ARPHRD_RAWIP:
281 case ARPHRD_NONE:
282 /* Linux cellular modem drivers (e.g. qmi_wwan) present a
283 * network interface of type ARPHRD_RAWIP(519) or
284 * ARPHRD_NONE(65534) when in point-to-point mode, but these
285 * are not valid DHCP hardware-type values.
286 *
287 * Apparently, it's best to just pretend that these are ethernet
288 * devices. Other approaches have been tried, but resulted in
289 * incompatibilities with some server software. See
290 * https://lore.kernel.org/netdev/cover.1228948072.git.inaky@linux.intel.com/
291 */
292 arp_type = ARPHRD_ETHER;
293 if (addr_len == 0) {
294 assert_cc(sizeof(default_eth_hwaddr) == ETH_ALEN);
295 assert_cc(sizeof(default_eth_bcast) == ETH_ALEN);
296 hw_addr = default_eth_hwaddr;
297 bcast_addr = default_eth_bcast;
298 addr_len = ETH_ALEN;
299 }
300 break;
301 }
302
7e5c25b2
YW
303 assert_return(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND), -EINVAL);
304 assert_return(hw_addr, -EINVAL);
305 assert_return(addr_len == (arp_type == ARPHRD_ETHER ? ETH_ALEN : INFINIBAND_ALEN), -EINVAL);
46a66b79 306
76253e73 307 client->arp_type = arp_type;
7e5c25b2
YW
308 hw_addr_set(&client->hw_addr, hw_addr, addr_len);
309 hw_addr_set(&client->bcast_addr, bcast_addr, bcast_addr ? addr_len : 0);
76253e73 310
ba6c0fd6
DW
311 return 0;
312}
313
6efa51f8 314int sd_dhcp_client_get_client_id(sd_dhcp_client *client, const sd_dhcp_client_id **ret) {
ba6c0fd6 315 assert_return(client, -EINVAL);
6efa51f8 316 assert_return(ret, -EINVAL);
f04c991a 317
6efa51f8
YW
318 if (!sd_dhcp_client_id_is_set(&client->client_id))
319 return -ENODATA;
f04c991a 320
6efa51f8 321 *ret = &client->client_id;
ba6c0fd6
DW
322 return 0;
323}
324
4b558378
ZJS
325int sd_dhcp_client_set_client_id(
326 sd_dhcp_client *client,
327 uint8_t type,
328 const uint8_t *data,
329 size_t data_len) {
330
ba6c0fd6 331 assert_return(client, -EINVAL);
7fddb970 332 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
ba6c0fd6 333 assert_return(data, -EINVAL);
6efa51f8 334 assert_return(client_id_data_size_is_valid(data_len), -EINVAL);
ba6c0fd6 335
bfda0d0f
TH
336 /* For hardware types, log debug message about unexpected data length.
337 *
338 * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
d7b34e38 339 * the last 8 bytes of the address are stable and suitable to put into
bfda0d0f
TH
340 * the client-id. The caller is advised to account for that. */
341 if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) ||
342 (type == ARPHRD_INFINIBAND && data_len != 8))
f31fa080
ZJS
343 log_dhcp_client(client,
344 "Changing client ID to hardware type %u with unexpected address length %zu",
bfda0d0f
TH
345 type, data_len);
346
6efa51f8 347 return sd_dhcp_client_id_set(&client->client_id, type, data, data_len);
53488ea3
YW
348}
349
97c3506d 350static int dhcp_client_set_iaid_duid(
53488ea3
YW
351 sd_dhcp_client *client,
352 bool iaid_set,
353 uint32_t iaid,
97c3506d 354 sd_dhcp_duid *duid) {
53488ea3 355
53488ea3
YW
356 int r;
357
6efa51f8
YW
358 if (!iaid_set) {
359 r = dhcp_identifier_set_iaid(client->dev, &client->hw_addr,
360 /* legacy_unstable_byteorder = */ true,
361 &iaid);
362 if (r < 0)
363 return r;
53488ea3 364
6efa51f8
YW
365 iaid = be32toh(iaid);
366 }
53488ea3 367
6efa51f8 368 return sd_dhcp_client_id_set_iaid_duid(&client->client_id, iaid, duid);
97c3506d
YW
369}
370
371int sd_dhcp_client_set_iaid_duid_llt(
372 sd_dhcp_client *client,
373 bool iaid_set,
374 uint32_t iaid,
375 usec_t llt_time) {
413708d1 376
97c3506d
YW
377 sd_dhcp_duid duid;
378 int r;
413708d1 379
97c3506d
YW
380 assert_return(client, -EINVAL);
381 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
382
383 r = sd_dhcp_duid_set_llt(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time);
384 if (r < 0)
385 return r;
386
387 return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
413708d1
VK
388}
389
53488ea3 390int sd_dhcp_client_set_iaid_duid_ll(
dace710c 391 sd_dhcp_client *client,
8217ed5e 392 bool iaid_set,
53488ea3
YW
393 uint32_t iaid) {
394
97c3506d 395 sd_dhcp_duid duid;
53488ea3
YW
396 int r;
397
398 assert_return(client, -EINVAL);
399 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
400
97c3506d 401 r = sd_dhcp_duid_set_ll(&duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type);
53488ea3
YW
402 if (r < 0)
403 return r;
404
97c3506d 405 return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
7e90a499
YW
406}
407
53488ea3
YW
408int sd_dhcp_client_set_iaid_duid_en(
409 sd_dhcp_client *client,
410 bool iaid_set,
411 uint32_t iaid) {
412
97c3506d 413 sd_dhcp_duid duid;
53488ea3
YW
414 int r;
415
416 assert_return(client, -EINVAL);
417 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
418
97c3506d 419 r = sd_dhcp_duid_set_en(&duid);
53488ea3
YW
420 if (r < 0)
421 return r;
422
97c3506d 423 return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
53488ea3
YW
424}
425
426int sd_dhcp_client_set_iaid_duid_uuid(
427 sd_dhcp_client *client,
428 bool iaid_set,
429 uint32_t iaid) {
430
97c3506d 431 sd_dhcp_duid duid;
53488ea3
YW
432 int r;
433
434 assert_return(client, -EINVAL);
435 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
436
97c3506d 437 r = sd_dhcp_duid_set_uuid(&duid);
53488ea3
YW
438 if (r < 0)
439 return r;
440
97c3506d 441 return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
53488ea3
YW
442}
443
444int sd_dhcp_client_set_iaid_duid_raw(
7e90a499 445 sd_dhcp_client *client,
8217ed5e 446 bool iaid_set,
7e90a499 447 uint32_t iaid,
53488ea3 448 uint16_t duid_type,
97c3506d
YW
449 const uint8_t *duid_data,
450 size_t duid_data_len) {
53488ea3 451
97c3506d 452 sd_dhcp_duid duid;
53488ea3
YW
453 int r;
454
455 assert_return(client, -EINVAL);
456 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
97c3506d 457 assert_return(duid_data || duid_data_len == 0, -EINVAL);
53488ea3 458
97c3506d 459 r = sd_dhcp_duid_set(&duid, duid_type, duid_data, duid_data_len);
53488ea3
YW
460 if (r < 0)
461 return r;
462
97c3506d 463 return dhcp_client_set_iaid_duid(client, iaid_set, iaid, &duid);
dace710c
YW
464}
465
808b65a0
RP
466int sd_dhcp_client_set_rapid_commit(sd_dhcp_client *client, bool rapid_commit) {
467 assert_return(client, -EINVAL);
468
469 client->rapid_commit = !client->anonymize && rapid_commit;
470 return 0;
471}
472
4b558378
ZJS
473int sd_dhcp_client_set_hostname(
474 sd_dhcp_client *client,
475 const char *hostname) {
476
4cc7a82c 477 assert_return(client, -EINVAL);
11352286 478 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
4cc7a82c 479
9740eae6 480 /* Make sure hostnames qualify as DNS and as Linux hostnames */
ef8b0084 481 if (hostname &&
52ef5dd7 482 !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0))
23873e25
BG
483 return -EINVAL;
484
ef8b0084 485 return free_and_strdup(&client->hostname, hostname);
4cc7a82c
EY
486}
487
4b558378
ZJS
488int sd_dhcp_client_set_vendor_class_identifier(
489 sd_dhcp_client *client,
490 const char *vci) {
491
edb85f0d 492 assert_return(client, -EINVAL);
11352286 493 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
edb85f0d 494
ef8b0084 495 return free_and_strdup(&client->vendor_class_identifier, vci);
edb85f0d
SS
496}
497
d11d4a64
SS
498int sd_dhcp_client_set_mud_url(
499 sd_dhcp_client *client,
500 const char *mudurl) {
501
502 assert_return(client, -EINVAL);
11352286 503 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
d11d4a64
SS
504 assert_return(mudurl, -EINVAL);
505 assert_return(strlen(mudurl) <= 255, -EINVAL);
506 assert_return(http_url_is_valid(mudurl), -EINVAL);
507
508 return free_and_strdup(&client->mudurl, mudurl);
509}
510
af1c0de0
SS
511int sd_dhcp_client_set_user_class(
512 sd_dhcp_client *client,
e4336c0a 513 char * const *user_class) {
af1c0de0 514
e4336c0a 515 char **s = NULL;
af1c0de0 516
e4336c0a 517 assert_return(client, -EINVAL);
11352286 518 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
e4336c0a
YW
519 assert_return(!strv_isempty(user_class), -EINVAL);
520
521 STRV_FOREACH(p, user_class) {
522 size_t n = strlen(*p);
af1c0de0 523
e4336c0a
YW
524 if (n > 255 || n == 0)
525 return -EINVAL;
526 }
527
528 s = strv_copy(user_class);
af1c0de0
SS
529 if (!s)
530 return -ENOMEM;
531
e4336c0a 532 return strv_free_and_replace(client->user_class, s);
af1c0de0
SS
533}
534
9faed222
SS
535int sd_dhcp_client_set_client_port(
536 sd_dhcp_client *client,
537 uint16_t port) {
538
539 assert_return(client, -EINVAL);
11352286 540 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
9faed222
SS
541
542 client->port = port;
543
544 return 0;
545}
546
ea932bd3
MI
547int sd_dhcp_client_set_port(
548 sd_dhcp_client *client,
549 uint16_t port) {
550
551 assert_return(client, -EINVAL);
552 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
553
554 client->server_port = port;
555
556 return 0;
557}
558
324f8187
TG
559int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
560 assert_return(client, -EINVAL);
4473cd7f 561 assert_return(mtu >= DHCP_MIN_PACKET_SIZE, -ERANGE);
324f8187 562
11352286
YW
563 /* MTU may be changed by the acquired lease. Hence, we cannot require that the client is stopped here.
564 * Please do not add assertion for !sd_dhcp_client_is_running(client) here. */
565
324f8187
TG
566 client->mtu = mtu;
567
568 return 0;
569}
570
715cedfb
SS
571int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
572 assert_return(client, -EINVAL);
11352286 573 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
715cedfb 574
6ff84614 575 client->max_discover_attempts = max_attempts;
715cedfb
SS
576
577 return 0;
578}
579
7354900d 580int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
cb29c156
SS
581 int r;
582
583 assert_return(client, -EINVAL);
11352286 584 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
cb29c156
SS
585 assert_return(v, -EINVAL);
586
ebffea2a 587 r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v);
cb29c156
SS
588 if (r < 0)
589 return r;
590
591 sd_dhcp_option_ref(v);
592 return 0;
593}
594
7354900d
DW
595int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) {
596 int r;
597
598 assert_return(client, -EINVAL);
11352286 599 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
7354900d
DW
600 assert_return(v, -EINVAL);
601
602 r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
603 if (r < 0)
604 return -ENOMEM;
605
606 r = ordered_hashmap_put(client->vendor_options, v, v);
607 if (r < 0)
608 return r;
609
610 sd_dhcp_option_ref(v);
611
612 return 1;
613}
614
a6cc569e 615int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
751246ee 616 assert_return(client, -EINVAL);
751246ee 617
a43f9225 618 if (!client->lease)
a6cc569e 619 return -EADDRNOTAVAIL;
751246ee 620
a1140666
LP
621 if (ret)
622 *ret = client->lease;
4f882b2a
TG
623
624 return 0;
625}
626
afe42aef
SC
627int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
628 assert_return(client, -EINVAL);
11352286 629 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
afe42aef
SC
630
631 client->ip_service_type = type;
632
633 return 0;
634}
635
ea577968 636int sd_dhcp_client_set_socket_priority(sd_dhcp_client *client, int socket_priority) {
637 assert_return(client, -EINVAL);
638 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
639
640 client->socket_priority_set = true;
641 client->socket_priority = socket_priority;
642
643 return 0;
644}
645
5fde4d37 646int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint64_t fallback_lease_lifetime) {
4c0b8d56 647 assert_return(client, -EINVAL);
11352286 648 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
4c0b8d56
SS
649 assert_return(fallback_lease_lifetime > 0, -EINVAL);
650
5fde4d37 651 assert_cc(sizeof(usec_t) == sizeof(uint64_t));
4c0b8d56
SS
652 client->fallback_lease_lifetime = fallback_lease_lifetime;
653
654 return 0;
655}
656
4ad29bad
CF
657int sd_dhcp_client_set_bootp(sd_dhcp_client *client, int bootp) {
658 assert_return(client, -EINVAL);
659 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
660
661 client->bootp = bootp;
662
663 return 0;
664}
665
4502f82b 666static void client_set_state(sd_dhcp_client *client, DHCPState state) {
667 assert(client);
668
669 if (client->state == state)
670 return;
671
8412d4c8 672 log_dhcp_client(client, "State changed: %s -> %s",
673 dhcp_state_to_string(client->state), dhcp_state_to_string(state));
674
4502f82b 675 client->state = state;
fd9b7f5b 676
677 if (client->state_callback)
678 client->state_callback(client, state, client->state_userdata);
679}
680
681int dhcp_client_get_state(sd_dhcp_client *client) {
682 assert_return(client, -EINVAL);
683
684 return client->state;
4502f82b 685}
686
727b5734 687static int client_notify(sd_dhcp_client *client, int event) {
45aa74c7
LP
688 assert(client);
689
690 if (client->callback)
727b5734
SS
691 return client->callback(client, event, client->userdata);
692
693 return 0;
3e3d8f78
PF
694}
695
0f941add 696static int client_initialize(sd_dhcp_client *client) {
bbdf06d9 697 assert_return(client, -EINVAL);
bbdf06d9 698
eb2f7502 699 client->receive_message = sd_event_source_disable_unref(client->receive_message);
8c00042c 700
5a8775bb 701 client->fd = safe_close(client->fd);
8c00042c 702
a3fa4287
YW
703 (void) event_source_disable(client->timeout_resend);
704 (void) event_source_disable(client->timeout_t1);
705 (void) event_source_disable(client->timeout_t2);
706 (void) event_source_disable(client->timeout_expire);
a91b888f 707 (void) event_source_disable(client->timeout_ipv6_only_mode);
51debc1e 708
6ff84614
AB
709 client->discover_attempt = 0;
710 client->request_attempt = 0;
e2dfc79f 711
4502f82b 712 client_set_state(client, DHCP_STATE_STOPPED);
0f941add 713 client->xid = 0;
bbdf06d9 714
0339cd77 715 client->lease = sd_dhcp_lease_unref(client->lease);
8c00042c 716
0f941add
PF
717 return 0;
718}
719
574cc928
TG
720static void client_stop(sd_dhcp_client *client, int error) {
721 assert(client);
e5b19cbe
YW
722 DHCP_CLIENT_DONT_DESTROY(client);
723
724 if (sd_dhcp_client_is_running(client)) {
725 if (error < 0)
726 log_dhcp_client_errno(client, error, "STOPPED: %m");
727 else if (error == SD_DHCP_CLIENT_EVENT_STOP)
728 log_dhcp_client(client, "STOPPED");
729 else
730 log_dhcp_client(client, "STOPPED: Unknown event");
731
732 client_notify(client, error);
733 } else if (error < 0) {
734 log_dhcp_client_errno(client, error, "FAILED: %m");
735 client_notify(client, error);
736 }
ee57a737 737
574cc928 738 client_initialize(client);
bbdf06d9
PF
739}
740
3d75a443
DS
741/* RFC2131 section 4.1:
742 * retransmission delays should include -1 to +1 sec of random 'fuzz'. */
743#define RFC2131_RANDOM_FUZZ \
744 ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC)
745
746/* RFC2131 section 4.1:
747 * for retransmission delays, timeout should start at 4s then double
748 * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added.
749 * This assumes the first call will be using attempt 1. */
816c6ec8 750static usec_t client_compute_request_timeout(uint64_t attempt) {
3d75a443 751 usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC;
816c6ec8 752 return usec_sub_signed(timeout, RFC2131_RANDOM_FUZZ);
3d75a443
DS
753}
754
755/* RFC2131 section 4.4.5:
756 * T1 defaults to (0.5 * duration_of_lease).
757 * T2 defaults to (0.875 * duration_of_lease). */
758#define T1_DEFAULT(lifetime) ((lifetime) / 2)
759#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8)
760
761/* RFC2131 section 4.4.5:
762 * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state)
763 * and one-half of the remaining lease time (in REBINDING state), down to a minimum
764 * of 60 seconds.
765 * Note that while the default T1/T2 initial times do have random 'fuzz' applied,
766 * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */
816c6ec8
YW
767static usec_t client_compute_reacquisition_timeout(usec_t now_usec, usec_t expire) {
768 return MAX(usec_sub_unsigned(expire, now_usec) / 2, 60 * USEC_PER_SEC);
3d75a443
DS
769}
770
4081756a
YW
771static int cmp_uint8(const uint8_t *a, const uint8_t *b) {
772 return CMP(*a, *b);
773}
774
4b558378
ZJS
775static int client_message_init(
776 sd_dhcp_client *client,
4b558378 777 uint8_t type,
556f641f
YW
778 DHCPPacket **ret_packet,
779 size_t *ret_optlen,
780 size_t *ret_optoffset) {
4b558378 781
3587161a 782 _cleanup_free_ DHCPPacket *packet = NULL;
424a8732 783 size_t optlen, optoffset, size;
d8d74ef0
DW
784 usec_t time_now;
785 uint16_t secs;
cf597f65 786 int r;
46a66b79 787
6236f49b 788 assert(client);
0f3ff4ea 789 assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE));
556f641f
YW
790 assert(ret_packet);
791 assert(ret_optlen);
792 assert(ret_optoffset);
0a1b6da8 793
424a8732
TG
794 optlen = DHCP_MIN_OPTIONS_SIZE;
795 size = sizeof(DHCPPacket) + optlen;
796
797 packet = malloc0(size);
798 if (!packet)
799 return -ENOMEM;
4ad29bad
CF
800 if (client->bootp) {
801 /* BOOTP supports options, but only DHCP_OPTION_END is used. The rest of the 64-byte buffer
802 * is set to zero, per RFC1542. Allow for this by initialaizing optoffset to 0. */
803 optoffset = 0;
804 r = bootp_message_init(
805 &packet->dhcp, BOOTREQUEST, client->xid, client->arp_type,
806 client->hw_addr.length, client->hw_addr.bytes);
807 } else
808 r = dhcp_message_init(
809 &packet->dhcp, BOOTREQUEST, client->xid, client->arp_type,
810 client->hw_addr.length, client->hw_addr.bytes,
811 type, optlen, &optoffset);
cf597f65
TG
812 if (r < 0)
813 return r;
46a66b79 814
0a1b6da8
TG
815 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
816 refuse to issue an DHCP lease if 'secs' is set to zero */
ba4e0427 817 r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now);
d8d74ef0
DW
818 if (r < 0)
819 return r;
820 assert(time_now >= client->start_time);
821
822 /* seconds between sending first and last DISCOVER
823 * must always be strictly positive to deal with broken servers */
1da3cb81 824 secs = ((time_now - client->start_time) / USEC_PER_SEC) ?: 1;
d8d74ef0 825 packet->dhcp.secs = htobe16(secs);
0a1b6da8 826
a6508f37 827 /* RFC2131 section 4.1
63a07041
CA
828 A client that cannot receive unicast IP datagrams until its protocol
829 software has been configured with an IP address SHOULD set the
830 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
831 DHCPREQUEST messages that client sends. The BROADCAST bit will
832 provide a hint to the DHCP server and BOOTP relay agent to broadcast
f5de5b00
TG
833 any messages to the client on the client's subnet.
834
835 Note: some interfaces needs this to be enabled, but some networks
836 needs this to be disabled as broadcasts are filteretd, so this
837 needs to be configurable */
76253e73 838 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
f5de5b00 839 packet->dhcp.flags = htobe16(0x8000);
63a07041 840
4ad29bad
CF
841 if (client->bootp) {
842 *ret_optlen = optlen;
843 *ret_optoffset = optoffset;
844 *ret_packet = TAKE_PTR(packet);
845 return 0;
846 }
847
ee57a737 848 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
46a66b79 849 Identifier option is not set */
22e299fc
YW
850 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
851 SD_DHCP_OPTION_CLIENT_IDENTIFIER,
6efa51f8
YW
852 client->client_id.size,
853 client->client_id.raw);
22e299fc
YW
854 if (r < 0)
855 return r;
50d6810e
TG
856
857 /* RFC2131 section 3.5:
858 in its initial DHCPDISCOVER or DHCPREQUEST message, a
859 client may provide the server with a list of specific
860 parameters the client is interested in. If the client
861 includes a list of parameters in a DHCPDISCOVER message,
862 it MUST include that list in any subsequent DHCPREQUEST
863 messages.
864 */
5e77a146 865
866 /* RFC7844 section 3:
867 MAY contain the Parameter Request List option. */
868 /* NOTE: in case that there would be an option to do not send
869 * any PRL at all, the size should be checked before sending */
4081756a
YW
870 if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) {
871 _cleanup_free_ uint8_t *opts = NULL;
872 size_t n_opts, i = 0;
873 void *val;
874
875 n_opts = set_size(client->req_opts);
876 opts = new(uint8_t, n_opts);
877 if (!opts)
878 return -ENOMEM;
879
880 SET_FOREACH(val, client->req_opts)
881 opts[i++] = PTR_TO_UINT8(val);
882 assert(i == n_opts);
883
884 /* For anonymizing the request, let's sort the options. */
885 typesafe_qsort(opts, n_opts, cmp_uint8);
886
5e77a146 887 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
888 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
4081756a 889 n_opts, opts);
5e77a146 890 if (r < 0)
891 return r;
892 }
8a9e7616 893
50d6810e
TG
894 /* RFC2131 section 3.5:
895 The client SHOULD include the ’maximum DHCP message size’ option to
896 let the server know how large the server may make its DHCP messages.
897
898 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
f21f31b2 899 than the defined default size unless the Maximum Message Size option
f131770b 900 is explicitly set
324f8187
TG
901
902 RFC3442 "Requirements to Avoid Sizing Constraints":
903 Because a full routing table can be quite large, the standard 576
904 octet maximum size for a DHCP message may be too short to contain
905 some legitimate Classless Static Route options. Because of this,
906 clients implementing the Classless Static Route option SHOULD send a
907 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
908 stack is capable of receiving larger IP datagrams. In this case, the
909 client SHOULD set the value of this option to at least the MTU of the
910 interface that the client is configuring. The client MAY set the
911 value of this option higher, up to the size of the largest UDP packet
912 it is prepared to accept. (Note that the value specified in the
913 Maximum DHCP Message Size option is the total maximum packet size,
914 including IP and UDP headers.)
50d6810e 915 */
1b41b815 916 /* RFC7844 section 3:
917 SHOULD NOT contain any other option. */
4473cd7f
YW
918 if (!client->anonymize && IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)) {
919 be16_t max_size = htobe16(MIN(client->mtu - DHCP_IP_UDP_SIZE, (uint32_t) UINT16_MAX));
920 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
1b41b815 921 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
922 2, &max_size);
923 if (r < 0)
924 return r;
925 }
46a66b79 926
556f641f
YW
927 *ret_optlen = optlen;
928 *ret_optoffset = optoffset;
929 *ret_packet = TAKE_PTR(packet);
424a8732 930
46a66b79
PF
931 return 0;
932}
933
4b558378
ZJS
934static int client_append_fqdn_option(
935 DHCPMessage *message,
936 size_t optlen,
937 size_t *optoffset,
938 const char *fqdn) {
939
23873e25
BG
940 uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
941 int r;
942
943 buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
944 DHCP_FQDN_FLAG_E; /* Canonical wire format */
945 buffer[1] = 0; /* RCODE1 (deprecated) */
946 buffer[2] = 0; /* RCODE2 (deprecated) */
947
3cd03457 948 r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
23873e25
BG
949 if (r > 0)
950 r = dhcp_option_append(message, optlen, optoffset, 0,
22805d92 951 SD_DHCP_OPTION_FQDN, 3 + r, buffer);
23873e25
BG
952
953 return r;
954}
955
4b558378
ZJS
956static int dhcp_client_send_raw(
957 sd_dhcp_client *client,
958 DHCPPacket *packet,
959 size_t len) {
960
9faed222 961 dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
ea932bd3 962 INADDR_BROADCAST, client->server_port, len, client->ip_service_type);
63edaa62
TG
963
964 return dhcp_network_send_raw_socket(client->fd, &client->link,
965 packet, len);
966}
967
579ca0a2 968static int client_append_common_discover_request_options(sd_dhcp_client *client, DHCPPacket *packet, size_t *optoffset, size_t optlen) {
cb29c156 969 sd_dhcp_option *j;
6236f49b
TG
970 int r;
971
972 assert(client);
46a66b79 973
4cc7a82c 974 if (client->hostname) {
23873e25
BG
975 /* According to RFC 4702 "clients that send the Client FQDN option in
976 their messages MUST NOT also send the Host Name option". Just send
977 one of the two depending on the hostname type.
978 */
dc477e73 979 if (dns_name_is_single_label(client->hostname)) {
23873e25
BG
980 /* it is unclear from RFC 2131 if client should send hostname in
981 DHCPDISCOVER but dhclient does and so we do as well
982 */
579ca0a2 983 r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
22805d92 984 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
985 strlen(client->hostname), client->hostname);
986 } else
579ca0a2 987 r = client_append_fqdn_option(&packet->dhcp, optlen, optoffset,
23873e25 988 client->hostname);
4cc7a82c
EY
989 if (r < 0)
990 return r;
991 }
992
edb85f0d 993 if (client->vendor_class_identifier) {
579ca0a2 994 r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
22805d92 995 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
edb85f0d
SS
996 strlen(client->vendor_class_identifier),
997 client->vendor_class_identifier);
998 if (r < 0)
999 return r;
1000 }
1001
d11d4a64 1002 if (client->mudurl) {
579ca0a2 1003 r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
d11d4a64
SS
1004 SD_DHCP_OPTION_MUD_URL,
1005 strlen(client->mudurl),
1006 client->mudurl);
1007 if (r < 0)
1008 return r;
1009 }
1010
af1c0de0 1011 if (client->user_class) {
579ca0a2 1012 r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
af1c0de0
SS
1013 SD_DHCP_OPTION_USER_CLASS,
1014 strv_length(client->user_class),
1015 client->user_class);
1016 if (r < 0)
1017 return r;
1018 }
1019
90e74a66 1020 ORDERED_HASHMAP_FOREACH(j, client->extra_options) {
579ca0a2 1021 r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
cb29c156
SS
1022 j->option, j->length, j->data);
1023 if (r < 0)
1024 return r;
1025 }
1026
7354900d
DW
1027 if (!ordered_hashmap_isempty(client->vendor_options)) {
1028 r = dhcp_option_append(
579ca0a2 1029 &packet->dhcp, optlen, optoffset, 0,
7354900d
DW
1030 SD_DHCP_OPTION_VENDOR_SPECIFIC,
1031 ordered_hashmap_size(client->vendor_options), client->vendor_options);
1032 if (r < 0)
1033 return r;
1034 }
1035
579ca0a2
SS
1036 return 0;
1037}
1038
4ad29bad 1039static int client_send_dhcp_discover(sd_dhcp_client *client) {
579ca0a2
SS
1040 _cleanup_free_ DHCPPacket *discover = NULL;
1041 size_t optoffset, optlen;
1042 int r;
1043
1044 assert(client);
1045 assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
1046
556f641f 1047 r = client_message_init(client, DHCP_DISCOVER, &discover, &optlen, &optoffset);
579ca0a2
SS
1048 if (r < 0)
1049 return r;
1050
1051 /* the client may suggest values for the network address
1052 and lease time in the DHCPDISCOVER message. The client may include
1053 the ’requested IP address’ option to suggest that a particular IP
1054 address be assigned, and may include the ’IP address lease time’
1055 option to suggest the lease time it would like.
1056 */
1057 /* RFC7844 section 3:
1058 SHOULD NOT contain any other option. */
1059 if (!client->anonymize && client->last_addr != INADDR_ANY) {
1060 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
1061 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
1062 4, &client->last_addr);
1063 if (r < 0)
1064 return r;
1065 }
1066
808b65a0
RP
1067 if (client->rapid_commit) {
1068 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
1069 SD_DHCP_OPTION_RAPID_COMMIT, 0, NULL);
1070 if (r < 0)
1071 return r;
1072 }
1073
579ca0a2
SS
1074 r = client_append_common_discover_request_options(client, discover, &optoffset, optlen);
1075 if (r < 0)
1076 return r;
1077
04b28be1 1078 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 1079 SD_DHCP_OPTION_END, 0, NULL);
f7926298
TA
1080 if (r < 0)
1081 return r;
46a66b79 1082
20b958bf 1083 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
1084 if (r < 0)
1085 return r;
e2dfc79f 1086
ee57a737
TG
1087 log_dhcp_client(client, "DISCOVER");
1088
63edaa62 1089 return 0;
e2dfc79f
PF
1090}
1091
4ad29bad
CF
1092static int client_send_bootp_discover(sd_dhcp_client *client) {
1093 _cleanup_free_ DHCPPacket *discover = NULL;
1094 size_t optoffset, optlen;
1095 int r;
1096
1097 assert(client);
1098 assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
1099
1100 r = client_message_init(client, DHCP_DISCOVER, &discover, &optlen, &optoffset);
1101 if (r < 0)
1102 return r;
1103
1104 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL);
1105 if (r < 0)
1106 return r;
1107
1108 /* RFC1542 section 3.5:
1109 * if the client has no information to communicate to the server, the octet immediately following the
1110 * magic cookie SHOULD be set to the "End" tag (255) and the remaining octets of the 'vend' field
1111 * SHOULD be set to zero.
1112 *
1113 * Use this RFC, along with the fact that some BOOTP servers require a 64-byte vend field, to suggest
1114 * that we always zero and send 64 bytes in the options field. The first four bites are the "magic"
1115 * field, so this only needs to add 60 bytes. */
1116 if (optoffset < 60 && optlen >= 60) {
1117 memzero(&discover->dhcp.options[optoffset], optlen - optoffset);
1118 optoffset = 60;
1119 }
1120
1121 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
1122 if (r < 0)
1123 return r;
1124
1125 log_dhcp_client(client, "DISCOVER");
1126 return 0;
1127}
1128
6236f49b 1129static int client_send_request(sd_dhcp_client *client) {
8186d9dd 1130 _cleanup_free_ DHCPPacket *request = NULL;
424a8732 1131 size_t optoffset, optlen;
6236f49b 1132 int r;
e2dfc79f 1133
a1140666 1134 assert(client);
4ad29bad 1135 assert(!client->bootp);
a1140666 1136
556f641f 1137 r = client_message_init(client, DHCP_REQUEST, &request, &optlen, &optoffset);
6236f49b
TG
1138 if (r < 0)
1139 return r;
46a66b79 1140
8b1243f7 1141 switch (client->state) {
50d6810e
TG
1142 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
1143 SELECTING should be REQUESTING)
1144 */
1145
1146 case DHCP_STATE_REQUESTING:
1147 /* Client inserts the address of the selected server in ’server
1148 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
1149 filled in with the yiaddr value from the chosen DHCPOFFER.
1150 */
8b1243f7 1151
04b28be1 1152 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1153 SD_DHCP_OPTION_SERVER_IDENTIFIER,
50d6810e 1154 4, &client->lease->server_address);
6236f49b
TG
1155 if (r < 0)
1156 return r;
8b1243f7 1157
04b28be1 1158 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1159 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
6236f49b
TG
1160 4, &client->lease->address);
1161 if (r < 0)
1162 return r;
1163
50d6810e
TG
1164 break;
1165
1166 case DHCP_STATE_INIT_REBOOT:
1167 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1168 option MUST be filled in with client’s notion of its previously
1169 assigned address. ’ciaddr’ MUST be zero.
1170 */
04b28be1 1171 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1172 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
50d6810e 1173 4, &client->last_addr);
6236f49b
TG
1174 if (r < 0)
1175 return r;
8b1243f7
PF
1176 break;
1177
8b1243f7 1178 case DHCP_STATE_RENEWING:
50d6810e
TG
1179 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1180 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1181 client’s IP address.
1182 */
1183
8b1243f7 1184 case DHCP_STATE_REBINDING:
50d6810e
TG
1185 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
1186 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
1187 client’s IP address.
1188
1189 This message MUST be broadcast to the 0xffffffff IP broadcast address.
1190 */
1191 request->dhcp.ciaddr = client->lease->address;
8b1243f7
PF
1192
1193 break;
781ca7a1 1194
50d6810e
TG
1195 case DHCP_STATE_INIT:
1196 case DHCP_STATE_SELECTING:
1197 case DHCP_STATE_REBOOTING:
1198 case DHCP_STATE_BOUND:
781ca7a1 1199 case DHCP_STATE_STOPPED:
8412d4c8 1200 default:
781ca7a1 1201 return -EINVAL;
e2dfc79f 1202 }
46a66b79 1203
579ca0a2
SS
1204 r = client_append_common_discover_request_options(client, request, &optoffset, optlen);
1205 if (r < 0)
1206 return r;
d11d4a64 1207
04b28be1 1208 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 1209 SD_DHCP_OPTION_END, 0, NULL);
6236f49b
TG
1210 if (r < 0)
1211 return r;
46a66b79 1212
bdbb98d9 1213 if (client->state == DHCP_STATE_RENEWING)
6236f49b
TG
1214 r = dhcp_network_send_udp_socket(client->fd,
1215 client->lease->server_address,
ea932bd3 1216 client->server_port,
6236f49b 1217 &request->dhcp,
20b958bf 1218 sizeof(DHCPMessage) + optoffset);
bdbb98d9 1219 else
20b958bf 1220 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
1221 if (r < 0)
1222 return r;
46a66b79 1223
998d8047 1224 switch (client->state) {
a1140666 1225
998d8047
TG
1226 case DHCP_STATE_REQUESTING:
1227 log_dhcp_client(client, "REQUEST (requesting)");
1228 break;
a1140666 1229
998d8047
TG
1230 case DHCP_STATE_INIT_REBOOT:
1231 log_dhcp_client(client, "REQUEST (init-reboot)");
1232 break;
a1140666 1233
998d8047
TG
1234 case DHCP_STATE_RENEWING:
1235 log_dhcp_client(client, "REQUEST (renewing)");
1236 break;
a1140666 1237
998d8047
TG
1238 case DHCP_STATE_REBINDING:
1239 log_dhcp_client(client, "REQUEST (rebinding)");
1240 break;
a1140666 1241
998d8047
TG
1242 default:
1243 log_dhcp_client(client, "REQUEST (invalid)");
998d8047 1244 }
ee57a737 1245
63edaa62 1246 return 0;
46a66b79
PF
1247}
1248
7739a40b
TG
1249static int client_start(sd_dhcp_client *client);
1250
4b558378
ZJS
1251static int client_timeout_resend(
1252 sd_event_source *s,
1253 uint64_t usec,
1254 void *userdata) {
1255
99534007 1256 sd_dhcp_client *client = ASSERT_PTR(userdata);
574cc928 1257 DHCP_CLIENT_DONT_DESTROY(client);
5fde4d37 1258 usec_t time_now, next_timeout;
d23c45bf 1259 int r;
b25ef18b
TG
1260
1261 assert(s);
b25ef18b 1262 assert(client->event);
d3d8ac2f 1263
ba4e0427 1264 r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now);
d23c45bf
TG
1265 if (r < 0)
1266 goto error;
1267
aba26854 1268 switch (client->state) {
a1140666 1269
aba26854 1270 case DHCP_STATE_RENEWING:
c24288d2 1271 next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time);
aba26854
PF
1272 break;
1273
3dd71400 1274 case DHCP_STATE_REBINDING:
c24288d2 1275 next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time);
3dd71400
PF
1276 break;
1277
8b1243f7
PF
1278 case DHCP_STATE_REBOOTING:
1279 /* start over as we did not receive a timely ack or nak */
7739a40b 1280 r = client_initialize(client);
eb105b96
TG
1281 if (r < 0)
1282 goto error;
8b1243f7 1283
998d8047
TG
1284 r = client_start(client);
1285 if (r < 0)
1286 goto error;
e4dc0845
ZJS
1287
1288 log_dhcp_client(client, "REBOOTED");
1289 return 0;
7739a40b 1290
aba26854
PF
1291 case DHCP_STATE_INIT:
1292 case DHCP_STATE_INIT_REBOOT:
aba26854 1293 case DHCP_STATE_SELECTING:
6ff84614
AB
1294 if (client->discover_attempt >= client->max_discover_attempts)
1295 goto error;
1296
1297 client->discover_attempt++;
816c6ec8 1298 next_timeout = client_compute_request_timeout(client->discover_attempt);
6ff84614 1299 break;
aba26854
PF
1300 case DHCP_STATE_REQUESTING:
1301 case DHCP_STATE_BOUND:
6ff84614 1302 if (client->request_attempt >= client->max_request_attempts)
8bc17bb3 1303 goto error;
aba26854 1304
6ff84614 1305 client->request_attempt++;
816c6ec8 1306 next_timeout = client_compute_request_timeout(client->request_attempt);
aba26854 1307 break;
781ca7a1
PF
1308
1309 case DHCP_STATE_STOPPED:
1310 r = -EINVAL;
1311 goto error;
1835a8a1
TH
1312
1313 default:
04499a70 1314 assert_not_reached();
aba26854
PF
1315 }
1316
816c6ec8
YW
1317 r = event_reset_time_relative(
1318 client->event, &client->timeout_resend,
1319 CLOCK_BOOTTIME, next_timeout, 10 * USEC_PER_MSEC,
1320 client_timeout_resend, client,
1321 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1322 if (r < 0)
1323 goto error;
1324
e2dfc79f
PF
1325 switch (client->state) {
1326 case DHCP_STATE_INIT:
4ad29bad
CF
1327 if (client->bootp)
1328 r = client_send_bootp_discover(client);
1329 else
1330 r = client_send_dhcp_discover(client);
b25ef18b 1331 if (r >= 0) {
4502f82b 1332 client_set_state(client, DHCP_STATE_SELECTING);
6ff84614
AB
1333 client->discover_attempt = 0;
1334 } else if (client->discover_attempt >= client->max_discover_attempts)
715cedfb 1335 goto error;
e2dfc79f
PF
1336 break;
1337
1338 case DHCP_STATE_SELECTING:
4ad29bad
CF
1339 if (client->bootp)
1340 r = client_send_bootp_discover(client);
1341 else
1342 r = client_send_dhcp_discover(client);
6ff84614 1343 if (r < 0 && client->discover_attempt >= client->max_discover_attempts)
d3d8ac2f 1344 goto error;
e2dfc79f
PF
1345 break;
1346
8b1243f7 1347 case DHCP_STATE_INIT_REBOOT:
e2dfc79f 1348 case DHCP_STATE_REQUESTING:
aba26854 1349 case DHCP_STATE_RENEWING:
3dd71400 1350 case DHCP_STATE_REBINDING:
6236f49b 1351 r = client_send_request(client);
6ff84614 1352 if (r < 0 && client->request_attempt >= client->max_request_attempts)
e2dfc79f 1353 goto error;
d3d8ac2f 1354
8b1243f7 1355 if (client->state == DHCP_STATE_INIT_REBOOT)
4502f82b 1356 client_set_state(client, DHCP_STATE_REBOOTING);
d3d8ac2f
PF
1357 break;
1358
d3d8ac2f 1359 case DHCP_STATE_REBOOTING:
d3d8ac2f 1360 case DHCP_STATE_BOUND:
d3d8ac2f 1361 break;
781ca7a1
PF
1362
1363 case DHCP_STATE_STOPPED:
8412d4c8 1364 default:
781ca7a1
PF
1365 r = -EINVAL;
1366 goto error;
d3d8ac2f
PF
1367 }
1368
6ff84614 1369 if (client->discover_attempt >= TRANSIENT_FAILURE_ATTEMPTS)
fb536bc5
ZJS
1370 client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE);
1371
d3d8ac2f
PF
1372 return 0;
1373
1374error:
6ff84614
AB
1375 /* Avoid REQUEST infinite loop. Per RFC 2131 section 3.1.5: if the client receives
1376 neither a DHCPACK or a DHCPNAK message after employing the retransmission algorithm,
1377 the client reverts to INIT state and restarts the initialization process */
1378 if (client->request_attempt >= client->max_request_attempts) {
1379 log_dhcp_client(client, "Max REQUEST attempts reached. Restarting...");
1380 client_restart(client);
1381 return 0;
1382 }
b25ef18b 1383 client_stop(client, r);
d3d8ac2f
PF
1384
1385 /* Errors were dealt with when stopping the client, don't spill
1386 errors into the event loop handler */
1387 return 0;
1388}
1389
4b558378
ZJS
1390static int client_initialize_io_events(
1391 sd_dhcp_client *client,
1392 sd_event_io_handler_t io_callback) {
1393
6a1cd41e
PF
1394 int r;
1395
b25ef18b
TG
1396 assert(client);
1397 assert(client->event);
1398
151b9b96
LP
1399 r = sd_event_add_io(client->event, &client->receive_message,
1400 client->fd, EPOLLIN, io_callback,
1401 client);
6a1cd41e
PF
1402 if (r < 0)
1403 goto error;
1404
e5002702
TG
1405 r = sd_event_source_set_priority(client->receive_message,
1406 client->event_priority);
b25ef18b
TG
1407 if (r < 0)
1408 goto error;
1409
356779df 1410 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
9021bb9f
TG
1411 if (r < 0)
1412 goto error;
1413
0af03ba5
TG
1414error:
1415 if (r < 0)
1416 client_stop(client, r);
1417
1418 return 0;
1419}
1420
1421static int client_initialize_time_events(sd_dhcp_client *client) {
5fde4d37 1422 usec_t usec = 0;
0af03ba5
TG
1423 int r;
1424
1425 assert(client);
1426 assert(client->event);
1427
a91b888f
YW
1428 (void) event_source_disable(client->timeout_ipv6_only_mode);
1429
bdbb98d9 1430 if (client->start_delay > 0) {
ba4e0427 1431 assert_se(sd_event_now(client->event, CLOCK_BOOTTIME, &usec) >= 0);
5fde4d37 1432 usec = usec_add(usec, client->start_delay);
1d1a3e0a
BG
1433 }
1434
a3fa4287 1435 r = event_reset_time(client->event, &client->timeout_resend,
ba4e0427 1436 CLOCK_BOOTTIME,
a3fa4287
YW
1437 usec, 0,
1438 client_timeout_resend, client,
1439 client->event_priority, "dhcp4-resend-timer", true);
6a1cd41e
PF
1440 if (r < 0)
1441 client_stop(client, r);
1442
1443 return 0;
6a1cd41e
PF
1444}
1445
4b558378 1446static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
0af03ba5
TG
1447 client_initialize_io_events(client, io_callback);
1448 client_initialize_time_events(client);
1449
1450 return 0;
1451}
1452
1d1a3e0a 1453static int client_start_delayed(sd_dhcp_client *client) {
0f941add
PF
1454 int r;
1455
1456 assert_return(client, -EINVAL);
1457 assert_return(client->event, -EINVAL);
2f8e7633 1458 assert_return(client->ifindex > 0, -EINVAL);
0f941add
PF
1459 assert_return(client->fd < 0, -EBUSY);
1460 assert_return(client->xid == 0, -EINVAL);
b2851e8d 1461 assert_return(IN_SET(client->state, DHCP_STATE_STOPPED, DHCP_STATE_INIT_REBOOT), -EBUSY);
0f941add
PF
1462
1463 client->xid = random_u32();
1464
14b66dbc 1465 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
073a1daa 1466 &client->hw_addr, &client->bcast_addr,
ea577968 1467 client->arp_type, client->port,
1468 client->socket_priority_set, client->socket_priority);
0f941add
PF
1469 if (r < 0) {
1470 client_stop(client, r);
1471 return r;
1472 }
0f941add 1473 client->fd = r;
58ec2d3e 1474
b2851e8d
YW
1475 client->start_time = now(CLOCK_BOOTTIME);
1476
1477 if (client->state == DHCP_STATE_STOPPED)
1478 client->state = DHCP_STATE_INIT;
0f941add 1479
0f941add
PF
1480 return client_initialize_events(client, client_receive_message_raw);
1481}
1482
1d1a3e0a
BG
1483static int client_start(sd_dhcp_client *client) {
1484 client->start_delay = 0;
1485 return client_start_delayed(client);
1486}
1487
4b558378 1488static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
751246ee 1489 sd_dhcp_client *client = userdata;
574cc928 1490 DHCP_CLIENT_DONT_DESTROY(client);
751246ee 1491
ee57a737
TG
1492 log_dhcp_client(client, "EXPIRED");
1493
03748142 1494 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
0f941add 1495
781ca7a1 1496 /* lease was lost, start over if not freed or stopped in callback */
574cc928 1497 if (client->state != DHCP_STATE_STOPPED) {
e5b04c8d
PF
1498 client_initialize(client);
1499 client_start(client);
1500 }
751246ee 1501
51debc1e
PF
1502 return 0;
1503}
1504
5ee482df 1505static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
99534007 1506 sd_dhcp_client *client = ASSERT_PTR(userdata);
574cc928 1507 DHCP_CLIENT_DONT_DESTROY(client);
3dd71400
PF
1508 int r;
1509
eb2f7502 1510 client->receive_message = sd_event_source_disable_unref(client->receive_message);
5a8775bb 1511 client->fd = safe_close(client->fd);
3dd71400 1512
4502f82b 1513 client_set_state(client, DHCP_STATE_REBINDING);
6ff84614
AB
1514 client->discover_attempt = 0;
1515 client->request_attempt = 0;
3dd71400 1516
14b66dbc 1517 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
073a1daa 1518 &client->hw_addr, &client->bcast_addr,
ea577968 1519 client->arp_type, client->port,
1520 client->socket_priority_set, client->socket_priority);
3dd71400
PF
1521 if (r < 0) {
1522 client_stop(client, r);
1523 return 0;
1524 }
3dd71400
PF
1525 client->fd = r;
1526
d23c45bf 1527 return client_initialize_events(client, client_receive_message_raw);
51debc1e
PF
1528}
1529
4b558378 1530static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
aba26854 1531 sd_dhcp_client *client = userdata;
574cc928 1532 DHCP_CLIENT_DONT_DESTROY(client);
aba26854 1533
921693a0 1534 if (client->lease)
4502f82b 1535 client_set_state(client, DHCP_STATE_RENEWING);
921693a0 1536 else if (client->state != DHCP_STATE_INIT)
4502f82b 1537 client_set_state(client, DHCP_STATE_INIT_REBOOT);
6ff84614
AB
1538 client->discover_attempt = 0;
1539 client->request_attempt = 0;
aba26854 1540
0af03ba5 1541 return client_initialize_time_events(client);
51debc1e
PF
1542}
1543
4ad29bad 1544static int dhcp_option_parse_and_verify(
f9edbb80
YW
1545 sd_dhcp_client *client,
1546 DHCPMessage *message,
1547 size_t len,
4ad29bad 1548 sd_dhcp_lease *lease) {
f9edbb80 1549
f9edbb80 1550 _cleanup_free_ char *error_message = NULL;
5ee482df 1551 int r;
3e3d8f78 1552
f9edbb80
YW
1553 assert(client);
1554 assert(message);
4ad29bad 1555 assert(lease);
e37f74a6 1556
f9edbb80
YW
1557 r = dhcp_option_parse(message, len, dhcp_lease_parse_options, lease, &error_message);
1558 if (r < 0)
1559 return log_dhcp_client_errno(client, r, "Failed to parse DHCP options, ignoring: %m");
8c00042c 1560
f9edbb80
YW
1561 switch (client->state) {
1562 case DHCP_STATE_SELECTING:
808b65a0
RP
1563 if (r == DHCP_ACK) {
1564 if (!client->rapid_commit)
1565 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
1566 "received unexpected ACK, ignoring.");
1567 if (!lease->rapid_commit)
1568 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
1569 "received rapid ACK without Rapid Commit option, ignoring.");
1570 } else if (r == DHCP_OFFER) {
c4efe0e5
YW
1571 if (lease->rapid_commit) {
1572 /* Some RFC incompliant servers provides an OFFER with a rapid commit option.
1573 * See https://github.com/systemd/systemd/issues/29904.
1574 * Let's support such servers gracefully. */
1575 log_dhcp_client(client, "received OFFER with Rapid Commit option, ignoring.");
1576 lease->rapid_commit = false;
1577 }
808b65a0
RP
1578 if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
1579 lease->lifetime = client->fallback_lease_lifetime;
1580 } else
f9edbb80 1581 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
808b65a0 1582 "received unexpected message, ignoring.");
f9edbb80
YW
1583
1584 break;
1585
1586 case DHCP_STATE_REBOOTING:
1587 case DHCP_STATE_REQUESTING:
1588 case DHCP_STATE_RENEWING:
1589 case DHCP_STATE_REBINDING:
13abd006
APF
1590 if (r == DHCP_NAK) {
1591 if (client->lease && client->lease->server_address != lease->server_address)
1592 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
1593 "NAK from unexpected server, ignoring: %s",
1594 strna(error_message));
f9edbb80
YW
1595 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
1596 "NAK: %s", strna(error_message));
13abd006 1597 }
f9edbb80
YW
1598 if (r != DHCP_ACK)
1599 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
1600 "received message was not an ACK, ignoring.");
1601 break;
1602
1603 default:
1604 assert_not_reached();
1605 }
1606
1607 lease->next_server = message->siaddr;
1608 lease->address = message->yiaddr;
4c0b8d56 1609
0339cd77
LP
1610 if (lease->address == 0 ||
1611 lease->server_address == 0 ||
f31fa080
ZJS
1612 lease->lifetime == 0)
1613 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
f9edbb80 1614 "received lease lacks address, server address or lease lifetime, ignoring.");
9e64dd72 1615
4ad29bad
CF
1616 return 0;
1617}
1618
1619static int bootp_option_parse_and_verify(
1620 sd_dhcp_client *client,
1621 DHCPMessage *message,
1622 size_t len,
1623 sd_dhcp_lease *lease) {
1624
1625 int r;
1626
1627 assert(client);
1628 assert(message);
1629 assert(lease);
1630
1631 r = dhcp_option_parse(message, len, dhcp_lease_parse_options, lease, /* ret_error_message = */ NULL);
1632 if (r == -ENOMSG)
1633 r = DHCP_ACK; /* BOOTP messages don't have a DHCP message type option */
1634 else if (r < 0)
1635 return log_dhcp_client_errno(client, r, "Failed to parse BOOTP options, ignoring: %m");
1636 else
1637 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG), "Received unexpected message, ignoring.");
1638
1639 log_dhcp_client(client, "BOOTP identified, using infinite lease. BOOTP siaddr=(%#x), DHCP Server Identifier=(%#x)",
1640 message->siaddr, lease->server_address);
1641
1642 lease->lifetime = USEC_INFINITY;
1643 lease->address = message->yiaddr;
1644 if (lease->server_address == 0)
1645 lease->server_address = message->siaddr;
1646
1647 /* BOOTP protocol does not have any OFFER and REQUEST process. Hence, it is mostly equivalent to
1648 * Rapid Commit process in DHCP. */
1649 lease->rapid_commit = true;
1650
1651 if (lease->address == 0)
1652 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG), "received lease lacks address, ignoring.");
1653
1654 return 0;
1655}
1656
1657static int client_parse_message(
1658 sd_dhcp_client *client,
1659 DHCPMessage *message,
1660 size_t len,
1661 sd_dhcp_lease **ret) {
1662
1663 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1664 int r;
1665
1666 assert(client);
1667 assert(message);
1668 assert(ret);
1669
1670 r = dhcp_lease_new(&lease);
1671 if (r < 0)
1672 return r;
1673
1674 if (sd_dhcp_client_id_is_set(&client->client_id)) {
1675 r = dhcp_lease_set_client_id(lease, &client->client_id);
1676 if (r < 0)
1677 return r;
1678 }
1679
1680 if (client->bootp)
1681 r = bootp_option_parse_and_verify(client, message, len, lease);
1682 else
1683 r = dhcp_option_parse_and_verify(client, message, len, lease);
1684 if (r < 0)
1685 return r;
1686
8fc72505
YW
1687 r = dhcp_lease_set_default_subnet_mask(lease);
1688 if (r < 0)
1689 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
1690 "received lease lacks subnet mask, and a fallback one cannot be generated, ignoring.");
8c00042c 1691
a91b888f
YW
1692 /* RFC 8925 section 3.2
1693 * If the client did not include the IPv6-Only Preferred option code in the Parameter Request List in
1694 * the DHCPDISCOVER or DHCPREQUEST message, it MUST ignore the IPv6-Only Preferred option in any
1695 * messages received from the server. */
1696 if (lease->ipv6_only_preferred_usec > 0 &&
1697 !client_request_contains(client, SD_DHCP_OPTION_IPV6_ONLY_PREFERRED)) {
1698 log_dhcp_client(client, "Received message with unrequested IPv6-only preferred option, ignoring the option.");
1699 lease->ipv6_only_preferred_usec = 0;
1700 }
1701
f9edbb80
YW
1702 *ret = TAKE_PTR(lease);
1703 return 0;
1704}
1705
905d0ea7 1706static int client_handle_offer_or_rapid_ack(sd_dhcp_client *client, DHCPMessage *message, size_t len, const triple_timestamp *timestamp) {
f9edbb80
YW
1707 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1708 int r;
1709
1710 assert(client);
1711 assert(message);
1712
1713 r = client_parse_message(client, message, len, &lease);
1714 if (r < 0)
1715 return r;
1716
905d0ea7
YW
1717 dhcp_lease_set_timestamp(lease, timestamp);
1718
db849df5 1719 dhcp_lease_unref_and_replace(client->lease, lease);
8c00042c 1720
808b65a0
RP
1721 if (client->lease->rapid_commit) {
1722 log_dhcp_client(client, "ACK");
1723 return SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1724 }
1725
727b5734
SS
1726 if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
1727 return -ENOMSG;
1728
ee57a737 1729 log_dhcp_client(client, "OFFER");
8c00042c 1730 return 0;
8c00042c
PF
1731}
1732
95bd6816
YW
1733static int client_enter_requesting_now(sd_dhcp_client *client) {
1734 assert(client);
1735
1736 client_set_state(client, DHCP_STATE_REQUESTING);
6ff84614
AB
1737 client->discover_attempt = 0;
1738 client->request_attempt = 0;
95bd6816
YW
1739
1740 return event_reset_time(client->event, &client->timeout_resend,
1741 CLOCK_BOOTTIME, 0, 0,
1742 client_timeout_resend, client,
1743 client->event_priority, "dhcp4-resend-timer",
1744 /* force_reset = */ true);
1745}
1746
1747static int client_enter_requesting_delayed(sd_event_source *s, uint64_t usec, void *userdata) {
1748 sd_dhcp_client *client = ASSERT_PTR(userdata);
1749 DHCP_CLIENT_DONT_DESTROY(client);
1750 int r;
1751
1752 r = client_enter_requesting_now(client);
1753 if (r < 0)
1754 client_stop(client, r);
1755
1756 return 0;
1757}
1758
2ff1e230
YW
1759static int client_enter_requesting(sd_dhcp_client *client) {
1760 assert(client);
a91b888f
YW
1761 assert(client->lease);
1762
95bd6816
YW
1763 (void) event_source_disable(client->timeout_resend);
1764
a91b888f
YW
1765 if (client->lease->ipv6_only_preferred_usec > 0) {
1766 if (client->ipv6_acquired) {
1767 log_dhcp_client(client,
1768 "Received an OFFER with IPv6-only preferred option, and the host already acquired IPv6 connectivity, stopping DHCPv4 client.");
1769 return sd_dhcp_client_stop(client);
1770 }
1771
1772 log_dhcp_client(client,
1773 "Received an OFFER with IPv6-only preferred option, delaying to send REQUEST with %s.",
1774 FORMAT_TIMESPAN(client->lease->ipv6_only_preferred_usec, USEC_PER_SEC));
2ff1e230 1775
95bd6816
YW
1776 return event_reset_time_relative(client->event, &client->timeout_ipv6_only_mode,
1777 CLOCK_BOOTTIME,
1778 client->lease->ipv6_only_preferred_usec, 0,
1779 client_enter_requesting_delayed, client,
1780 client->event_priority, "dhcp4-ipv6-only-mode-timer",
1781 /* force_reset = */ true);
1782 }
2ff1e230 1783
95bd6816 1784 return client_enter_requesting_now(client);
2ff1e230
YW
1785}
1786
4b558378 1787static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
615c1467
TG
1788 int r;
1789
f693e9b3 1790 r = dhcp_option_parse(force, len, NULL, NULL, NULL);
615c1467
TG
1791 if (r != DHCP_FORCERENEW)
1792 return -ENOMSG;
1793
38e980a6 1794#if 0
615c1467 1795 log_dhcp_client(client, "FORCERENEW");
615c1467 1796 return 0;
38e980a6
YW
1797#else
1798 /* FIXME: Ignore FORCERENEW requests until we implement RFC3118 (Authentication for DHCP
1799 * Messages) and/or RFC6704 (Forcerenew Nonce Authentication), as unauthenticated FORCERENEW
1800 * requests causes a security issue (TALOS-2020-1142, CVE-2020-13529). */
f31fa080
ZJS
1801 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
1802 "Received FORCERENEW, ignoring.");
38e980a6 1803#endif
615c1467
TG
1804}
1805
3d9f6707
YW
1806static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
1807 if (a->address != b->address)
1808 return false;
1809
1810 if (a->subnet_mask != b->subnet_mask)
1811 return false;
1812
1813 if (a->router_size != b->router_size)
1814 return false;
1815
1816 for (size_t i = 0; i < a->router_size; i++)
1817 if (a->router[i].s_addr != b->router[i].s_addr)
1818 return false;
1819
1820 return true;
1821}
1822
905d0ea7 1823static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *message, size_t len, const triple_timestamp *timestamp) {
4afd3348 1824 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
5ee482df 1825 int r;
3e3d8f78 1826
f9edbb80
YW
1827 assert(client);
1828 assert(message);
9e64dd72 1829
f9edbb80 1830 r = client_parse_message(client, message, len, &lease);
8fc72505 1831 if (r < 0)
f9edbb80 1832 return r;
3e3d8f78 1833
905d0ea7
YW
1834 dhcp_lease_set_timestamp(lease, timestamp);
1835
db849df5
YW
1836 if (!client->lease)
1837 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1838 else if (lease_equal(client->lease, lease))
1839 r = SD_DHCP_CLIENT_EVENT_RENEW;
1840 else
1841 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
3e3d8f78 1842
db849df5 1843 dhcp_lease_unref_and_replace(client->lease, lease);
3e3d8f78 1844
ee57a737 1845 log_dhcp_client(client, "ACK");
3e3d8f78
PF
1846 return r;
1847}
1848
022446ad
TG
1849static int client_set_lease_timeouts(sd_dhcp_client *client) {
1850 usec_t time_now;
5ee482df 1851 int r;
51debc1e 1852
b25ef18b
TG
1853 assert(client);
1854 assert(client->event);
022446ad 1855 assert(client->lease);
5fde4d37 1856 assert(client->lease->lifetime > 0);
905d0ea7 1857 assert(triple_timestamp_is_set(&client->lease->timestamp));
a93538e8 1858
022446ad 1859 /* don't set timers for infinite leases */
5fde4d37 1860 if (client->lease->lifetime == USEC_INFINITY) {
a3fa4287
YW
1861 (void) event_source_disable(client->timeout_t1);
1862 (void) event_source_disable(client->timeout_t2);
1863 (void) event_source_disable(client->timeout_expire);
1864
022446ad 1865 return 0;
a3fa4287 1866 }
51debc1e 1867
ba4e0427 1868 r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now);
022446ad
TG
1869 if (r < 0)
1870 return r;
022446ad 1871
b0d7d806
DS
1872 /* verify that 0 < t2 < lifetime */
1873 if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime)
1874 client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
1875 /* verify that 0 < t1 < lifetime */
1876 if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2)
1877 client->lease->t1 = T1_DEFAULT(client->lease->lifetime);
1878 /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check
5fde4d37 1879 * could not evaluate to false if t1 >= t2; so setting t2 to T2_DEFAULT
b0d7d806
DS
1880 * guarantees t1 < t2. */
1881 if (client->lease->t1 >= client->lease->t2)
1882 client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
1883
5fde4d37
YW
1884 assert(client->lease->t1 > 0);
1885 assert(client->lease->t1 < client->lease->t2);
1886 assert(client->lease->t2 < client->lease->lifetime);
1887
905d0ea7
YW
1888 r = sd_dhcp_lease_get_lifetime_timestamp(client->lease, CLOCK_BOOTTIME, &client->expire_time);
1889 if (r < 0)
1890 return r;
1891 r = sd_dhcp_lease_get_t1_timestamp(client->lease, CLOCK_BOOTTIME, &client->t1_time);
1892 if (r < 0)
1893 return r;
1894 r = sd_dhcp_lease_get_t2_timestamp(client->lease, CLOCK_BOOTTIME, &client->t2_time);
1895 if (r < 0)
1896 return r;
b0d7d806
DS
1897
1898 /* RFC2131 section 4.4.5:
1899 * Times T1 and T2 SHOULD be chosen with some random "fuzz".
1900 * Since the RFC doesn't specify here the exact 'fuzz' to use,
1901 * we use the range from section 4.1: -1 to +1 sec. */
1902 client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ);
1903 client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ);
1904
1905 /* after fuzzing, ensure t2 is still >= t1 */
1906 client->t2_time = MAX(client->t1_time, client->t2_time);
51debc1e 1907
022446ad 1908 /* arm lifetime timeout */
a3fa4287 1909 r = event_reset_time(client->event, &client->timeout_expire,
ba4e0427 1910 CLOCK_BOOTTIME,
0c3c5978 1911 client->expire_time, 10 * USEC_PER_MSEC,
a3fa4287
YW
1912 client_timeout_expire, client,
1913 client->event_priority, "dhcp4-lifetime", true);
9021bb9f
TG
1914 if (r < 0)
1915 return r;
1916
022446ad 1917 /* don't arm earlier timeouts if this has already expired */
0c3c5978 1918 if (client->expire_time <= time_now)
022446ad 1919 return 0;
51debc1e 1920
f3bd46c6 1921 log_dhcp_client(client, "lease expires in %s",
5291f26d 1922 FORMAT_TIMESPAN(client->expire_time - time_now, USEC_PER_SEC));
f3bd46c6 1923
022446ad 1924 /* arm T2 timeout */
a3fa4287 1925 r = event_reset_time(client->event, &client->timeout_t2,
ba4e0427 1926 CLOCK_BOOTTIME,
0c3c5978 1927 client->t2_time, 10 * USEC_PER_MSEC,
a3fa4287
YW
1928 client_timeout_t2, client,
1929 client->event_priority, "dhcp4-t2-timeout", true);
9021bb9f
TG
1930 if (r < 0)
1931 return r;
1932
022446ad 1933 /* don't arm earlier timeout if this has already expired */
0c3c5978 1934 if (client->t2_time <= time_now)
022446ad 1935 return 0;
51debc1e 1936
f3bd46c6 1937 log_dhcp_client(client, "T2 expires in %s",
5291f26d 1938 FORMAT_TIMESPAN(client->t2_time - time_now, USEC_PER_SEC));
f3bd46c6 1939
022446ad 1940 /* arm T1 timeout */
a3fa4287 1941 r = event_reset_time(client->event, &client->timeout_t1,
ba4e0427 1942 CLOCK_BOOTTIME,
0c3c5978 1943 client->t1_time, 10 * USEC_PER_MSEC,
a3fa4287
YW
1944 client_timeout_t1, client,
1945 client->event_priority, "dhcp4-t1-timer", true);
9021bb9f
TG
1946 if (r < 0)
1947 return r;
1948
0c3c5978 1949 if (client->t1_time > time_now)
f3bd46c6 1950 log_dhcp_client(client, "T1 expires in %s",
5291f26d 1951 FORMAT_TIMESPAN(client->t1_time - time_now, USEC_PER_SEC));
022446ad 1952
51debc1e
PF
1953 return 0;
1954}
1955
a91b888f 1956static int client_enter_bound_now(sd_dhcp_client *client, int notify_event) {
525717b8
YW
1957 int r;
1958
1959 assert(client);
1960
1961 if (IN_SET(client->state, DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING))
1962 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1963
525717b8 1964 client_set_state(client, DHCP_STATE_BOUND);
6ff84614
AB
1965 client->discover_attempt = 0;
1966 client->request_attempt = 0;
525717b8
YW
1967
1968 client->last_addr = client->lease->address;
1969
1970 r = client_set_lease_timeouts(client);
1971 if (r < 0)
1972 log_dhcp_client_errno(client, r, "could not set lease timeouts: %m");
1973
4ad29bad
CF
1974 if (client->bootp) {
1975 client->receive_message = sd_event_source_disable_unref(client->receive_message);
1976 client->fd = safe_close(client->fd);
1977 } else {
1978 r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
1979 if (r < 0)
1980 return log_dhcp_client_errno(client, r, "could not bind UDP socket: %m");
525717b8 1981
4ad29bad
CF
1982 client->receive_message = sd_event_source_disable_unref(client->receive_message);
1983 close_and_replace(client->fd, r);
1984 client_initialize_io_events(client, client_receive_message_udp);
1985 }
525717b8 1986
5516b0dd 1987 client_notify(client, notify_event);
525717b8
YW
1988
1989 return 0;
1990}
1991
95bd6816 1992static int client_enter_bound_delayed(sd_event_source *s, uint64_t usec, void *userdata) {
a91b888f
YW
1993 sd_dhcp_client *client = ASSERT_PTR(userdata);
1994 DHCP_CLIENT_DONT_DESTROY(client);
1995 int r;
1996
1997 r = client_enter_bound_now(client, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE);
1998 if (r < 0)
1999 client_stop(client, r);
2000
2001 return 0;
2002}
2003
2004static int client_enter_bound(sd_dhcp_client *client, int notify_event) {
2005 assert(client);
2006 assert(client->lease);
2007
2008 client->start_delay = 0;
2009 (void) event_source_disable(client->timeout_resend);
2010
74c102d7
YW
2011 /* RFC 8925 section 3.2
2012 * If the client is in the INIT-REBOOT state, it SHOULD stop the DHCPv4 configuration process or
2013 * disable the IPv4 stack completely for V6ONLY_WAIT seconds or until the network attachment event,
2014 * whichever happens first.
2015 *
2016 * In the below, the condition uses REBOOTING, instead of INIT-REBOOT, as the client state has
2017 * already transitioned from INIT-REBOOT to REBOOTING after sending a DHCPREQUEST message. */
a91b888f
YW
2018 if (client->state == DHCP_STATE_REBOOTING && client->lease->ipv6_only_preferred_usec > 0) {
2019 if (client->ipv6_acquired) {
2020 log_dhcp_client(client,
2021 "Received an ACK with IPv6-only preferred option, and the host already acquired IPv6 connectivity, stopping DHCPv4 client.");
2022 return sd_dhcp_client_stop(client);
2023 }
2024
2025 log_dhcp_client(client,
2026 "Received an ACK with IPv6-only preferred option, delaying to enter bound state with %s.",
2027 FORMAT_TIMESPAN(client->lease->ipv6_only_preferred_usec, USEC_PER_SEC));
2028
2029 return event_reset_time_relative(client->event, &client->timeout_ipv6_only_mode,
2030 CLOCK_BOOTTIME,
2031 client->lease->ipv6_only_preferred_usec, 0,
95bd6816 2032 client_enter_bound_delayed, client,
a91b888f
YW
2033 client->event_priority, "dhcp4-ipv6-only-mode",
2034 /* force_reset = */ true);
2035 }
2036
2037 return client_enter_bound_now(client, notify_event);
2038}
2039
808b65a0
RP
2040static int client_restart(sd_dhcp_client *client) {
2041 int r;
2042 assert(client);
2043
2044 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
2045
2046 r = client_initialize(client);
2047 if (r < 0)
2048 return r;
2049
2050 r = client_start_delayed(client);
2051 if (r < 0)
2052 return r;
2053
2054 log_dhcp_client(client, "REBOOT in %s", FORMAT_TIMESPAN(client->start_delay, USEC_PER_SEC));
2055
2056 client->start_delay = CLAMP(client->start_delay * 2,
2057 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
2058 return 0;
2059}
2060
7f42c660
YW
2061static int client_verify_message_header(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
2062 const uint8_t *expected_chaddr = NULL;
2063 uint8_t expected_hlen = 0;
2064
2065 assert(client);
2066 assert(message);
2067
2068 if (len < sizeof(DHCPMessage))
2069 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
2070 "Too small to be a DHCP message, ignoring.");
2071
2072 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE)
2073 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
2074 "Not a DHCP message, ignoring.");
2075
2076 if (message->op != BOOTREPLY)
2077 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
2078 "Not a BOOTREPLY message, ignoring.");
2079
2080 if (message->htype != client->arp_type)
2081 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
2082 "Packet type does not match client type, ignoring.");
2083
2084 if (client->arp_type == ARPHRD_ETHER) {
2085 expected_hlen = ETH_ALEN;
2086 expected_chaddr = client->hw_addr.bytes;
2087 }
2088
2089 if (message->hlen != expected_hlen)
2090 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
2091 "Received packet hlen (%u) does not match expected (%u), ignoring.",
2092 message->hlen, expected_hlen);
2093
2094 if (memcmp_safe(message->chaddr, expected_chaddr, expected_hlen))
2095 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
2096 "Received chaddr does not match expected, ignoring.");
2097
2098 if (client->state != DHCP_STATE_BOUND &&
2099 be32toh(message->xid) != client->xid)
2100 /* in BOUND state, we may receive FORCERENEW with xid set by server,
2101 so ignore the xid in this case */
2102 return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
2103 "Received xid (%u) does not match expected (%u), ignoring.",
2104 be32toh(message->xid), client->xid);
2105
2106 return 0;
2107}
2108
905d0ea7 2109static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, size_t len, const triple_timestamp *timestamp) {
574cc928 2110 DHCP_CLIENT_DONT_DESTROY(client);
525717b8 2111 int r;
8c00042c 2112
b25ef18b 2113 assert(client);
e5002702 2114 assert(message);
dd59d5e5 2115 assert(timestamp);
b25ef18b 2116
7f42c660
YW
2117 if (client_verify_message_header(client, message, len) < 0)
2118 return 0;
2119
8c00042c
PF
2120 switch (client->state) {
2121 case DHCP_STATE_SELECTING:
2122
905d0ea7 2123 r = client_handle_offer_or_rapid_ack(client, message, len, timestamp);
f9edbb80 2124 if (ERRNO_IS_NEG_RESOURCE(r))
69f50bf3
YW
2125 return r;
2126 if (r == -EADDRNOTAVAIL)
808b65a0 2127 /* got a rapid NAK, let's restart the client */
69f50bf3 2128 return client_restart(client);
f9edbb80
YW
2129 if (r < 0)
2130 return 0; /* invalid message, let's ignore it */
8c00042c 2131
808b65a0 2132 if (client->lease->rapid_commit)
d19434fb 2133 /* got a successful rapid commit */
69f50bf3
YW
2134 return client_enter_bound(client, r);
2135
2136 return client_enter_requesting(client);
8c00042c 2137
8b1243f7 2138 case DHCP_STATE_REBOOTING:
3e3d8f78 2139 case DHCP_STATE_REQUESTING:
aba26854 2140 case DHCP_STATE_RENEWING:
3dd71400 2141 case DHCP_STATE_REBINDING:
aba26854 2142
905d0ea7 2143 r = client_handle_ack(client, message, len, timestamp);
f9edbb80 2144 if (ERRNO_IS_NEG_RESOURCE(r))
69f50bf3
YW
2145 return r;
2146 if (r == -EADDRNOTAVAIL)
2d2349cc 2147 /* got a NAK, let's restart the client */
69f50bf3 2148 return client_restart(client);
67d8cd81 2149 if (r < 0)
f9edbb80 2150 return 0; /* invalid message, let's ignore it */
67d8cd81 2151
69f50bf3 2152 return client_enter_bound(client, r);
3e3d8f78 2153
615c1467
TG
2154 case DHCP_STATE_BOUND:
2155 r = client_handle_forcerenew(client, message, len);
69f50bf3
YW
2156 if (ERRNO_IS_NEG_RESOURCE(r))
2157 return r;
67d8cd81 2158 if (r < 0)
69f50bf3 2159 return 0; /* invalid message, let's ignore it */
67d8cd81 2160
69f50bf3 2161 return client_timeout_t1(NULL, 0, client);
615c1467 2162
8c00042c
PF
2163 case DHCP_STATE_INIT:
2164 case DHCP_STATE_INIT_REBOOT:
69f50bf3
YW
2165 log_dhcp_client(client, "Unexpectedly receive message without sending any requests, ignoring.");
2166 return 0;
781ca7a1 2167
d57b62be 2168 default:
04499a70 2169 assert_not_reached();
8c00042c
PF
2170 }
2171
69f50bf3 2172 return 0;
8c00042c
PF
2173}
2174
4b558378
ZJS
2175static int client_receive_message_udp(
2176 sd_event_source *s,
2177 int fd,
2178 uint32_t revents,
2179 void *userdata) {
2180
99534007 2181 sd_dhcp_client *client = ASSERT_PTR(userdata);
5266a81e 2182 _cleanup_free_ DHCPMessage *message = NULL;
4edc2c9b 2183 ssize_t len, buflen;
c7464843
YW
2184 /* This needs to be initialized with zero. See #20741.
2185 * The issue is fixed on glibc-2.35 (8fba672472ae0055387e9315fc2eddfa6775ca79). */
905d0ea7
YW
2186 CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {};
2187 struct iovec iov;
2188 struct msghdr msg = {
2189 .msg_iov = &iov,
2190 .msg_iovlen = 1,
2191 .msg_control = &control,
2192 .msg_controllen = sizeof(control),
2193 };
69f50bf3 2194 int r;
e5002702
TG
2195
2196 assert(s);
e5002702 2197
4edc2c9b 2198 buflen = next_datagram_size_fd(fd);
1f2db2e3
ZJS
2199 if (ERRNO_IS_NEG_TRANSIENT(buflen) || ERRNO_IS_NEG_DISCONNECT(buflen))
2200 return 0;
ab8a8a4e 2201 if (buflen < 0) {
ab8a8a4e 2202 log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
22a3fd2d 2203 return 0;
ab8a8a4e 2204 }
5266a81e
TG
2205
2206 message = malloc0(buflen);
2207 if (!message)
2208 return -ENOMEM;
2209
905d0ea7 2210 iov = IOVEC_MAKE(message, buflen);
0d43d2fc 2211
905d0ea7
YW
2212 len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
2213 if (ERRNO_IS_NEG_TRANSIENT(len) || ERRNO_IS_NEG_DISCONNECT(len))
2214 return 0;
2215 if (len < 0) {
2216 log_dhcp_client_errno(client, len, "Could not receive message from UDP socket, ignoring: %m");
ab8a8a4e 2217 return 0;
004845d1 2218 }
615c1467 2219
897f7206 2220 log_dhcp_client(client, "Received message from UDP socket, processing.");
dd59d5e5 2221 r = client_handle_message(client, message, len, TRIPLE_TIMESTAMP_FROM_CMSG(&msg));
69f50bf3
YW
2222 if (r < 0)
2223 client_stop(client, r);
2224
ab8a8a4e 2225 return 0;
e5002702
TG
2226}
2227
4b558378
ZJS
2228static int client_receive_message_raw(
2229 sd_event_source *s,
2230 int fd,
2231 uint32_t revents,
2232 void *userdata) {
2233
99534007 2234 sd_dhcp_client *client = ASSERT_PTR(userdata);
5266a81e 2235 _cleanup_free_ DHCPPacket *packet = NULL;
c7464843
YW
2236 /* This needs to be initialized with zero. See #20741.
2237 * The issue is fixed on glibc-2.35 (8fba672472ae0055387e9315fc2eddfa6775ca79). */
905d0ea7
YW
2238 CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL +
2239 CMSG_SPACE(sizeof(struct tpacket_auxdata))) control = {};
55dab2ed
TG
2240 struct iovec iov = {};
2241 struct msghdr msg = {
2242 .msg_iov = &iov,
2243 .msg_iovlen = 1,
fb29cdbe
LP
2244 .msg_control = &control,
2245 .msg_controllen = sizeof(control),
55dab2ed 2246 };
55dab2ed 2247 bool checksum = true;
4edc2c9b
LP
2248 ssize_t buflen, len;
2249 int r;
e5002702
TG
2250
2251 assert(s);
e5002702 2252
4edc2c9b 2253 buflen = next_datagram_size_fd(fd);
1f2db2e3
ZJS
2254 if (ERRNO_IS_NEG_TRANSIENT(buflen) || ERRNO_IS_NEG_DISCONNECT(buflen))
2255 return 0;
ab8a8a4e 2256 if (buflen < 0) {
ab8a8a4e 2257 log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
22a3fd2d 2258 return 0;
ab8a8a4e 2259 }
5266a81e
TG
2260
2261 packet = malloc0(buflen);
2262 if (!packet)
2263 return -ENOMEM;
2264
cb310866 2265 iov = IOVEC_MAKE(packet, buflen);
55dab2ed 2266
84b5d3e5 2267 len = recvmsg_safe(fd, &msg, 0);
1f2db2e3
ZJS
2268 if (ERRNO_IS_NEG_TRANSIENT(len) || ERRNO_IS_NEG_DISCONNECT(len))
2269 return 0;
8add30a0 2270 if (len < 0) {
ab8a8a4e
YW
2271 log_dhcp_client_errno(client, len, "Could not receive message from raw socket, ignoring: %m");
2272 return 0;
8add30a0 2273 }
55dab2ed 2274
dd59d5e5 2275 struct tpacket_auxdata *aux = CMSG_FIND_DATA(&msg, SOL_PACKET, PACKET_AUXDATA, struct tpacket_auxdata);
461ef398
LB
2276 if (aux)
2277 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
905d0ea7 2278
69f50bf3 2279 if (dhcp_packet_verify_headers(packet, len, checksum, client->port) < 0)
9fadd4ca 2280 return 0;
e5002702
TG
2281
2282 len -= DHCP_IP_UDP_SIZE;
2283
897f7206 2284 log_dhcp_client(client, "Received message from RAW socket, processing.");
dd59d5e5 2285 r = client_handle_message(client, &packet->dhcp, len, TRIPLE_TIMESTAMP_FROM_CMSG(&msg));
69f50bf3
YW
2286 if (r < 0)
2287 client_stop(client, r);
2288
ab8a8a4e 2289 return 0;
e5002702
TG
2290}
2291
1c9a2e26 2292int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
4ad29bad 2293 if (!sd_dhcp_client_is_running(client) || client->state != DHCP_STATE_BOUND || client->bootp)
f8cdd37d 2294 return 0; /* do nothing */
dab96fed 2295
1c9a2e26 2296 client->start_delay = 0;
6ff84614
AB
2297 client->discover_attempt = 1;
2298 client->request_attempt = 1;
4502f82b 2299 client_set_state(client, DHCP_STATE_RENEWING);
1c9a2e26
YW
2300
2301 return client_initialize_time_events(client);
2302}
2303
041ea9f9 2304int sd_dhcp_client_is_running(sd_dhcp_client *client) {
22bbba84
YW
2305 if (!client)
2306 return 0;
2307
b2851e8d 2308 return client->state != DHCP_STATE_STOPPED;
22bbba84
YW
2309}
2310
5ee482df 2311int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 2312 int r;
d3d8ac2f 2313
46a66b79 2314 assert_return(client, -EINVAL);
46a66b79 2315
a91b888f
YW
2316 /* Note, do not reset the flag in client_initialize(), as it is also called on expire. */
2317 client->ipv6_acquired = false;
2318
0f941add
PF
2319 r = client_initialize(client);
2320 if (r < 0)
6a1cd41e 2321 return r;
8c00042c 2322
5e2a89d8 2323 /* If no client identifier exists, construct an RFC 4361-compliant one */
6efa51f8 2324 if (!sd_dhcp_client_id_is_set(&client->client_id)) {
5e2a89d8
YW
2325 r = sd_dhcp_client_set_iaid_duid_en(client, /* iaid_set = */ false, /* iaid = */ 0);
2326 if (r < 0)
2327 return r;
2328 }
2329
66173db7 2330 /* RFC7844 section 3.3:
2331 SHOULD perform a complete four-way handshake, starting with a
2332 DHCPDISCOVER, to obtain a new address lease. If the client can
2333 ascertain that this is exactly the same network to which it was
2334 previously connected, and if the link-layer address did not change,
2335 the client MAY issue a DHCPREQUEST to try to reclaim the current
2336 address. */
4ad29bad 2337 if (client->last_addr && !client->anonymize && !client->bootp)
4502f82b 2338 client_set_state(client, DHCP_STATE_INIT_REBOOT);
d3d8ac2f 2339
98a9b0f9
YW
2340 /* We currently ignore:
2341 * The client SHOULD wait a random time between one and ten seconds to desynchronize the use of
2342 * DHCP at startup. */
998d8047
TG
2343 r = client_start(client);
2344 if (r >= 0)
2f8e7633 2345 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
998d8047
TG
2346
2347 return r;
46a66b79
PF
2348}
2349
1501b429 2350int sd_dhcp_client_send_release(sd_dhcp_client *client) {
8ff4585f
ZJS
2351 _cleanup_free_ DHCPPacket *release = NULL;
2352 size_t optoffset, optlen;
2353 int r;
2354
4ad29bad 2355 if (!sd_dhcp_client_is_running(client) || !client->lease || client->bootp)
f8cdd37d
YW
2356 return 0; /* do nothing */
2357
556f641f 2358 r = client_message_init(client, DHCP_RELEASE, &release, &optlen, &optoffset);
8ff4585f
ZJS
2359 if (r < 0)
2360 return r;
2361
2362 /* Fill up release IP and MAC */
2363 release->dhcp.ciaddr = client->lease->address;
7e5c25b2 2364 memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length);
1501b429 2365
8ff4585f
ZJS
2366 r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
2367 SD_DHCP_OPTION_END, 0, NULL);
2368 if (r < 0)
2369 return r;
2370
2371 r = dhcp_network_send_udp_socket(client->fd,
2372 client->lease->server_address,
ea932bd3 2373 client->server_port,
8ff4585f
ZJS
2374 &release->dhcp,
2375 sizeof(DHCPMessage) + optoffset);
2376 if (r < 0)
2377 return r;
2378
2379 log_dhcp_client(client, "RELEASE");
1501b429 2380
2bb7559a
YW
2381 /* This function is mostly called when stopping daemon. Hence, do not call client_stop() or
2382 * client_restart(). Otherwise, the notification callback will be called again and we may easily
2383 * enter an infinite loop. */
2384 client_initialize(client);
2385 return 1; /* sent and stopped. */
1501b429
SS
2386}
2387
0f3ff4ea 2388int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
0f3ff4ea
SS
2389 _cleanup_free_ DHCPPacket *release = NULL;
2390 size_t optoffset, optlen;
2391 int r;
2392
f8cdd37d
YW
2393 if (!sd_dhcp_client_is_running(client) || !client->lease)
2394 return 0; /* do nothing */
2395
556f641f 2396 r = client_message_init(client, DHCP_DECLINE, &release, &optlen, &optoffset);
0f3ff4ea
SS
2397 if (r < 0)
2398 return r;
2399
2400 release->dhcp.ciaddr = client->lease->address;
7e5c25b2 2401 memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length);
0f3ff4ea
SS
2402
2403 r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
2404 SD_DHCP_OPTION_END, 0, NULL);
2405 if (r < 0)
2406 return r;
2407
2408 r = dhcp_network_send_udp_socket(client->fd,
2409 client->lease->server_address,
ea932bd3 2410 client->server_port,
0f3ff4ea
SS
2411 &release->dhcp,
2412 sizeof(DHCPMessage) + optoffset);
2413 if (r < 0)
2414 return r;
2415
2416 log_dhcp_client(client, "DECLINE");
2417
22c864d8
YW
2418 /* This function is mostly called when the acquired address conflicts with another host.
2419 * Restarting the daemon to acquire another address. */
2420 r = client_restart(client);
2421 if (r < 0)
2422 return r;
0f3ff4ea 2423
22c864d8 2424 return 1; /* sent and restarted. */
0f3ff4ea
SS
2425}
2426
5ee482df 2427int sd_dhcp_client_stop(sd_dhcp_client *client) {
c8bae363
YW
2428 if (!client)
2429 return 0;
574cc928 2430
c8bae363 2431 DHCP_CLIENT_DONT_DESTROY(client);
e5b04c8d 2432
03748142 2433 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
e5b04c8d
PF
2434
2435 return 0;
bbdf06d9
PF
2436}
2437
a91b888f
YW
2438int sd_dhcp_client_set_ipv6_connectivity(sd_dhcp_client *client, int have) {
2439 if (!client)
2440 return 0;
2441
2442 /* We have already received a message with IPv6-Only preferred option, and are waiting for IPv6
2443 * connectivity or timeout, let's stop the client. */
2444 if (have && sd_event_source_get_enabled(client->timeout_ipv6_only_mode, NULL) > 0)
2445 return sd_dhcp_client_stop(client);
2446
2447 /* Otherwise, save that the host already has IPv6 connectivity. */
2448 client->ipv6_acquired = have;
2449 return 0;
2450}
2451
0bc30a20
YW
2452int sd_dhcp_client_interrupt_ipv6_only_mode(sd_dhcp_client *client) {
2453 assert_return(client, -EINVAL);
2454 assert_return(sd_dhcp_client_is_running(client), -ESTALE);
2455 assert_return(client->fd >= 0, -EINVAL);
2456
2457 if (sd_event_source_get_enabled(client->timeout_ipv6_only_mode, NULL) <= 0)
2458 return 0;
2459
2460 client_initialize(client);
2461 return client_start(client);
2462}
2463
32d20645 2464int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
b25ef18b
TG
2465 int r;
2466
2467 assert_return(client, -EINVAL);
2468 assert_return(!client->event, -EBUSY);
11352286 2469 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
b25ef18b
TG
2470
2471 if (event)
2472 client->event = sd_event_ref(event);
2473 else {
2474 r = sd_event_default(&client->event);
2475 if (r < 0)
2476 return 0;
2477 }
2478
2479 client->event_priority = priority;
2480
2481 return 0;
2482}
2483
2484int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
2485 assert_return(client, -EINVAL);
11352286 2486 assert_return(!sd_dhcp_client_is_running(client), -EBUSY);
b25ef18b
TG
2487
2488 client->event = sd_event_unref(client->event);
2489
2490 return 0;
2491}
2492
2493sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
a1140666 2494 assert_return(client, NULL);
b25ef18b
TG
2495
2496 return client->event;
2497}
2498
be615f7c
YW
2499int sd_dhcp_client_attach_device(sd_dhcp_client *client, sd_device *dev) {
2500 assert_return(client, -EINVAL);
2501
2502 return device_unref_and_replace(client->dev, dev);
2503}
2504
8301aa0b 2505static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
f7af63fd
ZJS
2506 if (!client)
2507 return NULL;
e5b04c8d 2508
3733eec3 2509 log_dhcp_client(client, "FREE");
6e00a806 2510
eb2f7502
YW
2511 client_initialize(client);
2512
a3fa4287
YW
2513 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
2514 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
2515 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
2516 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
3733eec3 2517
3733eec3
LP
2518 sd_dhcp_client_detach_event(client);
2519
be615f7c
YW
2520 sd_device_unref(client->dev);
2521
4081756a 2522 set_free(client->req_opts);
3733eec3
LP
2523 free(client->hostname);
2524 free(client->vendor_class_identifier);
d11d4a64 2525 free(client->mudurl);
af1c0de0 2526 client->user_class = strv_free(client->user_class);
7354900d
DW
2527 ordered_hashmap_free(client->extra_options);
2528 ordered_hashmap_free(client->vendor_options);
61a9fa8f 2529 free(client->ifname);
6b430fdb 2530 return mfree(client);
d2fe46b5
PF
2531}
2532
8301aa0b
YW
2533DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
2534
db3d2358 2535int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
4081756a
YW
2536 const uint8_t *opts;
2537 size_t n_opts;
2538 int r;
2539
b25ef18b 2540 assert_return(ret, -EINVAL);
d3d8ac2f 2541
f7af63fd 2542 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1);
011feef8 2543 if (!client)
b25ef18b 2544 return -ENOMEM;
011feef8 2545
be6bf4a7
YW
2546 *client = (sd_dhcp_client) {
2547 .n_ref = 1,
b2851e8d 2548 .state = DHCP_STATE_STOPPED,
be6bf4a7 2549 .ifindex = -1,
254d1313 2550 .fd = -EBADF,
4473cd7f 2551 .mtu = DHCP_MIN_PACKET_SIZE,
be6bf4a7 2552 .port = DHCP_PORT_CLIENT,
ea932bd3 2553 .server_port = DHCP_PORT_SERVER,
be6bf4a7 2554 .anonymize = !!anonymize,
6ff84614
AB
2555 .max_discover_attempts = UINT64_MAX,
2556 .max_request_attempts = 5,
afe42aef 2557 .ip_service_type = -1,
be6bf4a7 2558 };
db3d2358 2559 /* NOTE: this could be moved to a function. */
2560 if (anonymize) {
4081756a
YW
2561 n_opts = ELEMENTSOF(default_req_opts_anonymize);
2562 opts = default_req_opts_anonymize;
db3d2358 2563 } else {
4081756a
YW
2564 n_opts = ELEMENTSOF(default_req_opts);
2565 opts = default_req_opts;
2566 }
2567
2568 for (size_t i = 0; i < n_opts; i++) {
2569 r = sd_dhcp_client_set_request_option(client, opts[i]);
2570 if (r < 0)
2571 return r;
db3d2358 2572 }
b25ef18b 2573
1cc6c93a 2574 *ret = TAKE_PTR(client);
011feef8 2575
b25ef18b 2576 return 0;
011feef8 2577}
8320db40
YW
2578
2579static const char* const dhcp_state_table[_DHCP_STATE_MAX] = {
2580 [DHCP_STATE_STOPPED] = "stopped",
2581 [DHCP_STATE_INIT] = "initialization",
2582 [DHCP_STATE_SELECTING] = "selecting",
2583 [DHCP_STATE_INIT_REBOOT] = "init-reboot",
2584 [DHCP_STATE_REBOOTING] = "rebooting",
2585 [DHCP_STATE_REQUESTING] = "requesting",
2586 [DHCP_STATE_BOUND] = "bound",
2587 [DHCP_STATE_RENEWING] = "renewing",
2588 [DHCP_STATE_REBINDING] = "rebinding",
2589};
2590
2591DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dhcp_state, DHCPState);