]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-dhcp-client.c
networkd: Add support for blacklisting servers
[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);
4c701096 609 assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST));
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 */
700 if (client->req_opts_size > 0) {
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. */
732 if (!client->anonymize) {
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
6236f49b 864static int client_send_request(sd_dhcp_client *client) {
8186d9dd 865 _cleanup_free_ DHCPPacket *request = NULL;
424a8732 866 size_t optoffset, optlen;
6236f49b 867 int r;
e2dfc79f 868
a1140666
LP
869 assert(client);
870
871 r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
6236f49b
TG
872 if (r < 0)
873 return r;
46a66b79 874
8b1243f7 875 switch (client->state) {
50d6810e
TG
876 /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
877 SELECTING should be REQUESTING)
878 */
879
880 case DHCP_STATE_REQUESTING:
881 /* Client inserts the address of the selected server in ’server
882 identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be
883 filled in with the yiaddr value from the chosen DHCPOFFER.
884 */
8b1243f7 885
04b28be1 886 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 887 SD_DHCP_OPTION_SERVER_IDENTIFIER,
50d6810e 888 4, &client->lease->server_address);
6236f49b
TG
889 if (r < 0)
890 return r;
8b1243f7 891
04b28be1 892 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 893 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
6236f49b
TG
894 4, &client->lease->address);
895 if (r < 0)
896 return r;
897
50d6810e
TG
898 break;
899
900 case DHCP_STATE_INIT_REBOOT:
901 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
902 option MUST be filled in with client’s notion of its previously
903 assigned address. ’ciaddr’ MUST be zero.
904 */
04b28be1 905 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 906 SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
50d6810e 907 4, &client->last_addr);
6236f49b
TG
908 if (r < 0)
909 return r;
8b1243f7
PF
910 break;
911
8b1243f7 912 case DHCP_STATE_RENEWING:
50d6810e
TG
913 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
914 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
915 client’s IP address.
916 */
917
8b1243f7 918 case DHCP_STATE_REBINDING:
50d6810e
TG
919 /* ’server identifier’ MUST NOT be filled in, ’requested IP address’
920 option MUST NOT be filled in, ’ciaddr’ MUST be filled in with
921 client’s IP address.
922
923 This message MUST be broadcast to the 0xffffffff IP broadcast address.
924 */
925 request->dhcp.ciaddr = client->lease->address;
8b1243f7
PF
926
927 break;
781ca7a1 928
50d6810e
TG
929 case DHCP_STATE_INIT:
930 case DHCP_STATE_SELECTING:
931 case DHCP_STATE_REBOOTING:
932 case DHCP_STATE_BOUND:
781ca7a1
PF
933 case DHCP_STATE_STOPPED:
934 return -EINVAL;
e2dfc79f 935 }
46a66b79 936
4cc7a82c 937 if (client->hostname) {
dc477e73 938 if (dns_name_is_single_label(client->hostname))
23873e25 939 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 940 SD_DHCP_OPTION_HOST_NAME,
23873e25
BG
941 strlen(client->hostname), client->hostname);
942 else
943 r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
944 client->hostname);
4cc7a82c
EY
945 if (r < 0)
946 return r;
947 }
948
5153494f
AG
949 if (client->vendor_class_identifier) {
950 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
951 SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
952 strlen(client->vendor_class_identifier),
953 client->vendor_class_identifier);
954 if (r < 0)
955 return r;
956 }
957
04b28be1 958 r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
22805d92 959 SD_DHCP_OPTION_END, 0, NULL);
6236f49b
TG
960 if (r < 0)
961 return r;
46a66b79 962
aba26854 963 if (client->state == DHCP_STATE_RENEWING) {
6236f49b
TG
964 r = dhcp_network_send_udp_socket(client->fd,
965 client->lease->server_address,
966 DHCP_PORT_SERVER,
967 &request->dhcp,
20b958bf 968 sizeof(DHCPMessage) + optoffset);
aba26854 969 } else {
20b958bf 970 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
aba26854 971 }
6236f49b
TG
972 if (r < 0)
973 return r;
46a66b79 974
998d8047 975 switch (client->state) {
a1140666 976
998d8047
TG
977 case DHCP_STATE_REQUESTING:
978 log_dhcp_client(client, "REQUEST (requesting)");
979 break;
a1140666 980
998d8047
TG
981 case DHCP_STATE_INIT_REBOOT:
982 log_dhcp_client(client, "REQUEST (init-reboot)");
983 break;
a1140666 984
998d8047
TG
985 case DHCP_STATE_RENEWING:
986 log_dhcp_client(client, "REQUEST (renewing)");
987 break;
a1140666 988
998d8047
TG
989 case DHCP_STATE_REBINDING:
990 log_dhcp_client(client, "REQUEST (rebinding)");
991 break;
a1140666 992
998d8047
TG
993 default:
994 log_dhcp_client(client, "REQUEST (invalid)");
995 break;
996 }
ee57a737 997
63edaa62 998 return 0;
46a66b79
PF
999}
1000
7739a40b
TG
1001static int client_start(sd_dhcp_client *client);
1002
4b558378
ZJS
1003static int client_timeout_resend(
1004 sd_event_source *s,
1005 uint64_t usec,
1006 void *userdata) {
1007
d3d8ac2f 1008 sd_dhcp_client *client = userdata;
574cc928 1009 DHCP_CLIENT_DONT_DESTROY(client);
aba26854 1010 usec_t next_timeout = 0;
d23c45bf 1011 uint64_t time_now;
aba26854 1012 uint32_t time_left;
d23c45bf 1013 int r;
b25ef18b
TG
1014
1015 assert(s);
1016 assert(client);
1017 assert(client->event);
d3d8ac2f 1018
fa94c34b 1019 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
d23c45bf
TG
1020 if (r < 0)
1021 goto error;
1022
aba26854 1023 switch (client->state) {
a1140666 1024
aba26854
PF
1025 case DHCP_STATE_RENEWING:
1026
e5002702 1027 time_left = (client->lease->t2 - client->lease->t1) / 2;
aba26854
PF
1028 if (time_left < 60)
1029 time_left = 60;
d3d8ac2f 1030
d23c45bf 1031 next_timeout = time_now + time_left * USEC_PER_SEC;
d3d8ac2f 1032
aba26854
PF
1033 break;
1034
3dd71400
PF
1035 case DHCP_STATE_REBINDING:
1036
e5002702 1037 time_left = (client->lease->lifetime - client->lease->t2) / 2;
3dd71400
PF
1038 if (time_left < 60)
1039 time_left = 60;
1040
d23c45bf 1041 next_timeout = time_now + time_left * USEC_PER_SEC;
3dd71400
PF
1042 break;
1043
8b1243f7
PF
1044 case DHCP_STATE_REBOOTING:
1045 /* start over as we did not receive a timely ack or nak */
7739a40b 1046 r = client_initialize(client);
eb105b96
TG
1047 if (r < 0)
1048 goto error;
8b1243f7 1049
998d8047
TG
1050 r = client_start(client);
1051 if (r < 0)
1052 goto error;
1053 else {
1054 log_dhcp_client(client, "REBOOTED");
1055 return 0;
1056 }
7739a40b 1057
aba26854
PF
1058 case DHCP_STATE_INIT:
1059 case DHCP_STATE_INIT_REBOOT:
aba26854
PF
1060 case DHCP_STATE_SELECTING:
1061 case DHCP_STATE_REQUESTING:
1062 case DHCP_STATE_BOUND:
aba26854 1063
715cedfb 1064 if (client->attempt < client->max_attempts)
11793fcd 1065 client->attempt++;
8bc17bb3
SS
1066 else
1067 goto error;
aba26854 1068
715cedfb 1069 next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
aba26854
PF
1070
1071 break;
781ca7a1
PF
1072
1073 case DHCP_STATE_STOPPED:
1074 r = -EINVAL;
1075 goto error;
aba26854
PF
1076 }
1077
9bf3b535 1078 next_timeout += (random_u32() & 0x1fffff);
d3d8ac2f 1079
a3fa4287
YW
1080 r = event_reset_time(client->event, &client->timeout_resend,
1081 clock_boottime_or_monotonic(),
1082 next_timeout, 10 * USEC_PER_MSEC,
1083 client_timeout_resend, client,
1084 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1085 if (r < 0)
1086 goto error;
1087
e2dfc79f
PF
1088 switch (client->state) {
1089 case DHCP_STATE_INIT:
6236f49b 1090 r = client_send_discover(client);
b25ef18b 1091 if (r >= 0) {
e2dfc79f 1092 client->state = DHCP_STATE_SELECTING;
11793fcd 1093 client->attempt = 0;
715cedfb
SS
1094 } else if (client->attempt >= client->max_attempts)
1095 goto error;
e2dfc79f
PF
1096
1097 break;
1098
1099 case DHCP_STATE_SELECTING:
6236f49b 1100 r = client_send_discover(client);
715cedfb 1101 if (r < 0 && client->attempt >= client->max_attempts)
d3d8ac2f
PF
1102 goto error;
1103
e2dfc79f
PF
1104 break;
1105
8b1243f7 1106 case DHCP_STATE_INIT_REBOOT:
e2dfc79f 1107 case DHCP_STATE_REQUESTING:
aba26854 1108 case DHCP_STATE_RENEWING:
3dd71400 1109 case DHCP_STATE_REBINDING:
6236f49b 1110 r = client_send_request(client);
715cedfb 1111 if (r < 0 && client->attempt >= client->max_attempts)
e2dfc79f 1112 goto error;
d3d8ac2f 1113
8b1243f7
PF
1114 if (client->state == DHCP_STATE_INIT_REBOOT)
1115 client->state = DHCP_STATE_REBOOTING;
1116
d23c45bf 1117 client->request_sent = time_now;
51debc1e 1118
d3d8ac2f
PF
1119 break;
1120
d3d8ac2f 1121 case DHCP_STATE_REBOOTING:
d3d8ac2f 1122 case DHCP_STATE_BOUND:
d3d8ac2f
PF
1123
1124 break;
781ca7a1
PF
1125
1126 case DHCP_STATE_STOPPED:
1127 r = -EINVAL;
1128 goto error;
d3d8ac2f
PF
1129 }
1130
1131 return 0;
1132
1133error:
b25ef18b 1134 client_stop(client, r);
d3d8ac2f
PF
1135
1136 /* Errors were dealt with when stopping the client, don't spill
1137 errors into the event loop handler */
1138 return 0;
1139}
1140
4b558378
ZJS
1141static int client_initialize_io_events(
1142 sd_dhcp_client *client,
1143 sd_event_io_handler_t io_callback) {
1144
6a1cd41e
PF
1145 int r;
1146
b25ef18b
TG
1147 assert(client);
1148 assert(client->event);
1149
151b9b96
LP
1150 r = sd_event_add_io(client->event, &client->receive_message,
1151 client->fd, EPOLLIN, io_callback,
1152 client);
6a1cd41e
PF
1153 if (r < 0)
1154 goto error;
1155
e5002702
TG
1156 r = sd_event_source_set_priority(client->receive_message,
1157 client->event_priority);
b25ef18b
TG
1158 if (r < 0)
1159 goto error;
1160
356779df 1161 r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
9021bb9f
TG
1162 if (r < 0)
1163 goto error;
1164
0af03ba5
TG
1165error:
1166 if (r < 0)
1167 client_stop(client, r);
1168
1169 return 0;
1170}
1171
1172static int client_initialize_time_events(sd_dhcp_client *client) {
1d1a3e0a 1173 uint64_t usec = 0;
0af03ba5
TG
1174 int r;
1175
1176 assert(client);
1177 assert(client->event);
1178
1d1a3e0a 1179 if (client->start_delay) {
8ecdcb55 1180 assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
1d1a3e0a
BG
1181 usec += client->start_delay;
1182 }
1183
a3fa4287
YW
1184 r = event_reset_time(client->event, &client->timeout_resend,
1185 clock_boottime_or_monotonic(),
1186 usec, 0,
1187 client_timeout_resend, client,
1188 client->event_priority, "dhcp4-resend-timer", true);
6a1cd41e
PF
1189 if (r < 0)
1190 client_stop(client, r);
1191
1192 return 0;
1193
1194}
1195
4b558378 1196static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
0af03ba5
TG
1197 client_initialize_io_events(client, io_callback);
1198 client_initialize_time_events(client);
1199
1200 return 0;
1201}
1202
1d1a3e0a 1203static int client_start_delayed(sd_dhcp_client *client) {
0f941add
PF
1204 int r;
1205
1206 assert_return(client, -EINVAL);
1207 assert_return(client->event, -EINVAL);
2f8e7633 1208 assert_return(client->ifindex > 0, -EINVAL);
0f941add
PF
1209 assert_return(client->fd < 0, -EBUSY);
1210 assert_return(client->xid == 0, -EINVAL);
a1140666 1211 assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
0f941add
PF
1212
1213 client->xid = random_u32();
1214
2f8e7633 1215 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1216 client->xid, client->mac_addr,
9faed222 1217 client->mac_addr_len, client->arp_type, client->port);
0f941add
PF
1218 if (r < 0) {
1219 client_stop(client, r);
1220 return r;
1221 }
0f941add 1222 client->fd = r;
58ec2d3e 1223
3742095b 1224 if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
fa94c34b 1225 client->start_time = now(clock_boottime_or_monotonic());
0f941add 1226
0f941add
PF
1227 return client_initialize_events(client, client_receive_message_raw);
1228}
1229
1d1a3e0a
BG
1230static int client_start(sd_dhcp_client *client) {
1231 client->start_delay = 0;
1232 return client_start_delayed(client);
1233}
1234
4b558378 1235static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
751246ee 1236 sd_dhcp_client *client = userdata;
574cc928 1237 DHCP_CLIENT_DONT_DESTROY(client);
751246ee 1238
ee57a737
TG
1239 log_dhcp_client(client, "EXPIRED");
1240
03748142 1241 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
0f941add 1242
781ca7a1 1243 /* lease was lost, start over if not freed or stopped in callback */
574cc928 1244 if (client->state != DHCP_STATE_STOPPED) {
e5b04c8d
PF
1245 client_initialize(client);
1246 client_start(client);
1247 }
751246ee 1248
51debc1e
PF
1249 return 0;
1250}
1251
5ee482df 1252static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
3dd71400 1253 sd_dhcp_client *client = userdata;
574cc928 1254 DHCP_CLIENT_DONT_DESTROY(client);
3dd71400
PF
1255 int r;
1256
a1140666
LP
1257 assert(client);
1258
03e334a1 1259 client->receive_message = sd_event_source_unref(client->receive_message);
22fc2420 1260 client->fd = asynchronous_close(client->fd);
3dd71400
PF
1261
1262 client->state = DHCP_STATE_REBINDING;
11793fcd 1263 client->attempt = 0;
3dd71400 1264
2f8e7633 1265 r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
76253e73 1266 client->xid, client->mac_addr,
9faed222
SS
1267 client->mac_addr_len, client->arp_type,
1268 client->port);
3dd71400
PF
1269 if (r < 0) {
1270 client_stop(client, r);
1271 return 0;
1272 }
3dd71400
PF
1273 client->fd = r;
1274
d23c45bf 1275 return client_initialize_events(client, client_receive_message_raw);
51debc1e
PF
1276}
1277
4b558378 1278static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
aba26854 1279 sd_dhcp_client *client = userdata;
574cc928 1280 DHCP_CLIENT_DONT_DESTROY(client);
aba26854
PF
1281
1282 client->state = DHCP_STATE_RENEWING;
11793fcd 1283 client->attempt = 0;
aba26854 1284
0af03ba5 1285 return client_initialize_time_events(client);
51debc1e
PF
1286}
1287
4b558378 1288static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
4afd3348 1289 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
5ee482df 1290 int r;
3e3d8f78 1291
a6cc569e
TG
1292 r = dhcp_lease_new(&lease);
1293 if (r < 0)
1294 return r;
8c00042c 1295
e37f74a6
DW
1296 if (client->client_id_len) {
1297 r = dhcp_lease_set_client_id(lease,
5bac5235 1298 (uint8_t *) &client->client_id,
e37f74a6
DW
1299 client->client_id_len);
1300 if (r < 0)
1301 return r;
1302 }
1303
f693e9b3 1304 r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
9e64dd72 1305 if (r != DHCP_OFFER) {
6ff8806e 1306 log_dhcp_client(client, "received message was not an OFFER, ignoring");
5ee482df 1307 return -ENOMSG;
9e64dd72 1308 }
8c00042c 1309
8e34a618 1310 lease->next_server = offer->siaddr;
e5002702 1311 lease->address = offer->yiaddr;
8c00042c 1312
0339cd77
LP
1313 if (lease->address == 0 ||
1314 lease->server_address == 0 ||
9e64dd72 1315 lease->lifetime == 0) {
0339cd77 1316 log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
5ee482df 1317 return -ENOMSG;
9e64dd72
TG
1318 }
1319
0339cd77 1320 if (!lease->have_subnet_mask) {
9e64dd72
TG
1321 r = dhcp_lease_set_default_subnet_mask(lease);
1322 if (r < 0) {
87ac8d99
ZJS
1323 log_dhcp_client(client,
1324 "received lease lacks subnet mask, "
1325 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1326 return -ENOMSG;
1327 }
1328 }
8c00042c 1329
6e00a806 1330 sd_dhcp_lease_unref(client->lease);
1cc6c93a 1331 client->lease = TAKE_PTR(lease);
8c00042c 1332
727b5734
SS
1333 if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
1334 return -ENOMSG;
1335
ee57a737
TG
1336 log_dhcp_client(client, "OFFER");
1337
8c00042c 1338 return 0;
8c00042c
PF
1339}
1340
4b558378 1341static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
615c1467
TG
1342 int r;
1343
f693e9b3 1344 r = dhcp_option_parse(force, len, NULL, NULL, NULL);
615c1467
TG
1345 if (r != DHCP_FORCERENEW)
1346 return -ENOMSG;
1347
1348 log_dhcp_client(client, "FORCERENEW");
1349
1350 return 0;
1351}
1352
4b558378 1353static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
4afd3348 1354 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
f693e9b3 1355 _cleanup_free_ char *error_message = NULL;
5ee482df 1356 int r;
3e3d8f78 1357
a6cc569e
TG
1358 r = dhcp_lease_new(&lease);
1359 if (r < 0)
1360 return r;
3e3d8f78 1361
e37f74a6
DW
1362 if (client->client_id_len) {
1363 r = dhcp_lease_set_client_id(lease,
5bac5235 1364 (uint8_t *) &client->client_id,
e37f74a6
DW
1365 client->client_id_len);
1366 if (r < 0)
1367 return r;
1368 }
1369
f693e9b3 1370 r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
ee57a737 1371 if (r == DHCP_NAK) {
f693e9b3 1372 log_dhcp_client(client, "NAK: %s", strna(error_message));
2d2349cc 1373 return -EADDRNOTAVAIL;
ee57a737 1374 }
3e3d8f78 1375
9e64dd72 1376 if (r != DHCP_ACK) {
6ff8806e 1377 log_dhcp_client(client, "received message was not an ACK, ignoring");
5ee482df 1378 return -ENOMSG;
9e64dd72 1379 }
3e3d8f78 1380
8e34a618
TG
1381 lease->next_server = ack->siaddr;
1382
e5002702 1383 lease->address = ack->yiaddr;
3e3d8f78
PF
1384
1385 if (lease->address == INADDR_ANY ||
1386 lease->server_address == INADDR_ANY ||
9e64dd72 1387 lease->lifetime == 0) {
6ff8806e 1388 log_dhcp_client(client, "received lease lacks address, server "
9e64dd72 1389 "address or lease lifetime, ignoring");
5ee482df 1390 return -ENOMSG;
9e64dd72
TG
1391 }
1392
1393 if (lease->subnet_mask == INADDR_ANY) {
1394 r = dhcp_lease_set_default_subnet_mask(lease);
1395 if (r < 0) {
87ac8d99
ZJS
1396 log_dhcp_client(client,
1397 "received lease lacks subnet mask, "
1398 "and a fallback one cannot be generated, ignoring");
9e64dd72
TG
1399 return -ENOMSG;
1400 }
1401 }
3e3d8f78 1402
03748142 1403 r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
3e3d8f78
PF
1404 if (client->lease) {
1405 if (client->lease->address != lease->address ||
1406 client->lease->subnet_mask != lease->subnet_mask ||
1407 client->lease->router != lease->router) {
03748142 1408 r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
68ceb9df 1409 } else
03748142 1410 r = SD_DHCP_CLIENT_EVENT_RENEW;
3e3d8f78 1411
a6cc569e 1412 client->lease = sd_dhcp_lease_unref(client->lease);
3e3d8f78
PF
1413 }
1414
1cc6c93a 1415 client->lease = TAKE_PTR(lease);
3e3d8f78 1416
ee57a737
TG
1417 log_dhcp_client(client, "ACK");
1418
3e3d8f78
PF
1419 return r;
1420}
1421
fbcd420a 1422static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
022446ad
TG
1423 assert(client);
1424 assert(client->request_sent);
fbcd420a 1425 assert(lifetime > 0);
022446ad 1426
fbcd420a
LP
1427 if (lifetime > 3)
1428 lifetime -= 3;
1429 else
1430 lifetime = 0;
1431
1432 return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
9bf3b535 1433 + (random_u32() & 0x1fffff);
51debc1e
PF
1434}
1435
022446ad
TG
1436static int client_set_lease_timeouts(sd_dhcp_client *client) {
1437 usec_t time_now;
1438 uint64_t lifetime_timeout;
1439 uint64_t t2_timeout;
1440 uint64_t t1_timeout;
1441 char time_string[FORMAT_TIMESPAN_MAX];
5ee482df 1442 int r;
51debc1e 1443
b25ef18b
TG
1444 assert(client);
1445 assert(client->event);
022446ad
TG
1446 assert(client->lease);
1447 assert(client->lease->lifetime);
51debc1e 1448
022446ad 1449 /* don't set timers for infinite leases */
a3fa4287
YW
1450 if (client->lease->lifetime == 0xffffffff) {
1451 (void) event_source_disable(client->timeout_t1);
1452 (void) event_source_disable(client->timeout_t2);
1453 (void) event_source_disable(client->timeout_expire);
1454
022446ad 1455 return 0;
a3fa4287 1456 }
51debc1e 1457
fa94c34b 1458 r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
022446ad
TG
1459 if (r < 0)
1460 return r;
1461 assert(client->request_sent <= time_now);
1462
1463 /* convert the various timeouts from relative (secs) to absolute (usecs) */
1464 lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
fbcd420a 1465 if (client->lease->t1 > 0 && client->lease->t2 > 0) {
022446ad
TG
1466 /* both T1 and T2 are given */
1467 if (client->lease->t1 < client->lease->t2 &&
1468 client->lease->t2 < client->lease->lifetime) {
1469 /* they are both valid */
1470 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1471 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1472 } else {
1473 /* discard both */
1474 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1475 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1476 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1477 client->lease->t1 = client->lease->lifetime / 2;
1478 }
fbcd420a 1479 } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
022446ad
TG
1480 /* only T2 is given, and it is valid */
1481 t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
1482 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1483 client->lease->t1 = client->lease->lifetime / 2;
1484 if (t2_timeout <= t1_timeout) {
1485 /* the computed T1 would be invalid, so discard T2 */
1486 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1487 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1488 }
fbcd420a 1489 } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
022446ad
TG
1490 /* only T1 is given, and it is valid */
1491 t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
1492 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1493 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1494 if (t2_timeout <= t1_timeout) {
1495 /* the computed T2 would be invalid, so discard T1 */
1496 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1497 client->lease->t2 = client->lease->lifetime / 2;
1498 }
1499 } else {
1500 /* fall back to the default timeouts */
1501 t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
1502 client->lease->t1 = client->lease->lifetime / 2;
1503 t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
1504 client->lease->t2 = (client->lease->lifetime * 7) / 8;
1505 }
51debc1e 1506
022446ad 1507 /* arm lifetime timeout */
a3fa4287
YW
1508 r = event_reset_time(client->event, &client->timeout_expire,
1509 clock_boottime_or_monotonic(),
1510 lifetime_timeout, 10 * USEC_PER_MSEC,
1511 client_timeout_expire, client,
1512 client->event_priority, "dhcp4-lifetime", true);
9021bb9f
TG
1513 if (r < 0)
1514 return r;
1515
022446ad 1516 log_dhcp_client(client, "lease expires in %s",
ed19c567 1517 format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
51debc1e 1518
022446ad
TG
1519 /* don't arm earlier timeouts if this has already expired */
1520 if (lifetime_timeout <= time_now)
1521 return 0;
51debc1e 1522
022446ad 1523 /* arm T2 timeout */
a3fa4287
YW
1524 r = event_reset_time(client->event, &client->timeout_t2,
1525 clock_boottime_or_monotonic(),
1526 t2_timeout, 10 * USEC_PER_MSEC,
1527 client_timeout_t2, client,
1528 client->event_priority, "dhcp4-t2-timeout", true);
9021bb9f
TG
1529 if (r < 0)
1530 return r;
1531
022446ad 1532 log_dhcp_client(client, "T2 expires in %s",
ed19c567 1533 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
022446ad
TG
1534
1535 /* don't arm earlier timeout if this has already expired */
1536 if (t2_timeout <= time_now)
1537 return 0;
51debc1e 1538
022446ad 1539 /* arm T1 timeout */
a3fa4287
YW
1540 r = event_reset_time(client->event, &client->timeout_t1,
1541 clock_boottime_or_monotonic(),
1542 t1_timeout, 10 * USEC_PER_MSEC,
1543 client_timeout_t1, client,
1544 client->event_priority, "dhcp4-t1-timer", true);
9021bb9f
TG
1545 if (r < 0)
1546 return r;
1547
022446ad 1548 log_dhcp_client(client, "T1 expires in %s",
ed19c567 1549 format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
022446ad 1550
51debc1e
PF
1551 return 0;
1552}
1553
4b558378 1554static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
574cc928 1555 DHCP_CLIENT_DONT_DESTROY(client);
1d1a3e0a 1556 char time_string[FORMAT_TIMESPAN_MAX];
e5002702 1557 int r = 0, notify_event = 0;
8c00042c 1558
b25ef18b
TG
1559 assert(client);
1560 assert(client->event);
e5002702 1561 assert(message);
b25ef18b 1562
8c00042c
PF
1563 switch (client->state) {
1564 case DHCP_STATE_SELECTING:
1565
e5002702
TG
1566 r = client_handle_offer(client, message, len);
1567 if (r >= 0) {
8c00042c 1568
8c00042c 1569 client->state = DHCP_STATE_REQUESTING;
11793fcd 1570 client->attempt = 0;
e2dfc79f 1571
a3fa4287
YW
1572 r = event_reset_time(client->event, &client->timeout_resend,
1573 clock_boottime_or_monotonic(),
1574 0, 0,
1575 client_timeout_resend, client,
1576 client->event_priority, "dhcp4-resend-timer", true);
9021bb9f
TG
1577 if (r < 0)
1578 goto error;
9e64dd72
TG
1579 } else if (r == -ENOMSG)
1580 /* invalid message, let's ignore it */
1581 return 0;
8c00042c
PF
1582
1583 break;
1584
8b1243f7 1585 case DHCP_STATE_REBOOTING:
3e3d8f78 1586 case DHCP_STATE_REQUESTING:
aba26854 1587 case DHCP_STATE_RENEWING:
3dd71400 1588 case DHCP_STATE_REBINDING:
aba26854 1589
e5002702 1590 r = client_handle_ack(client, message, len);
2d2349cc 1591 if (r >= 0) {
1d1a3e0a 1592 client->start_delay = 0;
a3fa4287 1593 (void) event_source_disable(client->timeout_resend);
affaa94f
DW
1594 client->receive_message =
1595 sd_event_source_unref(client->receive_message);
1596 client->fd = asynchronous_close(client->fd);
3e3d8f78 1597
8b1243f7
PF
1598 if (IN_SET(client->state, DHCP_STATE_REQUESTING,
1599 DHCP_STATE_REBOOTING))
03748142
DH
1600 notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
1601 else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
aba26854
PF
1602 notify_event = r;
1603
3e3d8f78 1604 client->state = DHCP_STATE_BOUND;
11793fcd 1605 client->attempt = 0;
3e3d8f78
PF
1606
1607 client->last_addr = client->lease->address;
1608
022446ad 1609 r = client_set_lease_timeouts(client);
0411760a
TG
1610 if (r < 0) {
1611 log_dhcp_client(client, "could not set lease timeouts");
51debc1e 1612 goto error;
0411760a 1613 }
51debc1e 1614
3e7b9f76 1615 r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
0af03ba5
TG
1616 if (r < 0) {
1617 log_dhcp_client(client, "could not bind UDP socket");
1618 goto error;
1619 }
1620
1621 client->fd = r;
1622
1623 client_initialize_io_events(client, client_receive_message_udp);
1624
e5b04c8d 1625 if (notify_event) {
574cc928
TG
1626 client_notify(client, notify_event);
1627 if (client->state == DHCP_STATE_STOPPED)
e5b04c8d
PF
1628 return 0;
1629 }
3e3d8f78 1630
2d2349cc
TG
1631 } else if (r == -EADDRNOTAVAIL) {
1632 /* got a NAK, let's restart the client */
cc3981b1
LS
1633 client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
1634
2d2349cc
TG
1635 r = client_initialize(client);
1636 if (r < 0)
1637 goto error;
1638
1d1a3e0a 1639 r = client_start_delayed(client);
2d2349cc
TG
1640 if (r < 0)
1641 goto error;
1642
1d1a3e0a
BG
1643 log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX,
1644 client->start_delay, USEC_PER_SEC));
1645
1646 client->start_delay = CLAMP(client->start_delay * 2,
1647 RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
2d2349cc
TG
1648
1649 return 0;
9e64dd72
TG
1650 } else if (r == -ENOMSG)
1651 /* invalid message, let's ignore it */
1652 return 0;
97b9372d 1653
3e3d8f78
PF
1654 break;
1655
615c1467
TG
1656 case DHCP_STATE_BOUND:
1657 r = client_handle_forcerenew(client, message, len);
1658 if (r >= 0) {
1659 r = client_timeout_t1(NULL, 0, client);
1660 if (r < 0)
1661 goto error;
1662 } else if (r == -ENOMSG)
1663 /* invalid message, let's ignore it */
1664 return 0;
1665
1666 break;
1667
8c00042c
PF
1668 case DHCP_STATE_INIT:
1669 case DHCP_STATE_INIT_REBOOT:
8c00042c
PF
1670
1671 break;
781ca7a1
PF
1672
1673 case DHCP_STATE_STOPPED:
1674 r = -EINVAL;
1675 goto error;
8c00042c
PF
1676 }
1677
1678error:
2d2349cc 1679 if (r < 0)
e5b04c8d 1680 client_stop(client, r);
e2dfc79f 1681
e5b04c8d 1682 return r;
8c00042c
PF
1683}
1684
4b558378
ZJS
1685static int client_receive_message_udp(
1686 sd_event_source *s,
1687 int fd,
1688 uint32_t revents,
1689 void *userdata) {
1690
e5002702 1691 sd_dhcp_client *client = userdata;
5266a81e 1692 _cleanup_free_ DHCPMessage *message = NULL;
13f1fd03 1693 const uint8_t *expected_chaddr = NULL;
76253e73 1694 uint8_t expected_hlen = 0;
4edc2c9b 1695 ssize_t len, buflen;
e5002702
TG
1696
1697 assert(s);
1698 assert(client);
e5002702 1699
4edc2c9b 1700 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1701 if (buflen == -ENETDOWN) {
1702 /* the link is down. Don't return an error or the I/O event
1703 source will be disconnected and we won't be able to receive
1704 packets again when the link comes back. */
1705 return 0;
1706 }
4edc2c9b
LP
1707 if (buflen < 0)
1708 return buflen;
5266a81e
TG
1709
1710 message = malloc0(buflen);
1711 if (!message)
1712 return -ENOMEM;
1713
cf447cb6 1714 len = recv(fd, message, buflen, 0);
0c79c68d 1715 if (len < 0) {
22a3fd2d
BG
1716 /* see comment above for why we shouldn't error out on ENETDOWN. */
1717 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1718 return 0;
1719
25f027c5
ZJS
1720 return log_dhcp_client_errno(client, errno,
1721 "Could not receive message from UDP socket: %m");
004845d1
LP
1722 }
1723 if ((size_t) len < sizeof(DHCPMessage)) {
0d43d2fc 1724 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
e5002702 1725 return 0;
9fbc2523
TG
1726 }
1727
1728 if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
0d43d2fc 1729 log_dhcp_client(client, "Not a DHCP message: ignoring");
9fbc2523
TG
1730 return 0;
1731 }
1732
1733 if (message->op != BOOTREPLY) {
0d43d2fc 1734 log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
9fbc2523
TG
1735 return 0;
1736 }
1737
76253e73 1738 if (message->htype != client->arp_type) {
0d43d2fc 1739 log_dhcp_client(client, "Packet type does not match client type");
76253e73
DW
1740 return 0;
1741 }
1742
1743 if (client->arp_type == ARPHRD_ETHER) {
1744 expected_hlen = ETH_ALEN;
13f1fd03 1745 expected_chaddr = &client->mac_addr[0];
76253e73
DW
1746 }
1747
1748 if (message->hlen != expected_hlen) {
0d43d2fc 1749 log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
9fbc2523
TG
1750 return 0;
1751 }
1752
13f1fd03 1753 if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
0d43d2fc 1754 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
9fbc2523
TG
1755 return 0;
1756 }
e5002702 1757
615c1467
TG
1758 if (client->state != DHCP_STATE_BOUND &&
1759 be32toh(message->xid) != client->xid) {
1760 /* in BOUND state, we may receive FORCERENEW with xid set by server,
1761 so ignore the xid in this case */
0d43d2fc 1762 log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
615c1467
TG
1763 be32toh(message->xid), client->xid);
1764 return 0;
1765 }
1766
022446ad 1767 return client_handle_message(client, message, len);
e5002702
TG
1768}
1769
4b558378
ZJS
1770static int client_receive_message_raw(
1771 sd_event_source *s,
1772 int fd,
1773 uint32_t revents,
1774 void *userdata) {
1775
e5002702 1776 sd_dhcp_client *client = userdata;
5266a81e 1777 _cleanup_free_ DHCPPacket *packet = NULL;
55dab2ed
TG
1778 uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1779 struct iovec iov = {};
1780 struct msghdr msg = {
1781 .msg_iov = &iov,
1782 .msg_iovlen = 1,
1783 .msg_control = cmsgbuf,
1784 .msg_controllen = sizeof(cmsgbuf),
1785 };
1786 struct cmsghdr *cmsg;
1787 bool checksum = true;
4edc2c9b
LP
1788 ssize_t buflen, len;
1789 int r;
e5002702
TG
1790
1791 assert(s);
1792 assert(client);
e5002702 1793
4edc2c9b 1794 buflen = next_datagram_size_fd(fd);
22a3fd2d
BG
1795 if (buflen == -ENETDOWN)
1796 return 0;
4edc2c9b
LP
1797 if (buflen < 0)
1798 return buflen;
5266a81e
TG
1799
1800 packet = malloc0(buflen);
1801 if (!packet)
1802 return -ENOMEM;
1803
cb310866 1804 iov = IOVEC_MAKE(packet, buflen);
55dab2ed 1805
a38d9945 1806 len = recvmsg(fd, &msg, 0);
55dab2ed 1807 if (len < 0) {
22a3fd2d 1808 if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
0d43d2fc
TG
1809 return 0;
1810
25f027c5
ZJS
1811 return log_dhcp_client_errno(client, errno,
1812 "Could not receive message from raw socket: %m");
0c79c68d
TG
1813 } else if ((size_t)len < sizeof(DHCPPacket))
1814 return 0;
55dab2ed 1815
e4a0fe63 1816 CMSG_FOREACH(cmsg, &msg)
48a4612e
TG
1817 if (cmsg->cmsg_level == SOL_PACKET &&
1818 cmsg->cmsg_type == PACKET_AUXDATA &&
1819 cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
1820 struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg);
55dab2ed
TG
1821
1822 checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
1823 break;
1824 }
e5002702 1825
9faed222 1826 r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
ac4f16ab 1827 if (r < 0)
9fadd4ca 1828 return 0;
e5002702
TG
1829
1830 len -= DHCP_IP_UDP_SIZE;
1831
022446ad 1832 return client_handle_message(client, &packet->dhcp, len);
e5002702
TG
1833}
1834
5ee482df 1835int sd_dhcp_client_start(sd_dhcp_client *client) {
6a1cd41e 1836 int r;
d3d8ac2f 1837
46a66b79 1838 assert_return(client, -EINVAL);
46a66b79 1839
0f941add
PF
1840 r = client_initialize(client);
1841 if (r < 0)
6a1cd41e 1842 return r;
8c00042c 1843
66173db7 1844 /* RFC7844 section 3.3:
1845 SHOULD perform a complete four-way handshake, starting with a
1846 DHCPDISCOVER, to obtain a new address lease. If the client can
1847 ascertain that this is exactly the same network to which it was
1848 previously connected, and if the link-layer address did not change,
1849 the client MAY issue a DHCPREQUEST to try to reclaim the current
1850 address. */
1851 if (client->last_addr && !client->anonymize)
0f941add 1852 client->state = DHCP_STATE_INIT_REBOOT;
d3d8ac2f 1853
998d8047
TG
1854 r = client_start(client);
1855 if (r >= 0)
2f8e7633 1856 log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
998d8047
TG
1857
1858 return r;
46a66b79
PF
1859}
1860
5ee482df 1861int sd_dhcp_client_stop(sd_dhcp_client *client) {
574cc928
TG
1862 DHCP_CLIENT_DONT_DESTROY(client);
1863
e5b04c8d
PF
1864 assert_return(client, -EINVAL);
1865
03748142 1866 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
574cc928 1867 client->state = DHCP_STATE_STOPPED;
e5b04c8d
PF
1868
1869 return 0;
bbdf06d9
PF
1870}
1871
32d20645 1872int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
b25ef18b
TG
1873 int r;
1874
1875 assert_return(client, -EINVAL);
1876 assert_return(!client->event, -EBUSY);
1877
1878 if (event)
1879 client->event = sd_event_ref(event);
1880 else {
1881 r = sd_event_default(&client->event);
1882 if (r < 0)
1883 return 0;
1884 }
1885
1886 client->event_priority = priority;
1887
1888 return 0;
1889}
1890
1891int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
1892 assert_return(client, -EINVAL);
1893
1894 client->event = sd_event_unref(client->event);
1895
1896 return 0;
1897}
1898
1899sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
a1140666 1900 assert_return(client, NULL);
b25ef18b
TG
1901
1902 return client->event;
1903}
1904
8301aa0b
YW
1905static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
1906 assert(client);
e5b04c8d 1907
3733eec3 1908 log_dhcp_client(client, "FREE");
6e00a806 1909
a3fa4287
YW
1910 client->timeout_resend = sd_event_source_unref(client->timeout_resend);
1911 client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
1912 client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
1913 client->timeout_expire = sd_event_source_unref(client->timeout_expire);
3733eec3 1914
a3fa4287 1915 client_initialize(client);
3733eec3
LP
1916
1917 sd_dhcp_client_detach_event(client);
1918
1919 sd_dhcp_lease_unref(client->lease);
1920
1921 free(client->req_opts);
1922 free(client->hostname);
1923 free(client->vendor_class_identifier);
af1c0de0 1924 client->user_class = strv_free(client->user_class);
6b430fdb 1925 return mfree(client);
d2fe46b5
PF
1926}
1927
8301aa0b
YW
1928DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
1929
db3d2358 1930int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
4afd3348 1931 _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
011feef8 1932
b25ef18b 1933 assert_return(ret, -EINVAL);
d3d8ac2f 1934
be6bf4a7 1935 client = new(sd_dhcp_client, 1);
011feef8 1936 if (!client)
b25ef18b 1937 return -ENOMEM;
011feef8 1938
be6bf4a7
YW
1939 *client = (sd_dhcp_client) {
1940 .n_ref = 1,
1941 .state = DHCP_STATE_INIT,
1942 .ifindex = -1,
1943 .fd = -1,
be6bf4a7
YW
1944 .mtu = DHCP_DEFAULT_MIN_SIZE,
1945 .port = DHCP_PORT_CLIENT,
1946 .anonymize = !!anonymize,
715cedfb 1947 .max_attempts = (uint64_t) -1,
be6bf4a7 1948 };
db3d2358 1949 /* NOTE: this could be moved to a function. */
1950 if (anonymize) {
1951 client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
1952 client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
1953 } else {
1954 client->req_opts_size = ELEMENTSOF(default_req_opts);
1955 client->req_opts = memdup(default_req_opts, client->req_opts_size);
1956 }
b25ef18b
TG
1957 if (!client->req_opts)
1958 return -ENOMEM;
1959
1cc6c93a 1960 *ret = TAKE_PTR(client);
011feef8 1961
b25ef18b 1962 return 0;
011feef8 1963}