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