]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
Merge pull request #12508 from keszybz/no-root-checks
[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
4b558378 1388static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
4afd3348 1389 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
f693e9b3 1390 _cleanup_free_ char *error_message = NULL;
5ee482df 1391 int r;
3e3d8f78 1392
a6cc569e
TG
1393 r = dhcp_lease_new(&lease);
1394 if (r < 0)
1395 return r;
3e3d8f78 1396
e37f74a6
DW
1397 if (client->client_id_len) {
1398 r = dhcp_lease_set_client_id(lease,
5bac5235 1399 (uint8_t *) &client->client_id,
e37f74a6
DW
1400 client->client_id_len);
1401 if (r < 0)
1402 return r;
1403 }
1404
f693e9b3 1405 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
ee57a737 1406 if (r == DHCP_NAK) {
f693e9b3 1407 log_dhcp_client(client, "NAK: %s", strna(error_message));
2d2349cc 1408 return -EADDRNOTAVAIL;
ee57a737 1409 }
3e3d8f78 1410
9e64dd72 1411 if (r != DHCP_ACK) {
6ff8806e 1412 log_dhcp_client(client, "received message was not an ACK, ignoring");
5ee482df 1413 return -ENOMSG;
9e64dd72 1414 }
3e3d8f78 1415
8e34a618
TG
1416 lease->next_server = ack->siaddr;
1417
e5002702 1418 lease->address = ack->yiaddr;
3e3d8f78
PF
1419
1420 if (lease->address == INADDR_ANY ||
1421 lease->server_address == INADDR_ANY ||
9e64dd72 1422 lease->lifetime == 0) {
6ff8806e 1423 log_dhcp_client(client, "received lease lacks address, server "
9e64dd72 1424 "address or lease lifetime, ignoring");
5ee482df 1425 return -ENOMSG;
9e64dd72
TG
1426 }
1427
1428 if (lease->subnet_mask == INADDR_ANY) {
1429 r = dhcp_lease_set_default_subnet_mask(lease);
1430 if (r < 0) {
87ac8d99
ZJS
1431 log_dhcp_client(client,
1432 "received lease lacks subnet mask, "
1433 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1434 return -ENOMSG;
1435 }
1436 }
3e3d8f78 1437
03748142 1438 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
3e3d8f78
PF
1439 if (client->lease) {
1440 if (client->lease->address != lease->address ||
1441 client->lease->subnet_mask != lease->subnet_mask ||
1442 client->lease->router != lease->router) {
03748142 1443 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
68ceb9df 1444 } else
03748142 1445 r = SD_DHCP_CLIENT_EVENT_RENEW;
3e3d8f78 1446
a6cc569e 1447 client->lease = sd_dhcp_lease_unref(client->lease);
3e3d8f78
PF
1448 }
1449
1cc6c93a 1450 client->lease = TAKE_PTR(lease);
3e3d8f78 1451
ee57a737
TG
1452 log_dhcp_client(client, "ACK");
1453
3e3d8f78
PF
1454 return r;
1455}
1456
fbcd420a 1457static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
022446ad
TG
1458 assert(client);
1459 assert(client->request_sent);
fbcd420a 1460 assert(lifetime > 0);
022446ad 1461
fbcd420a
LP
1462 if (lifetime > 3)
1463 lifetime -= 3;
1464 else
1465 lifetime = 0;
1466
1467 return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
9bf3b535 1468 + (random_u32() & 0x1fffff);
51debc1e
PF
1469}
1470
022446ad
TG
1471static int client_set_lease_timeouts(sd_dhcp_client *client) {
1472 usec_t time_now;
1473 uint64_t lifetime_timeout;
1474 uint64_t t2_timeout;
1475 uint64_t t1_timeout;
1476 char time_string[FORMAT_TIMESPAN_MAX];
5ee482df 1477 int r;
51debc1e 1478
b25ef18b
TG
1479 assert(client);
1480 assert(client->event);
022446ad
TG
1481 assert(client->lease);
1482 assert(client->lease->lifetime);
51debc1e 1483
022446ad 1484 /* don't set timers for infinite leases */
a3fa4287
YW
1485 if (client->lease->lifetime == 0xffffffff) {
1486 (void) event_source_disable(client->timeout_t1);
1487 (void) event_source_disable(client->timeout_t2);
1488 (void) event_source_disable(client->timeout_expire);
1489
022446ad 1490 return 0;
a3fa4287 1491 }
51debc1e 1492
fa94c34b 1493 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
022446ad
TG
1494 if (r < 0)
1495 return r;
1496 assert(client->request_sent <= time_now);
1497
1498 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1499 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
fbcd420a 1500 if (client->lease->t1 > 0 && client->lease->t2 > 0) {
022446ad
TG
1501 /* both T1 and T2 are given */
1502 if (client->lease->t1 < client->lease->t2 &&
1503 client->lease->t2 < client->lease->lifetime) {
1504 /* they are both valid */
1505 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1506 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1507 } else {
1508 /* discard both */
1509 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1510 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1511 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1512 client->lease->t1 = client->lease->lifetime / 2;
1513 }
fbcd420a 1514 } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
022446ad
TG
1515 /* only T2 is given, and it is valid */
1516 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1517 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1518 client->lease->t1 = client->lease->lifetime / 2;
1519 if (t2_timeout <= t1_timeout) {
1520 /* the computed T1 would be invalid, so discard T2 */
1521 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1522 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1523 }
fbcd420a 1524 } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
022446ad
TG
1525 /* only T1 is given, and it is valid */
1526 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1527 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1528 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1529 if (t2_timeout <= t1_timeout) {
1530 /* the computed T2 would be invalid, so discard T1 */
1531 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1532 client->lease->t2 = client->lease->lifetime / 2;
1533 }
1534 } else {
1535 /* fall back to the default timeouts */
1536 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1537 client->lease->t1 = client->lease->lifetime / 2;
1538 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1539 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1540 }
51debc1e 1541
022446ad 1542 /* arm lifetime timeout */
a3fa4287
YW
1543 r = event_reset_time(client->event, &client->timeout_expire,
1544 clock_boottime_or_monotonic(),
1545 lifetime_timeout, 10 * USEC_PER_MSEC,
1546 client_timeout_expire, client,
1547 client->event_priority, "dhcp4-lifetime", true);
9021bb9f
TG
1548 if (r < 0)
1549 return r;
1550
022446ad 1551 log_dhcp_client(client, "lease expires in %s",
ed19c567 1552 format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
51debc1e 1553
022446ad
TG
1554 /* don't arm earlier timeouts if this has already expired */
1555 if (lifetime_timeout <= time_now)
1556 return 0;
51debc1e 1557
022446ad 1558 /* arm T2 timeout */
a3fa4287
YW
1559 r = event_reset_time(client->event, &client->timeout_t2,
1560 clock_boottime_or_monotonic(),
1561 t2_timeout, 10 * USEC_PER_MSEC,
1562 client_timeout_t2, client,
1563 client->event_priority, "dhcp4-t2-timeout", true);
9021bb9f
TG
1564 if (r < 0)
1565 return r;
1566
022446ad 1567 log_dhcp_client(client, "T2 expires in %s",
ed19c567 1568 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
022446ad
TG
1569
1570 /* don't arm earlier timeout if this has already expired */
1571 if (t2_timeout <= time_now)
1572 return 0;
51debc1e 1573
022446ad 1574 /* arm T1 timeout */
a3fa4287
YW
1575 r = event_reset_time(client->event, &client->timeout_t1,
1576 clock_boottime_or_monotonic(),
1577 t1_timeout, 10 * USEC_PER_MSEC,
1578 client_timeout_t1, client,
1579 client->event_priority, "dhcp4-t1-timer", true);
9021bb9f
TG
1580 if (r < 0)
1581 return r;
1582
022446ad 1583 log_dhcp_client(client, "T1 expires in %s",
ed19c567 1584 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
022446ad 1585
51debc1e
PF
1586 return 0;
1587}
1588
4b558378 1589static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
574cc928 1590 DHCP_CLIENT_DONT_DESTROY(client);
1d1a3e0a 1591 char time_string[FORMAT_TIMESPAN_MAX];
e5002702 1592 int r = 0, notify_event = 0;
8c00042c 1593
b25ef18b
TG
1594 assert(client);
1595 assert(client->event);
e5002702 1596 assert(message);
b25ef18b 1597
8c00042c
PF
1598 switch (client->state) {
1599 case DHCP_STATE_SELECTING:
1600
e5002702
TG
1601 r = client_handle_offer(client, message, len);
1602 if (r >= 0) {
8c00042c 1603
8c00042c 1604 client->state = DHCP_STATE_REQUESTING;
11793fcd 1605 client->attempt = 0;
e2dfc79f 1606
a3fa4287
YW
1607 r = event_reset_time(client->event, &client->timeout_resend,
1608 clock_boottime_or_monotonic(),
1609 0, 0,
1610 client_timeout_resend, client,
1611 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1612 if (r < 0)
1613 goto error;
9e64dd72
TG
1614 } else if (r == -ENOMSG)
1615 /* invalid message, let's ignore it */
1616 return 0;
8c00042c
PF
1617
1618 break;
1619
8b1243f7 1620 case DHCP_STATE_REBOOTING:
3e3d8f78 1621 case DHCP_STATE_REQUESTING:
aba26854 1622 case DHCP_STATE_RENEWING:
3dd71400 1623 case DHCP_STATE_REBINDING:
aba26854 1624
e5002702 1625 r = client_handle_ack(client, message, len);
2d2349cc 1626 if (r >= 0) {
1d1a3e0a 1627 client->start_delay = 0;
a3fa4287 1628 (void) event_source_disable(client->timeout_resend);
affaa94f
DW
1629 client->receive_message =
1630 sd_event_source_unref(client->receive_message);
1631 client->fd = asynchronous_close(client->fd);
3e3d8f78 1632
8b1243f7
PF
1633 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1634 DHCP_STATE_REBOOTING))
03748142
DH
1635 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1636 else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
aba26854
PF
1637 notify_event = r;
1638
3e3d8f78 1639 client->state = DHCP_STATE_BOUND;
11793fcd 1640 client->attempt = 0;
3e3d8f78
PF
1641
1642 client->last_addr = client->lease->address;
1643
022446ad 1644 r = client_set_lease_timeouts(client);
0411760a
TG
1645 if (r < 0) {
1646 log_dhcp_client(client, "could not set lease timeouts");
51debc1e 1647 goto error;
0411760a 1648 }
51debc1e 1649
3e7b9f76 1650 r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
0af03ba5
TG
1651 if (r < 0) {
1652 log_dhcp_client(client, "could not bind UDP socket");
1653 goto error;
1654 }
1655
1656 client->fd = r;
1657
1658 client_initialize_io_events(client, client_receive_message_udp);
1659
e5b04c8d 1660 if (notify_event) {
574cc928
TG
1661 client_notify(client, notify_event);
1662 if (client->state == DHCP_STATE_STOPPED)
e5b04c8d
PF
1663 return 0;
1664 }
3e3d8f78 1665
2d2349cc
TG
1666 } else if (r == -EADDRNOTAVAIL) {
1667 /* got a NAK, let's restart the client */
cc3981b1
LS
1668 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
1669
2d2349cc
TG
1670 r = client_initialize(client);
1671 if (r < 0)
1672 goto error;
1673
1d1a3e0a 1674 r = client_start_delayed(client);
2d2349cc
TG
1675 if (r < 0)
1676 goto error;
1677
1d1a3e0a
BG
1678 log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1679 client->start_delay, USEC_PER_SEC));
1680
1681 client->start_delay = CLAMP(client->start_delay * 2,
1682 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
2d2349cc
TG
1683
1684 return 0;
9e64dd72
TG
1685 } else if (r == -ENOMSG)
1686 /* invalid message, let's ignore it */
1687 return 0;
97b9372d 1688
3e3d8f78
PF
1689 break;
1690
615c1467
TG
1691 case DHCP_STATE_BOUND:
1692 r = client_handle_forcerenew(client, message, len);
1693 if (r >= 0) {
1694 r = client_timeout_t1(NULL, 0, client);
1695 if (r < 0)
1696 goto error;
1697 } else if (r == -ENOMSG)
1698 /* invalid message, let's ignore it */
1699 return 0;
1700
1701 break;
1702
8c00042c
PF
1703 case DHCP_STATE_INIT:
1704 case DHCP_STATE_INIT_REBOOT:
8c00042c
PF
1705
1706 break;
781ca7a1
PF
1707
1708 case DHCP_STATE_STOPPED:
1709 r = -EINVAL;
1710 goto error;
8c00042c
PF
1711 }
1712
1713error:
2d2349cc 1714 if (r < 0)
e5b04c8d 1715 client_stop(client, r);
e2dfc79f 1716
e5b04c8d 1717 return r;
8c00042c
PF
1718}
1719
4b558378
ZJS
1720static int client_receive_message_udp(
1721 sd_event_source *s,
1722 int fd,
1723 uint32_t revents,
1724 void *userdata) {
1725
e5002702 1726 sd_dhcp_client *client = userdata;
5266a81e 1727 _cleanup_free_ DHCPMessage *message = NULL;
13f1fd03 1728 const uint8_t *expected_chaddr = NULL;
76253e73 1729 uint8_t expected_hlen = 0;
4edc2c9b 1730 ssize_t len, buflen;
e5002702
TG
1731
1732 assert(s);
1733 assert(client);
e5002702 1734
4edc2c9b 1735 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1736 if (buflen == -ENETDOWN) {
1737 /* the link is down. Don't return an error or the I/O event
1738 source will be disconnected and we won't be able to receive
1739 packets again when the link comes back. */
1740 return 0;
1741 }
4edc2c9b
LP
1742 if (buflen < 0)
1743 return buflen;
5266a81e
TG
1744
1745 message = malloc0(buflen);
1746 if (!message)
1747 return -ENOMEM;
1748
cf447cb6 1749 len = recv(fd, message, buflen, 0);
0c79c68d 1750 if (len < 0) {
22a3fd2d
BG
1751 /* see comment above for why we shouldn't error out on ENETDOWN. */
1752 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1753 return 0;
1754
25f027c5
ZJS
1755 return log_dhcp_client_errno(client, errno,
1756 "Could not receive message from UDP socket: %m");
004845d1
LP
1757 }
1758 if ((size_t) len < sizeof(DHCPMessage)) {
0d43d2fc 1759 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
e5002702 1760 return 0;
9fbc2523
TG
1761 }
1762
1763 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
0d43d2fc 1764 log_dhcp_client(client, "Not a DHCP message: ignoring");
9fbc2523
TG
1765 return 0;
1766 }
1767
1768 if (message->op != BOOTREPLY) {
0d43d2fc 1769 log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
9fbc2523
TG
1770 return 0;
1771 }
1772
76253e73 1773 if (message->htype != client->arp_type) {
0d43d2fc 1774 log_dhcp_client(client, "Packet type does not match client type");
76253e73
DW
1775 return 0;
1776 }
1777
1778 if (client->arp_type == ARPHRD_ETHER) {
1779 expected_hlen = ETH_ALEN;
13f1fd03 1780 expected_chaddr = &client->mac_addr[0];
76253e73
DW
1781 }
1782
1783 if (message->hlen != expected_hlen) {
0d43d2fc 1784 log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
9fbc2523
TG
1785 return 0;
1786 }
1787
13f1fd03 1788 if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
0d43d2fc 1789 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
9fbc2523
TG
1790 return 0;
1791 }
e5002702 1792
615c1467
TG
1793 if (client->state != DHCP_STATE_BOUND &&
1794 be32toh(message->xid) != client->xid) {
1795 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1796 so ignore the xid in this case */
0d43d2fc 1797 log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
615c1467
TG
1798 be32toh(message->xid), client->xid);
1799 return 0;
1800 }
1801
022446ad 1802 return client_handle_message(client, message, len);
e5002702
TG
1803}
1804
4b558378
ZJS
1805static int client_receive_message_raw(
1806 sd_event_source *s,
1807 int fd,
1808 uint32_t revents,
1809 void *userdata) {
1810
e5002702 1811 sd_dhcp_client *client = userdata;
5266a81e 1812 _cleanup_free_ DHCPPacket *packet = NULL;
55dab2ed
TG
1813 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1814 struct iovec iov = {};
1815 struct msghdr msg = {
1816 .msg_iov = &iov,
1817 .msg_iovlen = 1,
1818 .msg_control = cmsgbuf,
1819 .msg_controllen = sizeof(cmsgbuf),
1820 };
1821 struct cmsghdr *cmsg;
1822 bool checksum = true;
4edc2c9b
LP
1823 ssize_t buflen, len;
1824 int r;
e5002702
TG
1825
1826 assert(s);
1827 assert(client);
e5002702 1828
4edc2c9b 1829 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1830 if (buflen == -ENETDOWN)
1831 return 0;
4edc2c9b
LP
1832 if (buflen < 0)
1833 return buflen;
5266a81e
TG
1834
1835 packet = malloc0(buflen);
1836 if (!packet)
1837 return -ENOMEM;
1838
cb310866 1839 iov = IOVEC_MAKE(packet, buflen);
55dab2ed 1840
a38d9945 1841 len = recvmsg(fd, &msg, 0);
55dab2ed 1842 if (len < 0) {
22a3fd2d 1843 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1844 return 0;
1845
25f027c5
ZJS
1846 return log_dhcp_client_errno(client, errno,
1847 "Could not receive message from raw socket: %m");
0c79c68d
TG
1848 } else if ((size_t)len < sizeof(DHCPPacket))
1849 return 0;
55dab2ed 1850
e4a0fe63 1851 CMSG_FOREACH(cmsg, &msg)
48a4612e
TG
1852 if (cmsg->cmsg_level == SOL_PACKET &&
1853 cmsg->cmsg_type == PACKET_AUXDATA &&
1854 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1855 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
55dab2ed
TG
1856
1857 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1858 break;
1859 }
e5002702 1860
9faed222 1861 r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
ac4f16ab 1862 if (r < 0)
9fadd4ca 1863 return 0;
e5002702
TG
1864
1865 len -= DHCP_IP_UDP_SIZE;
1866
022446ad 1867 return client_handle_message(client, &packet->dhcp, len);
e5002702
TG
1868}
1869
5ee482df 1870int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 1871 int r;
d3d8ac2f 1872
46a66b79 1873 assert_return(client, -EINVAL);
46a66b79 1874
0f941add
PF
1875 r = client_initialize(client);
1876 if (r < 0)
6a1cd41e 1877 return r;
8c00042c 1878
66173db7 1879 /* RFC7844 section 3.3:
1880 SHOULD perform a complete four-way handshake, starting with a
1881 DHCPDISCOVER, to obtain a new address lease. If the client can
1882 ascertain that this is exactly the same network to which it was
1883 previously connected, and if the link-layer address did not change,
1884 the client MAY issue a DHCPREQUEST to try to reclaim the current
1885 address. */
1886 if (client->last_addr && !client->anonymize)
0f941add 1887 client->state = DHCP_STATE_INIT_REBOOT;
d3d8ac2f 1888
998d8047
TG
1889 r = client_start(client);
1890 if (r >= 0)
2f8e7633 1891 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
998d8047
TG
1892
1893 return r;
46a66b79
PF
1894}
1895
1501b429
SS
1896int sd_dhcp_client_send_release(sd_dhcp_client *client) {
1897 assert_return(client, -EINVAL);
1898
1899 client_send_release(client);
1900
1901 return 0;
1902}
1903
5ee482df 1904int sd_dhcp_client_stop(sd_dhcp_client *client) {
574cc928
TG
1905 DHCP_CLIENT_DONT_DESTROY(client);
1906
e5b04c8d
PF
1907 assert_return(client, -EINVAL);
1908
03748142 1909 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
574cc928 1910 client->state = DHCP_STATE_STOPPED;
e5b04c8d
PF
1911
1912 return 0;
bbdf06d9
PF
1913}
1914
32d20645 1915int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
b25ef18b
TG
1916 int r;
1917
1918 assert_return(client, -EINVAL);
1919 assert_return(!client->event, -EBUSY);
1920
1921 if (event)
1922 client->event = sd_event_ref(event);
1923 else {
1924 r = sd_event_default(&client->event);
1925 if (r < 0)
1926 return 0;
1927 }
1928
1929 client->event_priority = priority;
1930
1931 return 0;
1932}
1933
1934int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1935 assert_return(client, -EINVAL);
1936
1937 client->event = sd_event_unref(client->event);
1938
1939 return 0;
1940}
1941
1942sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
a1140666 1943 assert_return(client, NULL);
b25ef18b
TG
1944
1945 return client->event;
1946}
1947
8301aa0b
YW
1948static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
1949 assert(client);
e5b04c8d 1950
3733eec3 1951 log_dhcp_client(client, "FREE");
6e00a806 1952
a3fa4287
YW
1953 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1954 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1955 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1956 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
3733eec3 1957
a3fa4287 1958 client_initialize(client);
3733eec3
LP
1959
1960 sd_dhcp_client_detach_event(client);
1961
1962 sd_dhcp_lease_unref(client->lease);
1963
1964 free(client->req_opts);
1965 free(client->hostname);
1966 free(client->vendor_class_identifier);
af1c0de0 1967 client->user_class = strv_free(client->user_class);
6b430fdb 1968 return mfree(client);
d2fe46b5
PF
1969}
1970
8301aa0b
YW
1971DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
1972
db3d2358 1973int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
4afd3348 1974 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
011feef8 1975
b25ef18b 1976 assert_return(ret, -EINVAL);
d3d8ac2f 1977
be6bf4a7 1978 client = new(sd_dhcp_client, 1);
011feef8 1979 if (!client)
b25ef18b 1980 return -ENOMEM;
011feef8 1981
be6bf4a7
YW
1982 *client = (sd_dhcp_client) {
1983 .n_ref = 1,
1984 .state = DHCP_STATE_INIT,
1985 .ifindex = -1,
1986 .fd = -1,
be6bf4a7
YW
1987 .mtu = DHCP_DEFAULT_MIN_SIZE,
1988 .port = DHCP_PORT_CLIENT,
1989 .anonymize = !!anonymize,
715cedfb 1990 .max_attempts = (uint64_t) -1,
be6bf4a7 1991 };
db3d2358 1992 /* NOTE: this could be moved to a function. */
1993 if (anonymize) {
1994 client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
1995 client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
1996 } else {
1997 client->req_opts_size = ELEMENTSOF(default_req_opts);
1998 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1999 }
b25ef18b
TG
2000 if (!client->req_opts)
2001 return -ENOMEM;
2002
1cc6c93a 2003 *ret = TAKE_PTR(client);
011feef8 2004
b25ef18b 2005 return 0;
011feef8 2006}