]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
Merge pull request #10801 from ssc-services/zsh-completion_machinectl_clone
[thirdparty/systemd.git] / src / libsystemd-network / sd-dhcp-client.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
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>
11#include <string.h>
5266a81e 12#include <sys/ioctl.h>
07630cea 13#include <linux/if_infiniband.h>
011feef8 14
07630cea 15#include "sd-dhcp-client.h"
011feef8 16
b5efdb8a 17#include "alloc-util.h"
07630cea
LP
18#include "async.h"
19#include "dhcp-identifier.h"
46a66b79 20#include "dhcp-internal.h"
fe8db0c5 21#include "dhcp-lease-internal.h"
07630cea 22#include "dhcp-protocol.h"
23873e25 23#include "dns-domain.h"
a3fa4287 24#include "event-util.h"
23873e25 25#include "hostname-util.h"
07630cea
LP
26#include "random-util.h"
27#include "string-util.h"
28#include "util.h"
af1c0de0 29#include "strv.h"
011feef8 30
5bac5235 31#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
dd168445 32#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
76253e73 33
1d1a3e0a
BG
34#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
35#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
36
011feef8 37struct sd_dhcp_client {
3733eec3 38 unsigned n_ref;
e5b04c8d 39
011feef8 40 DHCPState state;
d3d8ac2f 41 sd_event *event;
b25ef18b 42 int event_priority;
d3d8ac2f 43 sd_event_source *timeout_resend;
2f8e7633 44 int ifindex;
8c00042c 45 int fd;
9faed222 46 uint16_t port;
8c00042c
PF
47 union sockaddr_union link;
48 sd_event_source *receive_message;
f5de5b00 49 bool request_broadcast;
011feef8 50 uint8_t *req_opts;
7a7c74ca 51 size_t req_opts_allocated;
011feef8 52 size_t req_opts_size;
db3d2358 53 bool anonymize;
3b349af6 54 be32_t last_addr;
76253e73
DW
55 uint8_t mac_addr[MAX_MAC_ADDR_LEN];
56 size_t mac_addr_len;
57 uint16_t arp_type;
5bac5235
TG
58 struct {
59 uint8_t type;
60 union {
61 struct {
62 /* 0: Generic (non-LL) (RFC 2132) */
63 uint8_t data[MAX_CLIENT_ID_LEN];
64 } _packed_ gen;
65 struct {
66 /* 1: Ethernet Link-Layer (RFC 2132) */
67 uint8_t haddr[ETH_ALEN];
68 } _packed_ eth;
69 struct {
70 /* 2 - 254: ARP/Link-Layer (RFC 2132) */
71 uint8_t haddr[0];
72 } _packed_ ll;
73 struct {
74 /* 255: Node-specific (RFC 4361) */
413708d1 75 be32_t iaid;
5bac5235
TG
76 struct duid duid;
77 } _packed_ ns;
78 struct {
79 uint8_t data[MAX_CLIENT_ID_LEN];
80 } _packed_ raw;
81 };
82 } _packed_ client_id;
ba6c0fd6 83 size_t client_id_len;
4cc7a82c 84 char *hostname;
edb85f0d 85 char *vendor_class_identifier;
af1c0de0 86 char **user_class;
324f8187 87 uint32_t mtu;
46a66b79 88 uint32_t xid;
d3d8ac2f 89 usec_t start_time;
14cb109d 90 unsigned attempt;
51debc1e
PF
91 usec_t request_sent;
92 sd_event_source *timeout_t1;
93 sd_event_source *timeout_t2;
94 sd_event_source *timeout_expire;
45aa74c7 95 sd_dhcp_client_callback_t callback;
751246ee 96 void *userdata;
a6cc569e 97 sd_dhcp_lease *lease;
1d1a3e0a 98 usec_t start_delay;
011feef8
PF
99};
100
101static const uint8_t default_req_opts[] = {
22805d92
BG
102 SD_DHCP_OPTION_SUBNET_MASK,
103 SD_DHCP_OPTION_ROUTER,
104 SD_DHCP_OPTION_HOST_NAME,
105 SD_DHCP_OPTION_DOMAIN_NAME,
106 SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
011feef8
PF
107};
108
db3d2358 109/* RFC7844 section 3:
110 MAY contain the Parameter Request List option.
111 RFC7844 section 3.6:
112 The client intending to protect its privacy SHOULD only request a
113 minimal number of options in the PRL and SHOULD also randomly shuffle
114 the ordering of option codes in the PRL. If this random ordering
115 cannot be implemented, the client MAY order the option codes in the
116 PRL by option code number (lowest to highest).
117*/
118/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
119static const uint8_t default_req_opts_anonymize[] = {
120 SD_DHCP_OPTION_SUBNET_MASK, /* 1 */
121 SD_DHCP_OPTION_ROUTER, /* 3 */
122 SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */
123 SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */
124 SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */
125 SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */
126 SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */
127 SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */
128 SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */
129 SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */
130 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */
131 SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */
132 SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */
133};
134
4b558378
ZJS
135static int client_receive_message_raw(
136 sd_event_source *s,
137 int fd,
138 uint32_t revents,
139 void *userdata);
140static int client_receive_message_udp(
141 sd_event_source *s,
142 int fd,
143 uint32_t revents,
144 void *userdata);
574cc928 145static void client_stop(sd_dhcp_client *client, int error);
aba26854 146
4b558378
ZJS
147int sd_dhcp_client_set_callback(
148 sd_dhcp_client *client,
149 sd_dhcp_client_callback_t cb,
150 void *userdata) {
45aa74c7 151
751246ee
PF
152 assert_return(client, -EINVAL);
153
45aa74c7 154 client->callback = cb;
751246ee
PF
155 client->userdata = userdata;
156
157 return 0;
158}
159
f5de5b00
TG
160int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
161 assert_return(client, -EINVAL);
162
163 client->request_broadcast = !!broadcast;
164
165 return 0;
166}
167
5ee482df 168int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
011feef8
PF
169 size_t i;
170
171 assert_return(client, -EINVAL);
a1140666 172 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
011feef8
PF
173
174 switch(option) {
a1140666 175
22805d92
BG
176 case SD_DHCP_OPTION_PAD:
177 case SD_DHCP_OPTION_OVERLOAD:
178 case SD_DHCP_OPTION_MESSAGE_TYPE:
179 case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
180 case SD_DHCP_OPTION_END:
011feef8
PF
181 return -EINVAL;
182
183 default:
184 break;
185 }
186
187 for (i = 0; i < client->req_opts_size; i++)
188 if (client->req_opts[i] == option)
189 return -EEXIST;
190
7a7c74ca 191 if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
011feef8
PF
192 client->req_opts_size + 1))
193 return -ENOMEM;
194
7a7c74ca 195 client->req_opts[client->req_opts_size++] = option;
011feef8
PF
196
197 return 0;
198}
199
4b558378
ZJS
200int sd_dhcp_client_set_request_address(
201 sd_dhcp_client *client,
202 const struct in_addr *last_addr) {
a1140666 203
011feef8 204 assert_return(client, -EINVAL);
a1140666 205 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
011feef8
PF
206
207 if (last_addr)
208 client->last_addr = last_addr->s_addr;
209 else
210 client->last_addr = INADDR_ANY;
211
212 return 0;
213}
214
2f8e7633 215int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
011feef8 216
2f8e7633
LP
217 assert_return(client, -EINVAL);
218 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
219 assert_return(ifindex > 0, -EINVAL);
011feef8 220
2f8e7633 221 client->ifindex = ifindex;
011feef8
PF
222 return 0;
223}
224
4b558378
ZJS
225int sd_dhcp_client_set_mac(
226 sd_dhcp_client *client,
227 const uint8_t *addr,
228 size_t addr_len,
229 uint16_t arp_type) {
230
574cc928 231 DHCP_CLIENT_DONT_DESTROY(client);
4644fee0
TG
232 bool need_restart = false;
233
46a66b79 234 assert_return(client, -EINVAL);
4644fee0 235 assert_return(addr, -EINVAL);
76253e73
DW
236 assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
237 assert_return(arp_type > 0, -EINVAL);
238
239 if (arp_type == ARPHRD_ETHER)
240 assert_return(addr_len == ETH_ALEN, -EINVAL);
241 else if (arp_type == ARPHRD_INFINIBAND)
242 assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
243 else
244 return -EINVAL;
46a66b79 245
76253e73
DW
246 if (client->mac_addr_len == addr_len &&
247 memcmp(&client->mac_addr, addr, addr_len) == 0)
4644fee0
TG
248 return 0;
249
781ca7a1 250 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
a1140666 251 log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
4644fee0 252 need_restart = true;
03748142 253 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
4644fee0 254 }
02ec5cd7 255
76253e73
DW
256 memcpy(&client->mac_addr, addr, addr_len);
257 client->mac_addr_len = addr_len;
258 client->arp_type = arp_type;
259
ba6c0fd6
DW
260 if (need_restart && client->state != DHCP_STATE_STOPPED)
261 sd_dhcp_client_start(client);
262
263 return 0;
264}
265
4b558378
ZJS
266int sd_dhcp_client_get_client_id(
267 sd_dhcp_client *client,
268 uint8_t *type,
269 const uint8_t **data,
270 size_t *data_len) {
ba6c0fd6
DW
271
272 assert_return(client, -EINVAL);
273 assert_return(type, -EINVAL);
274 assert_return(data, -EINVAL);
275 assert_return(data_len, -EINVAL);
276
277 *type = 0;
278 *data = NULL;
279 *data_len = 0;
280 if (client->client_id_len) {
5bac5235 281 *type = client->client_id.type;
ba6c0fd6 282 *data = client->client_id.raw.data;
5bac5235 283 *data_len = client->client_id_len - sizeof(client->client_id.type);
ba6c0fd6
DW
284 }
285
286 return 0;
287}
288
4b558378
ZJS
289int sd_dhcp_client_set_client_id(
290 sd_dhcp_client *client,
291 uint8_t type,
292 const uint8_t *data,
293 size_t data_len) {
294
ba6c0fd6
DW
295 DHCP_CLIENT_DONT_DESTROY(client);
296 bool need_restart = false;
297
298 assert_return(client, -EINVAL);
299 assert_return(data, -EINVAL);
300 assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
301
302 switch (type) {
a1140666 303
ba6c0fd6
DW
304 case ARPHRD_ETHER:
305 if (data_len != ETH_ALEN)
306 return -EINVAL;
307 break;
a1140666 308
ba6c0fd6
DW
309 case ARPHRD_INFINIBAND:
310 if (data_len != INFINIBAND_ALEN)
311 return -EINVAL;
312 break;
a1140666 313
ba6c0fd6
DW
314 default:
315 break;
316 }
317
5bac5235
TG
318 if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
319 client->client_id.type == type &&
ba6c0fd6
DW
320 memcmp(&client->client_id.raw.data, data, data_len) == 0)
321 return 0;
322
323 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
324 log_dhcp_client(client, "Changing client ID on running DHCP "
325 "client, restarting");
326 need_restart = true;
03748142 327 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
ba6c0fd6
DW
328 }
329
5bac5235 330 client->client_id.type = type;
ba6c0fd6 331 memcpy(&client->client_id.raw.data, data, data_len);
5bac5235 332 client->client_id_len = data_len + sizeof (client->client_id.type);
46a66b79 333
781ca7a1 334 if (need_restart && client->state != DHCP_STATE_STOPPED)
4644fee0
TG
335 sd_dhcp_client_start(client);
336
46a66b79
PF
337 return 0;
338}
339
d7df2fd3
ZJS
340/**
341 * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
342 * without further modification. Otherwise, if duid_type is supported, DUID
343 * is set based on that type. Otherwise, an error is returned.
344 */
7e90a499 345static int dhcp_client_set_iaid_duid_internal(
4b558378
ZJS
346 sd_dhcp_client *client,
347 uint32_t iaid,
dace710c 348 bool append_iaid,
4b558378 349 uint16_t duid_type,
f7a92d1a 350 const void *duid,
7e90a499
YW
351 size_t duid_len,
352 usec_t llt_time) {
4b558378 353
413708d1
VK
354 DHCP_CLIENT_DONT_DESTROY(client);
355 int r;
d7df2fd3
ZJS
356 size_t len;
357
413708d1 358 assert_return(client, -EINVAL);
d7df2fd3
ZJS
359 assert_return(duid_len == 0 || duid != NULL, -EINVAL);
360
361 if (duid != NULL) {
362 r = dhcp_validate_duid_len(duid_type, duid_len);
363 if (r < 0)
364 return r;
365 }
413708d1 366
d7df2fd3 367 zero(client->client_id);
413708d1
VK
368 client->client_id.type = 255;
369
dace710c
YW
370 if (append_iaid) {
371 /* If IAID is not configured, generate it. */
372 if (iaid == 0) {
373 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
374 client->mac_addr_len,
6d13616b 375 true,
dace710c
YW
376 &client->client_id.ns.iaid);
377 if (r < 0)
378 return r;
379 } else
380 client->client_id.ns.iaid = htobe32(iaid);
381 }
413708d1 382
d7df2fd3 383 if (duid != NULL) {
413708d1
VK
384 client->client_id.ns.duid.type = htobe16(duid_type);
385 memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
d7df2fd3 386 len = sizeof(client->client_id.ns.duid.type) + duid_len;
d7df2fd3 387 } else
27eba50e 388 switch (duid_type) {
335f80a6 389 case DUID_TYPE_LLT:
339697f0 390 if (client->mac_addr_len == 0)
335f80a6
YW
391 return -EOPNOTSUPP;
392
7e90a499 393 r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
335f80a6
YW
394 if (r < 0)
395 return r;
396 break;
27eba50e
YW
397 case DUID_TYPE_EN:
398 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
399 if (r < 0)
400 return r;
401 break;
335f80a6 402 case DUID_TYPE_LL:
339697f0 403 if (client->mac_addr_len == 0)
335f80a6
YW
404 return -EOPNOTSUPP;
405
406 r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
407 if (r < 0)
408 return r;
409 break;
27eba50e
YW
410 case DUID_TYPE_UUID:
411 r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
412 if (r < 0)
413 return r;
414 break;
415 default:
335f80a6 416 return -EINVAL;
27eba50e 417 }
413708d1 418
d7df2fd3 419 client->client_id_len = sizeof(client->client_id.type) + len +
dace710c 420 (append_iaid ? sizeof(client->client_id.ns.iaid) : 0);
413708d1
VK
421
422 if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
f7708f3f 423 log_dhcp_client(client, "Configured %sDUID, restarting.", append_iaid ? "IAID+" : "");
413708d1
VK
424 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
425 sd_dhcp_client_start(client);
426 }
427
428 return 0;
429}
430
dace710c
YW
431int sd_dhcp_client_set_iaid_duid(
432 sd_dhcp_client *client,
433 uint32_t iaid,
434 uint16_t duid_type,
435 const void *duid,
436 size_t duid_len) {
7e90a499
YW
437 return dhcp_client_set_iaid_duid_internal(client, iaid, true, duid_type, duid, duid_len, 0);
438}
439
440int sd_dhcp_client_set_iaid_duid_llt(
441 sd_dhcp_client *client,
442 uint32_t iaid,
443 usec_t llt_time) {
444 return dhcp_client_set_iaid_duid_internal(client, iaid, true, DUID_TYPE_LLT, NULL, 0, llt_time);
dace710c
YW
445}
446
447int sd_dhcp_client_set_duid(
448 sd_dhcp_client *client,
449 uint16_t duid_type,
450 const void *duid,
451 size_t duid_len) {
7e90a499
YW
452 return dhcp_client_set_iaid_duid_internal(client, 0, false, duid_type, duid, duid_len, 0);
453}
454
455int sd_dhcp_client_set_duid_llt(
456 sd_dhcp_client *client,
457 usec_t llt_time) {
458 return dhcp_client_set_iaid_duid_internal(client, 0, false, DUID_TYPE_LLT, NULL, 0, llt_time);
dace710c
YW
459}
460
4b558378
ZJS
461int sd_dhcp_client_set_hostname(
462 sd_dhcp_client *client,
463 const char *hostname) {
464
4cc7a82c
EY
465 assert_return(client, -EINVAL);
466
9740eae6 467 /* Make sure hostnames qualify as DNS and as Linux hostnames */
ef8b0084 468 if (hostname &&
9740eae6 469 !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0))
23873e25
BG
470 return -EINVAL;
471
ef8b0084 472 return free_and_strdup(&client->hostname, hostname);
4cc7a82c
EY
473}
474
4b558378
ZJS
475int sd_dhcp_client_set_vendor_class_identifier(
476 sd_dhcp_client *client,
477 const char *vci) {
478
edb85f0d
SS
479 assert_return(client, -EINVAL);
480
ef8b0084 481 return free_and_strdup(&client->vendor_class_identifier, vci);
edb85f0d
SS
482}
483
af1c0de0
SS
484int sd_dhcp_client_set_user_class(
485 sd_dhcp_client *client,
486 const char* const* user_class) {
487
488 _cleanup_strv_free_ char **s = NULL;
489 char **p;
490
491 STRV_FOREACH(p, (char **) user_class)
492 if (strlen(*p) > 255)
493 return -ENAMETOOLONG;
494
495 s = strv_copy((char **) user_class);
496 if (!s)
497 return -ENOMEM;
498
499 client->user_class = TAKE_PTR(s);
500
501 return 0;
502}
503
9faed222
SS
504int sd_dhcp_client_set_client_port(
505 sd_dhcp_client *client,
506 uint16_t port) {
507
508 assert_return(client, -EINVAL);
509
510 client->port = port;
511
512 return 0;
513}
514
324f8187
TG
515int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
516 assert_return(client, -EINVAL);
517 assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
518
519 client->mtu = mtu;
520
521 return 0;
522}
523
a6cc569e 524int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
751246ee 525 assert_return(client, -EINVAL);
751246ee 526
ec2ce0c5 527 if (!IN_SET(client->state, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
a6cc569e 528 return -EADDRNOTAVAIL;
751246ee 529
a1140666
LP
530 if (ret)
531 *ret = client->lease;
4f882b2a
TG
532
533 return 0;
534}
535
574cc928 536static void client_notify(sd_dhcp_client *client, int event) {
45aa74c7
LP
537 assert(client);
538
539 if (client->callback)
540 client->callback(client, event, client->userdata);
3e3d8f78
PF
541}
542
0f941add 543static int client_initialize(sd_dhcp_client *client) {
bbdf06d9 544 assert_return(client, -EINVAL);
bbdf06d9 545
a1140666 546 client->receive_message = sd_event_source_unref(client->receive_message);
8c00042c 547
22fc2420 548 client->fd = asynchronous_close(client->fd);
8c00042c 549
a3fa4287
YW
550 (void) event_source_disable(client->timeout_resend);
551 (void) event_source_disable(client->timeout_t1);
552 (void) event_source_disable(client->timeout_t2);
553 (void) event_source_disable(client->timeout_expire);
51debc1e 554
e2dfc79f
PF
555 client->attempt = 1;
556
f8fdefe4 557 client->state = DHCP_STATE_INIT;
0f941add 558 client->xid = 0;
bbdf06d9 559
0339cd77 560 client->lease = sd_dhcp_lease_unref(client->lease);
8c00042c 561
0f941add
PF
562 return 0;
563}
564
574cc928
TG
565static void client_stop(sd_dhcp_client *client, int error) {
566 assert(client);
0f941add 567
ccfdc9a1
UTL
568 if (error < 0)
569 log_dhcp_client(client, "STOPPED: %s", strerror(-error));
03748142 570 else if (error == SD_DHCP_CLIENT_EVENT_STOP)
2d2349cc
TG
571 log_dhcp_client(client, "STOPPED");
572 else
573 log_dhcp_client(client, "STOPPED: Unknown event");
0f941add 574
574cc928 575 client_notify(client, error);
ee57a737 576
574cc928 577 client_initialize(client);
bbdf06d9
PF
578}
579
4b558378
ZJS
580static int client_message_init(
581 sd_dhcp_client *client,
582 DHCPPacket **ret,
583 uint8_t type,
584 size_t *_optlen,
585 size_t *_optoffset) {
586
3587161a 587 _cleanup_free_ DHCPPacket *packet = NULL;
424a8732 588 size_t optlen, optoffset, size;
8a9e7616 589 be16_t max_size;
d8d74ef0
DW
590 usec_t time_now;
591 uint16_t secs;
cf597f65 592 int r;
46a66b79 593
6236f49b 594 assert(client);
d8d74ef0 595 assert(client->start_time);
424a8732
TG
596 assert(ret);
597 assert(_optlen);
598 assert(_optoffset);
4c701096 599 assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST));
0a1b6da8 600
424a8732
TG
601 optlen = DHCP_MIN_OPTIONS_SIZE;
602 size = sizeof(DHCPPacket) + optlen;
603
604 packet = malloc0(size);
605 if (!packet)
606 return -ENOMEM;
607
608 r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
76253e73 609 client->arp_type, optlen, &optoffset);
cf597f65
TG
610 if (r < 0)
611 return r;
46a66b79 612
0a1b6da8
TG
613 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
614 refuse to issue an DHCP lease if 'secs' is set to zero */
d8d74ef0
DW
615 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
616 if (r < 0)
617 return r;
618 assert(time_now >= client->start_time);
619
620 /* seconds between sending first and last DISCOVER
621 * must always be strictly positive to deal with broken servers */
622 secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
623 packet->dhcp.secs = htobe16(secs);
0a1b6da8 624
63a07041
CA
625 /* RFC2132 section 4.1
626 A client that cannot receive unicast IP datagrams until its protocol
627 software has been configured with an IP address SHOULD set the
628 BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
629 DHCPREQUEST messages that client sends. The BROADCAST bit will
630 provide a hint to the DHCP server and BOOTP relay agent to broadcast
f5de5b00
TG
631 any messages to the client on the client's subnet.
632
633 Note: some interfaces needs this to be enabled, but some networks
634 needs this to be disabled as broadcasts are filteretd, so this
635 needs to be configurable */
76253e73 636 if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
f5de5b00 637 packet->dhcp.flags = htobe16(0x8000);
63a07041 638
50d6810e
TG
639 /* RFC2132 section 4.1.1:
640 The client MUST include its hardware address in the ’chaddr’ field, if
76253e73
DW
641 necessary for delivery of DHCP reply messages. Non-Ethernet
642 interfaces will leave 'chaddr' empty and use the client identifier
643 instead (eg, RFC 4390 section 2.1).
50d6810e 644 */
76253e73
DW
645 if (client->arp_type == ARPHRD_ETHER)
646 memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
f5a70de7 647
afec4539 648 /* If no client identifier exists, construct an RFC 4361-compliant one */
5bac5235
TG
649 if (client->client_id_len == 0) {
650 size_t duid_len;
651
652 client->client_id.type = 255;
653
6d13616b
TH
654 r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
655 true, &client->client_id.ns.iaid);
5bac5235
TG
656 if (r < 0)
657 return r;
658
659 r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
660 if (r < 0)
661 return r;
662
663 client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
ba6c0fd6
DW
664 }
665
ee57a737 666 /* Some DHCP servers will refuse to issue an DHCP lease if the Client
46a66b79 667 Identifier option is not set */
ba6c0fd6
DW
668 if (client->client_id_len) {
669 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
22805d92 670 SD_DHCP_OPTION_CLIENT_IDENTIFIER,
ba6c0fd6 671 client->client_id_len,
5bac5235 672 &client->client_id);
ba6c0fd6
DW
673 if (r < 0)
674 return r;
675 }
50d6810e
TG
676
677 /* RFC2131 section 3.5:
678 in its initial DHCPDISCOVER or DHCPREQUEST message, a
679 client may provide the server with a list of specific
680 parameters the client is interested in. If the client
681 includes a list of parameters in a DHCPDISCOVER message,
682 it MUST include that list in any subsequent DHCPREQUEST
683 messages.
684 */
5e77a146 685
686 /* RFC7844 section 3:
687 MAY contain the Parameter Request List option. */
688 /* NOTE: in case that there would be an option to do not send
689 * any PRL at all, the size should be checked before sending */
690 if (client->req_opts_size > 0) {
691 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
692 SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
693 client->req_opts_size, client->req_opts);
694 if (r < 0)
695 return r;
696 }
8a9e7616 697
50d6810e
TG
698 /* RFC2131 section 3.5:
699 The client SHOULD include the ’maximum DHCP message size’ option to
700 let the server know how large the server may make its DHCP messages.
701
702 Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
f21f31b2 703 than the defined default size unless the Maximum Message Size option
f131770b 704 is explicitly set
324f8187
TG
705
706 RFC3442 "Requirements to Avoid Sizing Constraints":
707 Because a full routing table can be quite large, the standard 576
708 octet maximum size for a DHCP message may be too short to contain
709 some legitimate Classless Static Route options. Because of this,
710 clients implementing the Classless Static Route option SHOULD send a
711 Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
712 stack is capable of receiving larger IP datagrams. In this case, the
713 client SHOULD set the value of this option to at least the MTU of the
714 interface that the client is configuring. The client MAY set the
715 value of this option higher, up to the size of the largest UDP packet
716 it is prepared to accept. (Note that the value specified in the
717 Maximum DHCP Message Size option is the total maximum packet size,
718 including IP and UDP headers.)
50d6810e 719 */
1b41b815 720 /* RFC7844 section 3:
721 SHOULD NOT contain any other option. */
722 if (!client->anonymize) {
723 max_size = htobe16(size);
724 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
725 SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
726 2, &max_size);
727 if (r < 0)
728 return r;
729 }
46a66b79 730
424a8732
TG
731 *_optlen = optlen;
732 *_optoffset = optoffset;
1cc6c93a 733 *ret = TAKE_PTR(packet);
424a8732 734
46a66b79
PF
735 return 0;
736}
737
4b558378
ZJS
738static int client_append_fqdn_option(
739 DHCPMessage *message,
740 size_t optlen,
741 size_t *optoffset,
742 const char *fqdn) {
743
23873e25
BG
744 uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
745 int r;
746
747 buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
748 DHCP_FQDN_FLAG_E; /* Canonical wire format */
749 buffer[1] = 0; /* RCODE1 (deprecated) */
750 buffer[2] = 0; /* RCODE2 (deprecated) */
751
3cd03457 752 r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
23873e25
BG
753 if (r > 0)
754 r = dhcp_option_append(message, optlen, optoffset, 0,
22805d92 755 SD_DHCP_OPTION_FQDN, 3 + r, buffer);
23873e25
BG
756
757 return r;
758}
759
4b558378
ZJS
760static int dhcp_client_send_raw(
761 sd_dhcp_client *client,
762 DHCPPacket *packet,
763 size_t len) {
764
9faed222 765 dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
63edaa62
TG
766 INADDR_BROADCAST, DHCP_PORT_SERVER, len);
767
768 return dhcp_network_send_raw_socket(client->fd, &client->link,
769 packet, len);
770}
771
6236f49b 772static int client_send_discover(sd_dhcp_client *client) {
9f2a50a3 773 _cleanup_free_ DHCPPacket *discover = NULL;
424a8732 774 size_t optoffset, optlen;
6236f49b
TG
775 int r;
776
777 assert(client);
4c701096 778 assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
50d6810e 779
424a8732
TG
780 r = client_message_init(client, &discover, DHCP_DISCOVER,
781 &optlen, &optoffset);
6236f49b
TG
782 if (r < 0)
783 return r;
46a66b79 784
50d6810e
TG
785 /* the client may suggest values for the network address
786 and lease time in the DHCPDISCOVER message. The client may include
787 the ’requested IP address’ option to suggest that a particular IP
788 address be assigned, and may include the ’IP address lease time’
789 option to suggest the lease time it would like.
790 */
46a66b79 791 if (client->last_addr != INADDR_ANY) {
04b28be1 792 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 793 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
20b958bf 794 4, &client->last_addr);
6236f49b
TG
795 if (r < 0)
796 return r;
46a66b79
PF
797 }
798
4cc7a82c 799 if (client->hostname) {
23873e25
BG
800 /* According to RFC 4702 "clients that send the Client FQDN option in
801 their messages MUST NOT also send the Host Name option". Just send
802 one of the two depending on the hostname type.
803 */
dc477e73 804 if (dns_name_is_single_label(client->hostname)) {
23873e25
BG
805 /* it is unclear from RFC 2131 if client should send hostname in
806 DHCPDISCOVER but dhclient does and so we do as well
807 */
808 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 809 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
810 strlen(client->hostname), client->hostname);
811 } else
812 r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
813 client->hostname);
4cc7a82c
EY
814 if (r < 0)
815 return r;
816 }
817
edb85f0d
SS
818 if (client->vendor_class_identifier) {
819 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 820 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
edb85f0d
SS
821 strlen(client->vendor_class_identifier),
822 client->vendor_class_identifier);
823 if (r < 0)
824 return r;
825 }
826
af1c0de0
SS
827 if (client->user_class) {
828 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
829 SD_DHCP_OPTION_USER_CLASS,
830 strv_length(client->user_class),
831 client->user_class);
832 if (r < 0)
833 return r;
834 }
835
04b28be1 836 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
22805d92 837 SD_DHCP_OPTION_END, 0, NULL);
f7926298
TA
838 if (r < 0)
839 return r;
46a66b79 840
50d6810e
TG
841 /* We currently ignore:
842 The client SHOULD wait a random time between one and ten seconds to
843 desynchronize the use of DHCP at startup.
844 */
20b958bf 845 r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
6236f49b
TG
846 if (r < 0)
847 return r;
e2dfc79f 848
ee57a737
TG
849 log_dhcp_client(client, "DISCOVER");
850
63edaa62 851 return 0;
e2dfc79f
PF
852}
853
6236f49b 854static int client_send_request(sd_dhcp_client *client) {
8186d9dd 855 _cleanup_free_ DHCPPacket *request = NULL;
424a8732 856 size_t optoffset, optlen;
6236f49b 857 int r;
e2dfc79f 858
a1140666
LP
859 assert(client);
860
861 r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
6236f49b
TG
862 if (r < 0)
863 return r;
46a66b79 864
8b1243f7 865 switch (client->state) {
50d6810e
TG
866 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
867 SELECTING should be REQUESTING)
868 */
869
870 case DHCP_STATE_REQUESTING:
871 /* Client inserts the address of the selected server in ’server
872 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
873 filled in with the yiaddr value from the chosen DHCPOFFER.
874 */
8b1243f7 875
04b28be1 876 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 877 SD_DHCP_OPTION_SERVER_IDENTIFIER,
50d6810e 878 4, &client->lease->server_address);
6236f49b
TG
879 if (r < 0)
880 return r;
8b1243f7 881
04b28be1 882 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 883 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
6236f49b
TG
884 4, &client->lease->address);
885 if (r < 0)
886 return r;
887
50d6810e
TG
888 break;
889
890 case DHCP_STATE_INIT_REBOOT:
891 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
892 option MUST be filled in with client’s notion of its previously
893 assigned address. ’ciaddr’ MUST be zero.
894 */
04b28be1 895 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 896 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
50d6810e 897 4, &client->last_addr);
6236f49b
TG
898 if (r < 0)
899 return r;
8b1243f7
PF
900 break;
901
8b1243f7 902 case DHCP_STATE_RENEWING:
50d6810e
TG
903 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
904 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
905 client’s IP address.
906 */
907
8b1243f7 908 case DHCP_STATE_REBINDING:
50d6810e
TG
909 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
910 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
911 client’s IP address.
912
913 This message MUST be broadcast to the 0xffffffff IP broadcast address.
914 */
915 request->dhcp.ciaddr = client->lease->address;
8b1243f7
PF
916
917 break;
781ca7a1 918
50d6810e
TG
919 case DHCP_STATE_INIT:
920 case DHCP_STATE_SELECTING:
921 case DHCP_STATE_REBOOTING:
922 case DHCP_STATE_BOUND:
781ca7a1
PF
923 case DHCP_STATE_STOPPED:
924 return -EINVAL;
e2dfc79f 925 }
46a66b79 926
4cc7a82c 927 if (client->hostname) {
dc477e73 928 if (dns_name_is_single_label(client->hostname))
23873e25 929 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 930 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
931 strlen(client->hostname), client->hostname);
932 else
933 r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
934 client->hostname);
4cc7a82c
EY
935 if (r < 0)
936 return r;
937 }
938
5153494f
AG
939 if (client->vendor_class_identifier) {
940 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
941 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
942 strlen(client->vendor_class_identifier),
943 client->vendor_class_identifier);
944 if (r < 0)
945 return r;
946 }
947
04b28be1 948 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 949 SD_DHCP_OPTION_END, 0, NULL);
6236f49b
TG
950 if (r < 0)
951 return r;
46a66b79 952
aba26854 953 if (client->state == DHCP_STATE_RENEWING) {
6236f49b
TG
954 r = dhcp_network_send_udp_socket(client->fd,
955 client->lease->server_address,
956 DHCP_PORT_SERVER,
957 &request->dhcp,
20b958bf 958 sizeof(DHCPMessage) + optoffset);
aba26854 959 } else {
20b958bf 960 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
aba26854 961 }
6236f49b
TG
962 if (r < 0)
963 return r;
46a66b79 964
998d8047 965 switch (client->state) {
a1140666 966
998d8047
TG
967 case DHCP_STATE_REQUESTING:
968 log_dhcp_client(client, "REQUEST (requesting)");
969 break;
a1140666 970
998d8047
TG
971 case DHCP_STATE_INIT_REBOOT:
972 log_dhcp_client(client, "REQUEST (init-reboot)");
973 break;
a1140666 974
998d8047
TG
975 case DHCP_STATE_RENEWING:
976 log_dhcp_client(client, "REQUEST (renewing)");
977 break;
a1140666 978
998d8047
TG
979 case DHCP_STATE_REBINDING:
980 log_dhcp_client(client, "REQUEST (rebinding)");
981 break;
a1140666 982
998d8047
TG
983 default:
984 log_dhcp_client(client, "REQUEST (invalid)");
985 break;
986 }
ee57a737 987
63edaa62 988 return 0;
46a66b79
PF
989}
990
7739a40b
TG
991static int client_start(sd_dhcp_client *client);
992
4b558378
ZJS
993static int client_timeout_resend(
994 sd_event_source *s,
995 uint64_t usec,
996 void *userdata) {
997
d3d8ac2f 998 sd_dhcp_client *client = userdata;
574cc928 999 DHCP_CLIENT_DONT_DESTROY(client);
aba26854 1000 usec_t next_timeout = 0;
d23c45bf 1001 uint64_t time_now;
aba26854 1002 uint32_t time_left;
d23c45bf 1003 int r;
b25ef18b
TG
1004
1005 assert(s);
1006 assert(client);
1007 assert(client->event);
d3d8ac2f 1008
fa94c34b 1009 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
d23c45bf
TG
1010 if (r < 0)
1011 goto error;
1012
aba26854 1013 switch (client->state) {
a1140666 1014
aba26854
PF
1015 case DHCP_STATE_RENEWING:
1016
e5002702 1017 time_left = (client->lease->t2 - client->lease->t1) / 2;
aba26854
PF
1018 if (time_left < 60)
1019 time_left = 60;
d3d8ac2f 1020
d23c45bf 1021 next_timeout = time_now + time_left * USEC_PER_SEC;
d3d8ac2f 1022
aba26854
PF
1023 break;
1024
3dd71400
PF
1025 case DHCP_STATE_REBINDING:
1026
e5002702 1027 time_left = (client->lease->lifetime - client->lease->t2) / 2;
3dd71400
PF
1028 if (time_left < 60)
1029 time_left = 60;
1030
d23c45bf 1031 next_timeout = time_now + time_left * USEC_PER_SEC;
3dd71400
PF
1032 break;
1033
8b1243f7
PF
1034 case DHCP_STATE_REBOOTING:
1035 /* start over as we did not receive a timely ack or nak */
7739a40b 1036 r = client_initialize(client);
eb105b96
TG
1037 if (r < 0)
1038 goto error;
8b1243f7 1039
998d8047
TG
1040 r = client_start(client);
1041 if (r < 0)
1042 goto error;
1043 else {
1044 log_dhcp_client(client, "REBOOTED");
1045 return 0;
1046 }
7739a40b 1047
aba26854
PF
1048 case DHCP_STATE_INIT:
1049 case DHCP_STATE_INIT_REBOOT:
aba26854
PF
1050 case DHCP_STATE_SELECTING:
1051 case DHCP_STATE_REQUESTING:
1052 case DHCP_STATE_BOUND:
aba26854
PF
1053
1054 if (client->attempt < 64)
1055 client->attempt *= 2;
1056
d23c45bf 1057 next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC;
aba26854
PF
1058
1059 break;
781ca7a1
PF
1060
1061 case DHCP_STATE_STOPPED:
1062 r = -EINVAL;
1063 goto error;
aba26854
PF
1064 }
1065
9bf3b535 1066 next_timeout += (random_u32() & 0x1fffff);
d3d8ac2f 1067
a3fa4287
YW
1068 r = event_reset_time(client->event, &client->timeout_resend,
1069 clock_boottime_or_monotonic(),
1070 next_timeout, 10 * USEC_PER_MSEC,
1071 client_timeout_resend, client,
1072 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1073 if (r < 0)
1074 goto error;
1075
e2dfc79f
PF
1076 switch (client->state) {
1077 case DHCP_STATE_INIT:
6236f49b 1078 r = client_send_discover(client);
b25ef18b 1079 if (r >= 0) {
e2dfc79f
PF
1080 client->state = DHCP_STATE_SELECTING;
1081 client->attempt = 1;
1082 } else {
1083 if (client->attempt >= 64)
1084 goto error;
1085 }
1086
1087 break;
1088
1089 case DHCP_STATE_SELECTING:
6236f49b 1090 r = client_send_discover(client);
b25ef18b 1091 if (r < 0 && client->attempt >= 64)
d3d8ac2f
PF
1092 goto error;
1093
e2dfc79f
PF
1094 break;
1095
8b1243f7 1096 case DHCP_STATE_INIT_REBOOT:
e2dfc79f 1097 case DHCP_STATE_REQUESTING:
aba26854 1098 case DHCP_STATE_RENEWING:
3dd71400 1099 case DHCP_STATE_REBINDING:
6236f49b 1100 r = client_send_request(client);
b25ef18b 1101 if (r < 0 && client->attempt >= 64)
e2dfc79f 1102 goto error;
d3d8ac2f 1103
8b1243f7
PF
1104 if (client->state == DHCP_STATE_INIT_REBOOT)
1105 client->state = DHCP_STATE_REBOOTING;
1106
d23c45bf 1107 client->request_sent = time_now;
51debc1e 1108
d3d8ac2f
PF
1109 break;
1110
d3d8ac2f 1111 case DHCP_STATE_REBOOTING:
d3d8ac2f 1112 case DHCP_STATE_BOUND:
d3d8ac2f
PF
1113
1114 break;
781ca7a1
PF
1115
1116 case DHCP_STATE_STOPPED:
1117 r = -EINVAL;
1118 goto error;
d3d8ac2f
PF
1119 }
1120
1121 return 0;
1122
1123error:
b25ef18b 1124 client_stop(client, r);
d3d8ac2f
PF
1125
1126 /* Errors were dealt with when stopping the client, don't spill
1127 errors into the event loop handler */
1128 return 0;
1129}
1130
4b558378
ZJS
1131static int client_initialize_io_events(
1132 sd_dhcp_client *client,
1133 sd_event_io_handler_t io_callback) {
1134
6a1cd41e
PF
1135 int r;
1136
b25ef18b
TG
1137 assert(client);
1138 assert(client->event);
1139
151b9b96
LP
1140 r = sd_event_add_io(client->event, &client->receive_message,
1141 client->fd, EPOLLIN, io_callback,
1142 client);
6a1cd41e
PF
1143 if (r < 0)
1144 goto error;
1145
e5002702
TG
1146 r = sd_event_source_set_priority(client->receive_message,
1147 client->event_priority);
b25ef18b
TG
1148 if (r < 0)
1149 goto error;
1150
356779df 1151 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
9021bb9f
TG
1152 if (r < 0)
1153 goto error;
1154
0af03ba5
TG
1155error:
1156 if (r < 0)
1157 client_stop(client, r);
1158
1159 return 0;
1160}
1161
1162static int client_initialize_time_events(sd_dhcp_client *client) {
1d1a3e0a 1163 uint64_t usec = 0;
0af03ba5
TG
1164 int r;
1165
1166 assert(client);
1167 assert(client->event);
1168
1d1a3e0a 1169 if (client->start_delay) {
8ecdcb55 1170 assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
1d1a3e0a
BG
1171 usec += client->start_delay;
1172 }
1173
a3fa4287
YW
1174 r = event_reset_time(client->event, &client->timeout_resend,
1175 clock_boottime_or_monotonic(),
1176 usec, 0,
1177 client_timeout_resend, client,
1178 client->event_priority, "dhcp4-resend-timer", true);
6a1cd41e
PF
1179 if (r < 0)
1180 client_stop(client, r);
1181
1182 return 0;
1183
1184}
1185
4b558378 1186static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
0af03ba5
TG
1187 client_initialize_io_events(client, io_callback);
1188 client_initialize_time_events(client);
1189
1190 return 0;
1191}
1192
1d1a3e0a 1193static int client_start_delayed(sd_dhcp_client *client) {
0f941add
PF
1194 int r;
1195
1196 assert_return(client, -EINVAL);
1197 assert_return(client->event, -EINVAL);
2f8e7633 1198 assert_return(client->ifindex > 0, -EINVAL);
0f941add
PF
1199 assert_return(client->fd < 0, -EBUSY);
1200 assert_return(client->xid == 0, -EINVAL);
a1140666 1201 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
0f941add
PF
1202
1203 client->xid = random_u32();
1204
2f8e7633 1205 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1206 client->xid, client->mac_addr,
9faed222 1207 client->mac_addr_len, client->arp_type, client->port);
0f941add
PF
1208 if (r < 0) {
1209 client_stop(client, r);
1210 return r;
1211 }
0f941add 1212 client->fd = r;
58ec2d3e 1213
3742095b 1214 if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
fa94c34b 1215 client->start_time = now(clock_boottime_or_monotonic());
0f941add 1216
0f941add
PF
1217 return client_initialize_events(client, client_receive_message_raw);
1218}
1219
1d1a3e0a
BG
1220static int client_start(sd_dhcp_client *client) {
1221 client->start_delay = 0;
1222 return client_start_delayed(client);
1223}
1224
4b558378 1225static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
751246ee 1226 sd_dhcp_client *client = userdata;
574cc928 1227 DHCP_CLIENT_DONT_DESTROY(client);
751246ee 1228
ee57a737
TG
1229 log_dhcp_client(client, "EXPIRED");
1230
03748142 1231 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
0f941add 1232
781ca7a1 1233 /* lease was lost, start over if not freed or stopped in callback */
574cc928 1234 if (client->state != DHCP_STATE_STOPPED) {
e5b04c8d
PF
1235 client_initialize(client);
1236 client_start(client);
1237 }
751246ee 1238
51debc1e
PF
1239 return 0;
1240}
1241
5ee482df 1242static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
3dd71400 1243 sd_dhcp_client *client = userdata;
574cc928 1244 DHCP_CLIENT_DONT_DESTROY(client);
3dd71400
PF
1245 int r;
1246
a1140666
LP
1247 assert(client);
1248
03e334a1 1249 client->receive_message = sd_event_source_unref(client->receive_message);
22fc2420 1250 client->fd = asynchronous_close(client->fd);
3dd71400
PF
1251
1252 client->state = DHCP_STATE_REBINDING;
1253 client->attempt = 1;
1254
2f8e7633 1255 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1256 client->xid, client->mac_addr,
9faed222
SS
1257 client->mac_addr_len, client->arp_type,
1258 client->port);
3dd71400
PF
1259 if (r < 0) {
1260 client_stop(client, r);
1261 return 0;
1262 }
3dd71400
PF
1263 client->fd = r;
1264
d23c45bf 1265 return client_initialize_events(client, client_receive_message_raw);
51debc1e
PF
1266}
1267
4b558378 1268static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
aba26854 1269 sd_dhcp_client *client = userdata;
574cc928 1270 DHCP_CLIENT_DONT_DESTROY(client);
aba26854
PF
1271
1272 client->state = DHCP_STATE_RENEWING;
1273 client->attempt = 1;
1274
0af03ba5 1275 return client_initialize_time_events(client);
51debc1e
PF
1276}
1277
4b558378 1278static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
4afd3348 1279 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
5ee482df 1280 int r;
3e3d8f78 1281
a6cc569e
TG
1282 r = dhcp_lease_new(&lease);
1283 if (r < 0)
1284 return r;
8c00042c 1285
e37f74a6
DW
1286 if (client->client_id_len) {
1287 r = dhcp_lease_set_client_id(lease,
5bac5235 1288 (uint8_t *) &client->client_id,
e37f74a6
DW
1289 client->client_id_len);
1290 if (r < 0)
1291 return r;
1292 }
1293
f693e9b3 1294 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
9e64dd72 1295 if (r != DHCP_OFFER) {
6ff8806e 1296 log_dhcp_client(client, "received message was not an OFFER, ignoring");
5ee482df 1297 return -ENOMSG;
9e64dd72 1298 }
8c00042c 1299
8e34a618 1300 lease->next_server = offer->siaddr;
e5002702 1301 lease->address = offer->yiaddr;
8c00042c 1302
0339cd77
LP
1303 if (lease->address == 0 ||
1304 lease->server_address == 0 ||
9e64dd72 1305 lease->lifetime == 0) {
0339cd77 1306 log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
5ee482df 1307 return -ENOMSG;
9e64dd72
TG
1308 }
1309
0339cd77 1310 if (!lease->have_subnet_mask) {
9e64dd72
TG
1311 r = dhcp_lease_set_default_subnet_mask(lease);
1312 if (r < 0) {
87ac8d99
ZJS
1313 log_dhcp_client(client,
1314 "received lease lacks subnet mask, "
1315 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1316 return -ENOMSG;
1317 }
1318 }
8c00042c 1319
6e00a806 1320 sd_dhcp_lease_unref(client->lease);
1cc6c93a 1321 client->lease = TAKE_PTR(lease);
8c00042c 1322
ee57a737
TG
1323 log_dhcp_client(client, "OFFER");
1324
8c00042c 1325 return 0;
8c00042c
PF
1326}
1327
4b558378 1328static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
615c1467
TG
1329 int r;
1330
f693e9b3 1331 r = dhcp_option_parse(force, len, NULL, NULL, NULL);
615c1467
TG
1332 if (r != DHCP_FORCERENEW)
1333 return -ENOMSG;
1334
1335 log_dhcp_client(client, "FORCERENEW");
1336
1337 return 0;
1338}
1339
4b558378 1340static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
4afd3348 1341 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
f693e9b3 1342 _cleanup_free_ char *error_message = NULL;
5ee482df 1343 int r;
3e3d8f78 1344
a6cc569e
TG
1345 r = dhcp_lease_new(&lease);
1346 if (r < 0)
1347 return r;
3e3d8f78 1348
e37f74a6
DW
1349 if (client->client_id_len) {
1350 r = dhcp_lease_set_client_id(lease,
5bac5235 1351 (uint8_t *) &client->client_id,
e37f74a6
DW
1352 client->client_id_len);
1353 if (r < 0)
1354 return r;
1355 }
1356
f693e9b3 1357 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
ee57a737 1358 if (r == DHCP_NAK) {
f693e9b3 1359 log_dhcp_client(client, "NAK: %s", strna(error_message));
2d2349cc 1360 return -EADDRNOTAVAIL;
ee57a737 1361 }
3e3d8f78 1362
9e64dd72 1363 if (r != DHCP_ACK) {
6ff8806e 1364 log_dhcp_client(client, "received message was not an ACK, ignoring");
5ee482df 1365 return -ENOMSG;
9e64dd72 1366 }
3e3d8f78 1367
8e34a618
TG
1368 lease->next_server = ack->siaddr;
1369
e5002702 1370 lease->address = ack->yiaddr;
3e3d8f78
PF
1371
1372 if (lease->address == INADDR_ANY ||
1373 lease->server_address == INADDR_ANY ||
9e64dd72 1374 lease->lifetime == 0) {
6ff8806e 1375 log_dhcp_client(client, "received lease lacks address, server "
9e64dd72 1376 "address or lease lifetime, ignoring");
5ee482df 1377 return -ENOMSG;
9e64dd72
TG
1378 }
1379
1380 if (lease->subnet_mask == INADDR_ANY) {
1381 r = dhcp_lease_set_default_subnet_mask(lease);
1382 if (r < 0) {
87ac8d99
ZJS
1383 log_dhcp_client(client,
1384 "received lease lacks subnet mask, "
1385 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1386 return -ENOMSG;
1387 }
1388 }
3e3d8f78 1389
03748142 1390 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
3e3d8f78
PF
1391 if (client->lease) {
1392 if (client->lease->address != lease->address ||
1393 client->lease->subnet_mask != lease->subnet_mask ||
1394 client->lease->router != lease->router) {
03748142 1395 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
68ceb9df 1396 } else
03748142 1397 r = SD_DHCP_CLIENT_EVENT_RENEW;
3e3d8f78 1398
a6cc569e 1399 client->lease = sd_dhcp_lease_unref(client->lease);
3e3d8f78
PF
1400 }
1401
1cc6c93a 1402 client->lease = TAKE_PTR(lease);
3e3d8f78 1403
ee57a737
TG
1404 log_dhcp_client(client, "ACK");
1405
3e3d8f78
PF
1406 return r;
1407}
1408
fbcd420a 1409static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
022446ad
TG
1410 assert(client);
1411 assert(client->request_sent);
fbcd420a 1412 assert(lifetime > 0);
022446ad 1413
fbcd420a
LP
1414 if (lifetime > 3)
1415 lifetime -= 3;
1416 else
1417 lifetime = 0;
1418
1419 return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
9bf3b535 1420 + (random_u32() & 0x1fffff);
51debc1e
PF
1421}
1422
022446ad
TG
1423static int client_set_lease_timeouts(sd_dhcp_client *client) {
1424 usec_t time_now;
1425 uint64_t lifetime_timeout;
1426 uint64_t t2_timeout;
1427 uint64_t t1_timeout;
1428 char time_string[FORMAT_TIMESPAN_MAX];
5ee482df 1429 int r;
51debc1e 1430
b25ef18b
TG
1431 assert(client);
1432 assert(client->event);
022446ad
TG
1433 assert(client->lease);
1434 assert(client->lease->lifetime);
51debc1e 1435
022446ad 1436 /* don't set timers for infinite leases */
a3fa4287
YW
1437 if (client->lease->lifetime == 0xffffffff) {
1438 (void) event_source_disable(client->timeout_t1);
1439 (void) event_source_disable(client->timeout_t2);
1440 (void) event_source_disable(client->timeout_expire);
1441
022446ad 1442 return 0;
a3fa4287 1443 }
51debc1e 1444
fa94c34b 1445 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
022446ad
TG
1446 if (r < 0)
1447 return r;
1448 assert(client->request_sent <= time_now);
1449
1450 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1451 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
fbcd420a 1452 if (client->lease->t1 > 0 && client->lease->t2 > 0) {
022446ad
TG
1453 /* both T1 and T2 are given */
1454 if (client->lease->t1 < client->lease->t2 &&
1455 client->lease->t2 < client->lease->lifetime) {
1456 /* they are both valid */
1457 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1458 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1459 } else {
1460 /* discard both */
1461 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1462 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1463 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1464 client->lease->t1 = client->lease->lifetime / 2;
1465 }
fbcd420a 1466 } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
022446ad
TG
1467 /* only T2 is given, and it is valid */
1468 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1469 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1470 client->lease->t1 = client->lease->lifetime / 2;
1471 if (t2_timeout <= t1_timeout) {
1472 /* the computed T1 would be invalid, so discard T2 */
1473 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1474 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1475 }
fbcd420a 1476 } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
022446ad
TG
1477 /* only T1 is given, and it is valid */
1478 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1479 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1480 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1481 if (t2_timeout <= t1_timeout) {
1482 /* the computed T2 would be invalid, so discard T1 */
1483 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1484 client->lease->t2 = client->lease->lifetime / 2;
1485 }
1486 } else {
1487 /* fall back to the default timeouts */
1488 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1489 client->lease->t1 = client->lease->lifetime / 2;
1490 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1491 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1492 }
51debc1e 1493
022446ad 1494 /* arm lifetime timeout */
a3fa4287
YW
1495 r = event_reset_time(client->event, &client->timeout_expire,
1496 clock_boottime_or_monotonic(),
1497 lifetime_timeout, 10 * USEC_PER_MSEC,
1498 client_timeout_expire, client,
1499 client->event_priority, "dhcp4-lifetime", true);
9021bb9f
TG
1500 if (r < 0)
1501 return r;
1502
022446ad 1503 log_dhcp_client(client, "lease expires in %s",
ed19c567 1504 format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
51debc1e 1505
022446ad
TG
1506 /* don't arm earlier timeouts if this has already expired */
1507 if (lifetime_timeout <= time_now)
1508 return 0;
51debc1e 1509
022446ad 1510 /* arm T2 timeout */
a3fa4287
YW
1511 r = event_reset_time(client->event, &client->timeout_t2,
1512 clock_boottime_or_monotonic(),
1513 t2_timeout, 10 * USEC_PER_MSEC,
1514 client_timeout_t2, client,
1515 client->event_priority, "dhcp4-t2-timeout", true);
9021bb9f
TG
1516 if (r < 0)
1517 return r;
1518
022446ad 1519 log_dhcp_client(client, "T2 expires in %s",
ed19c567 1520 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
022446ad
TG
1521
1522 /* don't arm earlier timeout if this has already expired */
1523 if (t2_timeout <= time_now)
1524 return 0;
51debc1e 1525
022446ad 1526 /* arm T1 timeout */
a3fa4287
YW
1527 r = event_reset_time(client->event, &client->timeout_t1,
1528 clock_boottime_or_monotonic(),
1529 t1_timeout, 10 * USEC_PER_MSEC,
1530 client_timeout_t1, client,
1531 client->event_priority, "dhcp4-t1-timer", true);
9021bb9f
TG
1532 if (r < 0)
1533 return r;
1534
022446ad 1535 log_dhcp_client(client, "T1 expires in %s",
ed19c567 1536 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
022446ad 1537
51debc1e
PF
1538 return 0;
1539}
1540
4b558378 1541static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
574cc928 1542 DHCP_CLIENT_DONT_DESTROY(client);
1d1a3e0a 1543 char time_string[FORMAT_TIMESPAN_MAX];
e5002702 1544 int r = 0, notify_event = 0;
8c00042c 1545
b25ef18b
TG
1546 assert(client);
1547 assert(client->event);
e5002702 1548 assert(message);
b25ef18b 1549
8c00042c
PF
1550 switch (client->state) {
1551 case DHCP_STATE_SELECTING:
1552
e5002702
TG
1553 r = client_handle_offer(client, message, len);
1554 if (r >= 0) {
8c00042c 1555
8c00042c 1556 client->state = DHCP_STATE_REQUESTING;
e2dfc79f
PF
1557 client->attempt = 1;
1558
a3fa4287
YW
1559 r = event_reset_time(client->event, &client->timeout_resend,
1560 clock_boottime_or_monotonic(),
1561 0, 0,
1562 client_timeout_resend, client,
1563 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1564 if (r < 0)
1565 goto error;
9e64dd72
TG
1566 } else if (r == -ENOMSG)
1567 /* invalid message, let's ignore it */
1568 return 0;
8c00042c
PF
1569
1570 break;
1571
8b1243f7 1572 case DHCP_STATE_REBOOTING:
3e3d8f78 1573 case DHCP_STATE_REQUESTING:
aba26854 1574 case DHCP_STATE_RENEWING:
3dd71400 1575 case DHCP_STATE_REBINDING:
aba26854 1576
e5002702 1577 r = client_handle_ack(client, message, len);
2d2349cc 1578 if (r >= 0) {
1d1a3e0a 1579 client->start_delay = 0;
a3fa4287 1580 (void) event_source_disable(client->timeout_resend);
affaa94f
DW
1581 client->receive_message =
1582 sd_event_source_unref(client->receive_message);
1583 client->fd = asynchronous_close(client->fd);
3e3d8f78 1584
8b1243f7
PF
1585 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1586 DHCP_STATE_REBOOTING))
03748142
DH
1587 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1588 else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
aba26854
PF
1589 notify_event = r;
1590
3e3d8f78
PF
1591 client->state = DHCP_STATE_BOUND;
1592 client->attempt = 1;
1593
1594 client->last_addr = client->lease->address;
1595
022446ad 1596 r = client_set_lease_timeouts(client);
0411760a
TG
1597 if (r < 0) {
1598 log_dhcp_client(client, "could not set lease timeouts");
51debc1e 1599 goto error;
0411760a 1600 }
51debc1e 1601
3e7b9f76 1602 r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
0af03ba5
TG
1603 if (r < 0) {
1604 log_dhcp_client(client, "could not bind UDP socket");
1605 goto error;
1606 }
1607
1608 client->fd = r;
1609
1610 client_initialize_io_events(client, client_receive_message_udp);
1611
e5b04c8d 1612 if (notify_event) {
574cc928
TG
1613 client_notify(client, notify_event);
1614 if (client->state == DHCP_STATE_STOPPED)
e5b04c8d
PF
1615 return 0;
1616 }
3e3d8f78 1617
2d2349cc
TG
1618 } else if (r == -EADDRNOTAVAIL) {
1619 /* got a NAK, let's restart the client */
cc3981b1
LS
1620 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
1621
2d2349cc
TG
1622 r = client_initialize(client);
1623 if (r < 0)
1624 goto error;
1625
1d1a3e0a 1626 r = client_start_delayed(client);
2d2349cc
TG
1627 if (r < 0)
1628 goto error;
1629
1d1a3e0a
BG
1630 log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1631 client->start_delay, USEC_PER_SEC));
1632
1633 client->start_delay = CLAMP(client->start_delay * 2,
1634 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
2d2349cc
TG
1635
1636 return 0;
9e64dd72
TG
1637 } else if (r == -ENOMSG)
1638 /* invalid message, let's ignore it */
1639 return 0;
97b9372d 1640
3e3d8f78
PF
1641 break;
1642
615c1467
TG
1643 case DHCP_STATE_BOUND:
1644 r = client_handle_forcerenew(client, message, len);
1645 if (r >= 0) {
1646 r = client_timeout_t1(NULL, 0, client);
1647 if (r < 0)
1648 goto error;
1649 } else if (r == -ENOMSG)
1650 /* invalid message, let's ignore it */
1651 return 0;
1652
1653 break;
1654
8c00042c
PF
1655 case DHCP_STATE_INIT:
1656 case DHCP_STATE_INIT_REBOOT:
8c00042c
PF
1657
1658 break;
781ca7a1
PF
1659
1660 case DHCP_STATE_STOPPED:
1661 r = -EINVAL;
1662 goto error;
8c00042c
PF
1663 }
1664
1665error:
2d2349cc 1666 if (r < 0)
e5b04c8d 1667 client_stop(client, r);
e2dfc79f 1668
e5b04c8d 1669 return r;
8c00042c
PF
1670}
1671
4b558378
ZJS
1672static int client_receive_message_udp(
1673 sd_event_source *s,
1674 int fd,
1675 uint32_t revents,
1676 void *userdata) {
1677
e5002702 1678 sd_dhcp_client *client = userdata;
5266a81e 1679 _cleanup_free_ DHCPMessage *message = NULL;
16f0b479 1680 const struct ether_addr zero_mac = {};
3dc05554 1681 const struct ether_addr *expected_chaddr = NULL;
76253e73 1682 uint8_t expected_hlen = 0;
4edc2c9b 1683 ssize_t len, buflen;
e5002702
TG
1684
1685 assert(s);
1686 assert(client);
e5002702 1687
4edc2c9b
LP
1688 buflen = next_datagram_size_fd(fd);
1689 if (buflen < 0)
1690 return buflen;
5266a81e
TG
1691
1692 message = malloc0(buflen);
1693 if (!message)
1694 return -ENOMEM;
1695
cf447cb6 1696 len = recv(fd, message, buflen, 0);
0c79c68d 1697 if (len < 0) {
4c701096 1698 if (IN_SET(errno, EAGAIN, EINTR))
0d43d2fc
TG
1699 return 0;
1700
25f027c5
ZJS
1701 return log_dhcp_client_errno(client, errno,
1702 "Could not receive message from UDP socket: %m");
004845d1
LP
1703 }
1704 if ((size_t) len < sizeof(DHCPMessage)) {
0d43d2fc 1705 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
e5002702 1706 return 0;
9fbc2523
TG
1707 }
1708
1709 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
0d43d2fc 1710 log_dhcp_client(client, "Not a DHCP message: ignoring");
9fbc2523
TG
1711 return 0;
1712 }
1713
1714 if (message->op != BOOTREPLY) {
0d43d2fc 1715 log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
9fbc2523
TG
1716 return 0;
1717 }
1718
76253e73 1719 if (message->htype != client->arp_type) {
0d43d2fc 1720 log_dhcp_client(client, "Packet type does not match client type");
76253e73
DW
1721 return 0;
1722 }
1723
1724 if (client->arp_type == ARPHRD_ETHER) {
1725 expected_hlen = ETH_ALEN;
3dc05554 1726 expected_chaddr = (const struct ether_addr *) &client->mac_addr;
76253e73 1727 } else {
a8eaaee7 1728 /* Non-Ethernet links expect zero chaddr */
76253e73 1729 expected_hlen = 0;
3dc05554 1730 expected_chaddr = &zero_mac;
76253e73
DW
1731 }
1732
1733 if (message->hlen != expected_hlen) {
0d43d2fc 1734 log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
9fbc2523
TG
1735 return 0;
1736 }
1737
3dc05554 1738 if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
0d43d2fc 1739 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
9fbc2523
TG
1740 return 0;
1741 }
e5002702 1742
615c1467
TG
1743 if (client->state != DHCP_STATE_BOUND &&
1744 be32toh(message->xid) != client->xid) {
1745 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1746 so ignore the xid in this case */
0d43d2fc 1747 log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
615c1467
TG
1748 be32toh(message->xid), client->xid);
1749 return 0;
1750 }
1751
022446ad 1752 return client_handle_message(client, message, len);
e5002702
TG
1753}
1754
4b558378
ZJS
1755static int client_receive_message_raw(
1756 sd_event_source *s,
1757 int fd,
1758 uint32_t revents,
1759 void *userdata) {
1760
e5002702 1761 sd_dhcp_client *client = userdata;
5266a81e 1762 _cleanup_free_ DHCPPacket *packet = NULL;
55dab2ed
TG
1763 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1764 struct iovec iov = {};
1765 struct msghdr msg = {
1766 .msg_iov = &iov,
1767 .msg_iovlen = 1,
1768 .msg_control = cmsgbuf,
1769 .msg_controllen = sizeof(cmsgbuf),
1770 };
1771 struct cmsghdr *cmsg;
1772 bool checksum = true;
4edc2c9b
LP
1773 ssize_t buflen, len;
1774 int r;
e5002702
TG
1775
1776 assert(s);
1777 assert(client);
e5002702 1778
4edc2c9b
LP
1779 buflen = next_datagram_size_fd(fd);
1780 if (buflen < 0)
1781 return buflen;
5266a81e
TG
1782
1783 packet = malloc0(buflen);
1784 if (!packet)
1785 return -ENOMEM;
1786
55dab2ed
TG
1787 iov.iov_base = packet;
1788 iov.iov_len = buflen;
1789
a38d9945 1790 len = recvmsg(fd, &msg, 0);
55dab2ed 1791 if (len < 0) {
4c701096 1792 if (IN_SET(errno, EAGAIN, EINTR))
0d43d2fc
TG
1793 return 0;
1794
25f027c5
ZJS
1795 return log_dhcp_client_errno(client, errno,
1796 "Could not receive message from raw socket: %m");
0c79c68d
TG
1797 } else if ((size_t)len < sizeof(DHCPPacket))
1798 return 0;
55dab2ed 1799
2a1288ff 1800 CMSG_FOREACH(cmsg, &msg) {
48a4612e
TG
1801 if (cmsg->cmsg_level == SOL_PACKET &&
1802 cmsg->cmsg_type == PACKET_AUXDATA &&
1803 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1804 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
55dab2ed
TG
1805
1806 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1807 break;
1808 }
1809 }
e5002702 1810
9faed222 1811 r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
ac4f16ab 1812 if (r < 0)
9fadd4ca 1813 return 0;
e5002702
TG
1814
1815 len -= DHCP_IP_UDP_SIZE;
1816
022446ad 1817 return client_handle_message(client, &packet->dhcp, len);
e5002702
TG
1818}
1819
5ee482df 1820int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 1821 int r;
d3d8ac2f 1822
46a66b79 1823 assert_return(client, -EINVAL);
46a66b79 1824
0f941add
PF
1825 r = client_initialize(client);
1826 if (r < 0)
6a1cd41e 1827 return r;
8c00042c 1828
66173db7 1829 /* RFC7844 section 3.3:
1830 SHOULD perform a complete four-way handshake, starting with a
1831 DHCPDISCOVER, to obtain a new address lease. If the client can
1832 ascertain that this is exactly the same network to which it was
1833 previously connected, and if the link-layer address did not change,
1834 the client MAY issue a DHCPREQUEST to try to reclaim the current
1835 address. */
1836 if (client->last_addr && !client->anonymize)
0f941add 1837 client->state = DHCP_STATE_INIT_REBOOT;
d3d8ac2f 1838
998d8047
TG
1839 r = client_start(client);
1840 if (r >= 0)
2f8e7633 1841 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
998d8047
TG
1842
1843 return r;
46a66b79
PF
1844}
1845
5ee482df 1846int sd_dhcp_client_stop(sd_dhcp_client *client) {
574cc928
TG
1847 DHCP_CLIENT_DONT_DESTROY(client);
1848
e5b04c8d
PF
1849 assert_return(client, -EINVAL);
1850
03748142 1851 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
574cc928 1852 client->state = DHCP_STATE_STOPPED;
e5b04c8d
PF
1853
1854 return 0;
bbdf06d9
PF
1855}
1856
32d20645 1857int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
b25ef18b
TG
1858 int r;
1859
1860 assert_return(client, -EINVAL);
1861 assert_return(!client->event, -EBUSY);
1862
1863 if (event)
1864 client->event = sd_event_ref(event);
1865 else {
1866 r = sd_event_default(&client->event);
1867 if (r < 0)
1868 return 0;
1869 }
1870
1871 client->event_priority = priority;
1872
1873 return 0;
1874}
1875
1876int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1877 assert_return(client, -EINVAL);
1878
1879 client->event = sd_event_unref(client->event);
1880
1881 return 0;
1882}
1883
1884sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
a1140666 1885 assert_return(client, NULL);
b25ef18b
TG
1886
1887 return client->event;
1888}
1889
8301aa0b
YW
1890static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
1891 assert(client);
e5b04c8d 1892
3733eec3 1893 log_dhcp_client(client, "FREE");
6e00a806 1894
a3fa4287
YW
1895 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1896 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1897 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1898 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
3733eec3 1899
a3fa4287 1900 client_initialize(client);
3733eec3
LP
1901
1902 sd_dhcp_client_detach_event(client);
1903
1904 sd_dhcp_lease_unref(client->lease);
1905
1906 free(client->req_opts);
1907 free(client->hostname);
1908 free(client->vendor_class_identifier);
af1c0de0 1909 client->user_class = strv_free(client->user_class);
6b430fdb 1910 return mfree(client);
d2fe46b5
PF
1911}
1912
8301aa0b
YW
1913DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
1914
db3d2358 1915int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
4afd3348 1916 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
011feef8 1917
b25ef18b 1918 assert_return(ret, -EINVAL);
d3d8ac2f 1919
be6bf4a7 1920 client = new(sd_dhcp_client, 1);
011feef8 1921 if (!client)
b25ef18b 1922 return -ENOMEM;
011feef8 1923
be6bf4a7
YW
1924 *client = (sd_dhcp_client) {
1925 .n_ref = 1,
1926 .state = DHCP_STATE_INIT,
1927 .ifindex = -1,
1928 .fd = -1,
1929 .attempt = 1,
1930 .mtu = DHCP_DEFAULT_MIN_SIZE,
1931 .port = DHCP_PORT_CLIENT,
1932 .anonymize = !!anonymize,
1933 };
db3d2358 1934 /* NOTE: this could be moved to a function. */
1935 if (anonymize) {
1936 client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
1937 client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
1938 } else {
1939 client->req_opts_size = ELEMENTSOF(default_req_opts);
1940 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1941 }
b25ef18b
TG
1942 if (!client->req_opts)
1943 return -ENOMEM;
1944
1cc6c93a 1945 *ret = TAKE_PTR(client);
011feef8 1946
b25ef18b 1947 return 0;
011feef8 1948}