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