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