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